GNU Info

Info Node: (libc.info)Nonreentrancy

(libc.info)Nonreentrancy


Next: Atomic Data Access Prev: Merged Signals Up: Defining Handlers
Enter node , (file) or (file)node

Signal Handling and Nonreentrant Functions
------------------------------------------

   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 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.

   * If your handler needs to access any global variables from your
     program, declare those variables `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.

   * If you call a function in the handler, make sure it is "reentrant"
     with respect to signals, or else make sure that the signal cannot
     interrupt a call to a related function.

   A function can be non-reentrant if it uses memory that is not on the
stack.

   * If a function uses a static variable or a global variable, or a
     dynamically-allocated object that it finds for itself, then it is
     non-reentrant and any two calls to the function can interfere.

     For example, suppose that the signal handler uses `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 `gethostbyname' or 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.  Function descriptions in
     this manual always mention this behavior.

   * If a function uses and modifies an object that you supply, then it
     is potentially non-reentrant; two calls can interfere if they use
     the same object.

     This case arises when you do I/O using streams.  Suppose that the
     signal handler prints a message with `fprintf'.  Suppose that the
     program was in the middle of an `fprintf' call 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.

   * On most systems, `malloc' and `free' are 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.

   * Any function that modifies `errno' is non-reentrant, but you can
     correct for this: in the handler, save the original value of
     `errno' and 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.

   * Merely reading from a memory object is safe provided that you can
     deal with any of the values that might appear in the object at a
     time when the signal can be delivered.  Keep in mind that
     assignment to some data types requires more than one instruction,
     which means that the handler could run "in the middle of" an
     assignment to the variable if its type is not atomic.  Note:
     Atomic Data Access.

   * Merely writing into a memory object is safe as long as a sudden
     change in the value, at any time when the handler might run, will
     not disturb anything.


automatically generated by info2www version 1.2.2.9