[Someone wrote:]
Your second sentence hints at this, but I'll state it explicitly. The
signal handler can use objects of types other than sig_atomic_t as long
as the objects are not ever accessed by the program outside of the
signal handler's context.
In article <news:bq**********@alageremail2.agere.com>
Sudheer Reddy Vakati <su*****@agere.com> writes:Do you mean that i cant modify a global variable in my signal handler?
Not exactly, but mostly.
Why this particular restriction?
Consider the following example. Suppose you have a machine with
32-bit "long"s, 32-bit CPU registers, 64-bit "long long"s, and an
implementation that handles something like:
/* long x; */
x = 7;
by generating machine instructions of the form:
move #7, reg
store reg, [memory location for x]
But if "y" is a "long long" (and thus 64 bits wide), it requires
two separate stores to set it to a new value -- for instance:
/* long long y; */
y = 0x1111111122222222LL;
might compile to:
move #0x11111111, reg
store reg, [memory location for y]
move #0x22222222, reg
store reg, [(memory location for y) + 4]
Now, suppose that you wrote C code of the form:
printf("y is %llx\n", y);
and that this compiles to code of the form:
load reg, [y]
--> push reg
load reg, [y+4]
push reg
move #stringaddr("y is 0x%llxLL\n"), reg
push reg
call printf
Suppose further that you manage to invoke your signal handler right
when the processor has finished the first "load" but has not yet
started the second "load", i.e., is about to execute (or has just
executed) the instruction marked with the "-->" arrow. If y used
to hold the value 0x8888888899999999LL, the code will have handled
the first half -- 0x88888888 -- but not the second. Then your
signal handler will change y to 0x1111111122222222LL, and only
when that finishes will the CPU resume and execute the second "load".
The output from printf() will then be:
y is 0x8888888822222222LL
which, as you will see, is an "impossible" value -- y is *supposed*
to be either 0x8888888899999999LL or 0x1111111122222222LL, but not
0x1111111199999999LL nor 0x8888888822222222LL.
Now, you might say "oh, well, in that case I will just avoid using
64-bit variables" -- but what if your CPU has 32-bit "int"s and
16-bit registers, or 16-bit "int"s and 8-bit registers, or any
other number of possibilities? Even if you use a size that happens
to match your CPU hardware -- either by accident, or by knowing
all the details about your CPU -- what if the compiler chooses to
decide: "aha, I know for sure that I only need to modify the low
byte of variable y here"? (Admittedly, the "volatile" keyword is
likely to inhibit such an optimization.)
The one guarantee you get, from the ANSI/ISO C standard, is that
you can assign to a "volatile sig_atomic_t" variable and see *only*
either the old value or the new value, never any weird intermediate
mix. Use any other type and the C-level guarantee is gone. This
does not mean you *cannot* use any other type, only that if you do,
you must look elsewhere for guarantees about it.
(Incidentally, if you study the above assembly too closely, you
will observe that "long long"s are big-endian in RAM but little-endian
when pushed on the stack for printf(). This is partly for exposition,
but also deliberate: there is nothing that says they must be
consistent; the va_arg() macro could assemble "long long"s in
reverse word-endian-ness order.)
--
In-Real-Life: Chris Torek, Wind River Systems
Salt Lake City, UT, USA (40°39.22'N, 111°50.29'W) +1 801 277 2603
email: forget about it
http://web.torek.net/torek/index.html
Reading email is like searching for food in the garbage, thanks to spammers.