Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is 'volatile' sufficient to prevent C++ compilers from optimizing out a silent write?

Tags:

c++

volatile

I would like to write a function that triggers copy-on-write of a page, without having to modify any values in that page. A simple implementation:

void trigger_cow(char* addr){
    *addr = *addr;
}

doesn't work because GCC will optimize out the line. If I use volatile,

void trigger_cow(char* addr){
    volatile char* vaddr = (volatile char*) addr;
    *vaddr = *vaddr;
}

then this works under -O3.

Will this "hack" work under other compilers or optimization settings?

The description of volatile in most sites I've seen doesn't seem to describe what happens when you write to a volatile pointer, only what happens when you read from one. Thanks!

like image 964
Ben Braun Avatar asked Nov 19 '13 19:11

Ben Braun


3 Answers

That is exactly what volatile does... it forces reads and writes to happen exactly once each time a variable is accessed, and in the same order as the reads and writes appear in the program (they cannot be reordered).

Note that the processor can still reorder reads and writes*, so volatile is not particularly useful for multithreaded programming.

*Except on the Itanium ABI, but that's unique.

like image 192
Dietrich Epp Avatar answered Oct 25 '22 20:10

Dietrich Epp


Formally, any access to volatile variables constitutes observable behavior of the program. It cannot be optimized out and it cannot be reordered with regard to other elements of observable behavior.

Optimizations in C++ programs are carried out under that "as if" rule, which basically gives the compiler permission to do anything as long as it does not change the observable behavior of the program.

like image 29
AnT Avatar answered Oct 25 '22 19:10

AnT


The standard (§1.9/8) requires that:

The least requirements on a conforming implementation are:
— Access to volatile objects are evaluated strictly according to the rules of the abstract machine.

"Access" is defined as either reading or writing, so yes, your *vaddr = *vaddr; must read a value from *vaddr, and then write the same value back to *vaddr.

like image 38
Jerry Coffin Avatar answered Oct 25 '22 19:10

Jerry Coffin