Email List: Xaustin-group-lX
[All Lists]

Re: [Fwd: Re: whether ext() and atexit() are safe w.r.t each other

To: "Clive D.W. Feather" <clive@xxxxxxxxx>
Subject: Re: [Fwd: Re: whether ext() and atexit() are safe w.r.t each other
From: Dave Butenhof <david.butenhof@xxxxxx>
Date: Fri, 06 Jun 2008 12:42:45 -0400
Cc: Andrew Josey <ajosey@xxxxxxxxxxxxx>, austin-group-l <austin-group-l@xxxxxxxxxxxxx>
References: <1212759114.12557.52.camel@localhost.localdomain> <20080606154514.GB39160@finch-staff-1.thus.net>
Clive D.W. Feather wrote:
In any case, it clearly would not be acceptable for the application to
crash because exit() found the list of atexit() handlers in an
inconsistent state, for example. Nor for atexit() to crash because
exit() might modify the list.
Agreed.


There is, however, always a "race" between callers of dependent
functions. That is, it's not possible to define exit() so that it's
guaranteed to see all atexit() handlers that the application might ever
register (concurrently or in the future). But either exit() shall see
the new atexit handler and invoke it properly OR exit() shall not see
the new atexit handler and will proceed as if this call to atexit() had
not happened. Logically, exit() occurs either before or after atexit()
insertion; never "during".
I disagree here.

An atexit() handler is either installed before the call to exit(), or while
exit() is processing. In the former case, the handler must be called for
obvious reasons. In the latter case it is installed by another atexit()
handler. The C Standard is clear that an atexit() handler installed by
another atexit() handler is called after that one returns and before what
would have been the next one is called. In other words, it has a stack
model:
* atexit() pushes the handler on to the stack.
* exit() effectively goes:
while stack is not empty
{
pop handler from stack
call handler
}
Except that here we're talking about synchronization between two concurrently executing threads. It IS possible for atexit() to be invoked after exit() starts, but not from another atexit handler -- it's called from another thread.

This call may block on an internal libc mutex until exit() calls _exit() and the process terminates, unless exit() releases the mutex controlling the atexit handler list during processing. But even if it does, another thread may invoke atexit() immediately after exit() relocks for the last time. Until all threads cease execution (which doesn't happen until _exit()), there's no way to prevent this.

POSIX does not require that the process somehow be shut down to single thread mode before calling atexit() handlers; and this would be contentious to specify, difficult to implement, and probably impossible to use. Therefore, atexit() CAN be called after exit() processing begins, in such a way that the atexit() handler cannot be seen by exit().

<Prev in Thread] Current Thread [Next in Thread>