Linux: Why is sig_atomic_t typedef'ed to int?

smcdow picture smcdow · Mar 7, 2012 · Viewed 13.4k times · Source

On my Linux box, sig_atomic_t is a plain old int. Do ints posses a special atomic quality?

$ gcc -v
Using built-in specs.
Target: x86_64-linux-gnu
...
Thread model: posix
gcc version 4.3.2 (Debian 4.3.2-1.1) 

$ echo '#include <signal.h>' | gcc -E - | grep atomic
typedef int __sig_atomic_t;
typedef __sig_atomic_t sig_atomic_t;

Answer

zwol picture zwol · Mar 7, 2012

C99 sig_atomic_t conforms only to a very weak definition of "atomicity", because C99 has no concept of concurrency, only interruptibility. (C2011 adds a concurrency model, and with it the _Atomic types that make stronger guarantees; however, AFAIK sig_atomic_t is unchanged, since its raison d'être is still communication with signal handlers, not across threads.)

This is everything C99 says about sig_atomic_t:

(§7.14 <signal.h>, paragraph 2) The type defined is sig_atomic_t, which is the (possibly volatile-qualified) integer type of an object that can be accessed as an atomic entity, even in the presence of asynchronous interrupts. (§7.14 <signal.h>, paragraph 2)

(§7.14p5) If [a] signal occurs other than as the result of calling the abort or raise function, the behavior is undefined if the signal handler refers to any object with static storage duration other than by assigning a value to an object declared as volatile sig_atomic_t.

(§7.18.3 Limits of other integer types, paragraph 3) If sig_atomic_t (see 7.14) is defined as a signed integer type, the value of SIG_ATOMIC_MIN shall be no greater than −127 and the value of SIG_ATOMIC_MAX shall be no less than 127; otherwise, sig_atomic_t is defined as an unsigned integer type, and the value of SIG_ATOMIC_MIN shall be 0 and the value of SIG_ATOMIC_MAX shall be no less than 255.

The term "atomic entity" is not defined anywhere in the standard. Translating from standards-ese, the intent is that the CPU can completely update a variable of type sig_atomic_t in memory ("static storage duration") with one machine instruction. Thus, in the concurrency-free, precisely interruptible C99 abstract machine, it is impossible for a signal handler to observe a variable of type sig_atomic_t halfway through an update. The §7.18.3p3 language licenses this type to be as small as char if necessary. Note please the complete absence of any language relating to cross-processor consistency.

There are real CPUs which require more than one instruction to write a value larger than char to memory. There are also real CPUs which require more than one instruction to write values smaller than a machine word (often, but not necessarily, the same as int) to memory. The language in the GNU C Library manual is now inaccurate. It represents a desire on the part of the original authors to eliminate what they saw as unnecessary license for C implementations to do weird shit that made life harder for application programmers. Unfortunately, that very license is what makes it possible to have C at all on some real machines. There is at least one embedded Linux port (to the AVR) for which neither int nor pointers can be written to memory in one instruction. (People are working on making the manual more accurate, see e.g. http://sourceware.org/ml/libc-alpha/2012-02/msg00651.html -- sig_atomic_t seems to have been missed in that one, though.)