20
votes

I am currently reading the PostgreSql code. Here is an excerpt from the buffer manager:

static void WaitIO(volatile BufferDesc *buf);
static bool StartBufferIO(volatile BufferDesc *buf, bool forInput);
static void TerminateBufferIO(volatile BufferDesc *buf, bool clear_dirty,

I know the volatile keyword is usually used for device drivers and in embedded systems. There is an explanation of the keyword.

When the keyword volatile is used in the type definition it is giving an indication to the compiler on how it should handle the variable. Primarily it is telling the compiler that the value of the variable may change at any time as a result of actions external to the program or current line of execution. (Source)

So why are certain function arguments declared as volatile? I don't expect that DMA changes the pointer location. So what happens here?

5
Not sure its worth another question, but interested to know why you might write void func(int volatile arg); - ideasman42

5 Answers

21
votes

volatile BufferDesc *buf means that the data that buf points to is volatile, not that the pointer contained by buf is volatile. (That would be BufferDesc * volatile buf.)

From the page you linked to:

On the other hand, if you have a pointer variable where the address itself was volatile but the memory pointed to was not then we have:

int * volatile x;

Re this part of your question:

So why are certain function arguments declared as volatile?

Presumably because the data it points to can change in a way that the compiler wouldn't necessarily know about. The volatile keyword is there to prevent the compiler applying optimizations that assume the data doesn't change in ways it doesn't know about.

7
votes

I don't expect that DMA changes the pointer location.

Not the location, but maybe the content. And that's exactly what it is about...

1
votes

Databases implementation does not rely on the OS buffers&caches when accessing files. They prefer to implement they own cache system and get direct access to the file on the physical disk, for reliability issues: data MUST to be flushed to the physical disk. (They use the O_DIRECT option to perform direct access to physical disk.)

The 3 functions you are showing us make me think of asynchronous handling of data coming from the disk. (StartBufferIO(), TerminatedBufferIO() and so on). Honestly I am not sure of what is their purpose, but based on what I know about databases implementation, and those function names, I would say that the buffer content might be modified by the "disk" itself with data from the file on the disk (or whatever device), and therefore needs to be flaged as volatile.

This hypothesis joins your usual interpretation of what the volatile keyword is usually used for: device drivers.

0
votes

DMA isn't the only reason to use "volatile". It's also useful for multithreaded and shared memory applications, where another thread may change memory referenced by this code. I'm sure that PostgreSql is multi-threaded, so this is a likely reason why volatile is being used here.

0
votes

One thing a compiler usually does when optimising is removing dead code, so if you do some operations with a variable that its never read neither and its result is useless compiler will probably just remove it, as well as removing the rest of operations that affects it. That behaviour can be very annoying when your debug a code ore your are performing some kind of benchamrks. If you declare as volatile a variable you alert the compiler it could be used by external libraries or programs, among other implications the keyword may have. Then it should never treat it as dead code.