Here is a simple toy program that uses volatile sig_atomic_t.
#include <stdio.h>
#include <signal.h>
#include <stdlib.h>
#include <unistd.h>
#define UNUSED(x) (void) (x)
volatile sig_atomic_t quit;
void sigusr1_handler(int sig)
{
UNUSED(sig);
write(1, "handler\n", 8);
quit = 1;
}
int main()
{
struct sigaction sa;
sa.sa_handler = sigusr1_handler;
sa.sa_flags = 0;
sigemptyset(&sa.sa_mask);
if (sigaction(SIGUSR1, &sa, NULL) == -1) {
perror("sigaction");
return 1;
}
quit = 0;
while (!quit)
;
printf("Exiting ...\n");
return 0;
}
I think I know why volatile sig_atomic_t is necessary for the quit variable in this particular program.
- Without
volatile, the compiler may optimizewhile (!quit) ;to an infinite loop. It does not find the loop modifyingquit, so it assumes thatquitalways remains0. - An update to
quitor a read ofquitshould happen in a single machine instruction. If it takes multiple machine instructions to update or readquit, then if a signal handler is invoked while an update was going on, a read in the signal handler may see inconsistent value inquit.
Am I correct so far? If not, please correct me in your answer.
Now I want to learn a generalized rule for when sig_atomic_t is necessary in the context of signal handling. Jonathan Leffler has explained in the comment that it is not easy to provide a generalization.
Can you provide a list of known scenarios where a variable needs to be defined as sig_atomic_t from C standard perspective? It need not be an exhaustive list. It could be a list a less experienced developer can refer to while writing C software with signal handling code.
There are 2 relevant sections from the c99 spec:
"Static storage duration" is defined as:
In a nutshell, you are required to use
volatile sig_atomic_tif the variable may be accessed asynchronously (i.e., the variable is accessed both inside and outside of the signal handler). In addition, it is undefined behavior to access a non-volatile sig_atomic_tvariable which has static storage duration. Undefined behavior means that not only could the value of the variable be inconsistent, the program could do something else entirely (like segfault).