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

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

To: austin-group-l <austin-group-l@xxxxxxxxxxxxx>
Subject: [Fwd: Re: whether ext() and atexit() are safe w.r.t each other
From: Andrew Josey <ajosey@xxxxxxxxxxxxx>
Date: Fri, 06 Jun 2008 14:31:54 +0100
Organization: The Open Group
[ This was blocked due to the attachment -- Andrew ]
 

Date: Fri, 06 Jun 2008 08:27:06 -0400
From: David Butenhof <david.butenhof@hp.com>
Organization: IS/MSL/iCAP
User-Agent: Thunderbird 2.0.0.14 (Windows/20080421)
MIME-Version: 1.0
To: Anoop <acv@linux.vnet.ibm.com>
CC: "austin-group-l@opengroup.org" <austin-group-l@opengroup.org>
Subject: Re: whether ext() and atexit() are safe w.r.t each other
References: <48491601.7030306@linux.vnet.ibm.com>
In-Reply-To: <48491601.7030306@linux.vnet.ibm.com>


Anoop wrote:
> A race is observed between atexit() and exit() in Linux.
>
> Does these functions need to be safe with respect to each other?
>
> Being more specific, if a thread is registering a handler using atexit() while
> exit() is processing the already registered handlers in the main thread,
> what is the expected behavior as per the standard?
>   

    2.9.1 Thread-Safety

    All functions defined by this volume of POSIX.1-200x shall be
    thread-safe, except that the
    following functions need not be thread-safe.

Neither atexit() nor exit() are on the list, therefore they must be 
thread safe. Being thread safe means not subject to "unexpected 
behavior" when called concurrently. This implicitly (but strongly and 
unambiguously) requires synchronization between dependent functions. 
(E.g., malloc and free, or exit and atexit.)

(I suppose one could make an argument that the standard should specify 
and describe all such dependencies among the defined interfaces. That 
might make it easier for "naive implementors", but it's hard to imagine 
that any reasonable effort would identify all possible interactions; and 
ultimately an implementor is still responsible for making the 
implementation usable. I'll also agree that doesn't sound like a very 
good excuse -- but someone would have to volunteer to get such an effort 
started. While you're at it, you can work on a complete, consistent, and 
comprehensible memory model. ;-) )

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.

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

The exit() function in particular has a lot of dependencies since it 
cleans up and finalizes a lot of implicit user-mode process state "on 
the way out". For example exit() can't crash because some thread is 
opening a stdio stream, even though exit() must flush all streams. 
Again, the new stream is either flushed because it's known to exit() as 
open, or not flushed because it's not; but exit() must complete 
successfully.



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