Handler functions usually don't do very much. The best practice is to
write a handler that does nothing but set an external variable that the
program checks regularly, and leave all serious work to the program.
This is best because the handler can be called at asynchronously, at
unpredictable times--perhaps in the middle of a primitive function, or
even between the beginning and the end of a C operator that requires
multiple instructions. The data structures being manipulated might
therefore be in an inconsistent state when the handler function is
invoked. Even copying one
int variable into another can take two
instructions on most machines.
This means you have to be very careful about what you do in a signal handler.
volatile. This tells the compiler that the value of the variable might change asynchronously, and inhibits certain optimizations that would be invalidated by such modifications.
A function can be non-reentrant if it uses memory that is not on the stack.
gethostbyname. This function returns its value in a static object, reusing the same object each time. If the signal happens to arrive during a call to
gethostbyname, or even after one (while the program is still using the value), it will clobber the value that the program asked for. However, if the program does not use
gethostbynameor any other function that returns information in the same object, or if it always blocks signals around each use, then you are safe. There are a large number of library functions that return values in a fixed object, always reusing the same object in this fashion, and all of them cause the same problem. The description of a function in this manual always mentions this behavior.
fprintf. Suppose that the program was in the middle of an
fprintfcall using the same stream when the signal was delivered. Both the signal handler's message and the program's data could be corrupted, because both calls operate on the same data structure--the stream itself. However, if you know that the stream that the handler uses cannot possibly be used by the program at a time when signals can arrive, then you are safe. It is no problem if the program uses some other stream.
freeare not reentrant, because they use a static data structure which records what memory blocks are free. As a result, no library functions that allocate or free memory are reentrant. This includes functions that allocate space to store a result. The best way to avoid the need to allocate memory in a handler is to allocate in advance space for signal handlers to use. The best way to avoid freeing memory in a handler is to flag or record the objects to be freed, and have the program check from time to time whether anything is waiting to be freed. But this must be done with care, because placing an object on a chain is not atomic, and if it is interrupted by another signal handler that does the same thing, you could "lose" one of the objects. The relocating allocation functions (see section Relocating Allocator) are certainly not safe to use in a signal handler.
errnois non-reentrant, but you can correct for this: in the handler, save the original value of
errnoand restore it before returning normally. This prevents errors that occur within the signal handler from being confused with errors from system calls at the point the program is interrupted to run the handler. This technique is generally applicable; if you want to call in a handler a function that modifies a particular object in memory, you can make this safe by saving and restoring that object.
Go to the first, previous, next, last section, table of contents.