... I'm beginning to think that I do understand C's idea of "atomic" - and
that it isn't what "atomic" means to most everybody else.
I can't speak for "most everybody else", but I've never thought
"atomic" implied "atomic read-and-update" in the context of the C
standard. Obviously "atomic" in computer science usually means that
some operation will either be performed completely or not at all, but
what that operation is can vary widely depending on context.
In the case of sig_atomic_t ISTM that the intent of the standard is
clear: assigning to a sig_atomic_t variable, or referencing one,
will be an atomic operation. The assignment, or reference, will
occur completely or not at all.
Consider a hypothetical conforming implementation on a processor with
an 8-bit bus, where a 16-bit store requires two instructions. An
asynchronous signal could interrupt that sequence between the two
instructions and leave a 16-bit value partially updated. On such an
implementation, sig_atomic_t would have to be an 8-bit integer
(signed or unsigned char, where CHAR_BIT was 8) so that no
sig_atomic_t variable could ever have a partially-updated value.
That said, sig_atomic_t as defined in the standard adds relatively
little value, because there are few cases where strictly-conforming
code could read a partially-updated value from any object. In
particular, a signal handler for an asynchronous signal cannot read
such a value, since it cannot refer to any object with static storage
duration except to assign to a volatile sig_atomic_t.
Footnote 109 (C90) states that another signal while in a handler for
an asynchronous signal causes undefined behavior. Footnotes aren't
normative, but clearly the standard doesn't intend to cover this case
(where a handler's assignment to a variable is interrupted by another
signal) with sig_atomic_t either.
The only other case I can think of is one where:
- Function A establishes a jmp_buf with setjmp.
- Function B assigns a value to a file-scope object X.
- Signal handler H longjmps back to A.
- A, when returning from setjmp via longjmp, refers to X.
- An asynchronous signal occurs while B is assigning to X.
However, it appears to me that this is not guaranteed to work by
the standard (I'm looking at C90), because while it says that a
signal handler may exit by calling longjmp, it also says it's not
allowed to "refer[] to any object with static storage duration"
except for the aforementioned assignment to a volatile sig_atomic_t.
Does calling longjmp constitute referring to the jmp_buf? Also,
in the case of asynchronous signals (ie ones not caused by abort or
raise), handlers are prohibited from calling any library function
other than signal. So as far as I can tell, there are no circum-
stances where a partial assignment could be detected (by strictly-
conforming code) anyway.
I suspect sig_atomic_t is one of those things which has semantics
that are not actually useful for strictly-conforming code, but are
plausibly useful in a variety of implementations as a common
extension. Specifically, I suspect that in most implementations
an asynchronous handler can safely refer to the value of a volatile
sig_atomic_t (as well as assigning to it), and in this case its
atomicity is important (as it guarantees that the handler will not
see a partial value).