An object that has volatile-qualified type may be modified in ways unknown to the implementation or have other unknown side effects. Asynchronous signal handling falls under these conditions. Without this type qualifier, unintended optimizations may occur.
| Wiki Markup |
|---|
volatile eliminates this confusion by imposing restrictions on access and cacheing \[C99 Rationale\]: |
No cacheing through this lvalue: each operation in the abstract semantics must be performed (that is, no cacheing assumptions may be made, since the location is not guaranteed to contain any previous value). In the absence of this qualifier, the contents of the designated location may be assumed to be unchanged except for possible aliasing.
Non-Compliant Coding Example
If the value of i is cached, the while loop may never terminate, even on the program receiving a SIGINT.
| Code Block | ||
|---|---|---|
| ||
#include <signal.h> size_t i; void handler(void) { i = 0; } int main(void) { signal(SIGINT, handler); i = 1; while(i) { /* do something */ } } } |
Compliant Solution
i will now be accessed again for every iteration of the while loop.
| Code Block | ||
|---|---|---|
| ||
#include <signal.h>
volatile size_t i;
void handler() {
i = 0;
}
int main(void) {
signal(SIGINT, handler);
i = 1;
while(i) {
/* do something */
}
}
|
Risk Assessment
In addition to incorrect optimizations, this can cause race conditions, resulting in inconsistent state.
...
| Wiki Markup |
|---|
\[[ISO/IEC 03|AA. C References#ISO/IEC 03]\] "SignalsType and Interrupts" \[[Open Group 04|AA. C References#Open Group 04]\] [longjmp|http://www.opengroup.org/onlinepubs/000095399/functions/longjmp.html] \[OpenBSD\] [{{signal()}} Man Page|http://www.openbsd.org/cgi-bin/man.cgi?query=signal]Qualifiers" |