diff --git a/abi.html b/abi.html index b2df8ab..161d3ec 100644 --- a/abi.html +++ b/abi.html @@ -4079,22 +4079,21 @@
3.3.5.5 Linker Processing

-

3.3.6 DSO Object Destruction API

+

3.3.6 Global and Thread-Local Object Destruction API

3.3.6.1 Motivation

-The C++ Standard requires that destructors be called for global objects -when a program exits in the opposite order of construction. -Most implementations have handled this by calling the C library -atexit routine to register the destructors. -This is problematic because the 1999 C Standard only requires that the -implementation support 32 registered functions, -although most implementations support many more. -More important, -it does not deal at all with the ability in most implementations to +The C++ Standard requires that destructors be called for global +objects when a program exits. Most implementations have handled +this by calling the C library atexit routine to +register the destructors. +This is problematic because the C standard only requires that the +implementation support 32 registered functions, although most +implementations support many more. More importantly, it does not +deal at all with the ability in most implementations to remove DSOs from a running program image by calling dlclose prior to program termination. @@ -4107,73 +4106,156 @@

3.3.6.1 Motivation

-

3.3.6.2 Runtime Data Structure
+
3.3.6.2 Runtime Data Structure

-The runtime library shall maintain a list of termination functions -with the following information about each: +The runtime library shall maintain a list of global termination +functions with the following information about each:

-The representation of this structure is implementation defined. +Entries in this list need not be unique. If the same function +is registered multiple times, it is called multiple times as +described below. + +

+The runtime library shall also maintain an analogous list of +thread-local termination functions for each thread, with +the same information about each. + +

+The representation of these lists is implementation defined. All references are via the API described below. + + +

3.3.6.3 Destructors for global objects
+

- -

3.3.6.3 Runtime API
+After constructing an object with static storage duration +that will require destruction on process exit, a global +termination function is registered by calling the following +function: + +
extern "C" int __cxa_atexit(void (*f)(void *), void *p, void *d);
+ +

The third argument, d, must be the value +&__dso_handle for the DSO which defines the object; +see below. The first and second arguments may be chosen at the +implementation's convenience. -

    -

  1. Object construction: +The runtime library will call f(p) when the unloading +of DSO d is required, including when the process exits. +The call will occur before the DSO is actually unloaded from the +process. Calls to global termination functions will be made in the +reverse order of their registration. +

    -After constructing a global (or local static) object, -that will require destruction on exit, -a termination function is registered as follows: -

    -extern "C" int __cxa_atexit ( void (*f)(void *), void *p, void *d ); -
    -This registration, e.g. __cxa_atexit(f,p,d), -is intended to cause the call f(p) when DSO d is unloaded, -before all such termination calls registered before this one. -It returns zero if registration is successful, nonzero on failure. +Note that global termination functions may be registered +concurrently. If the registrations of two separate termination +functions are not well-ordered by the strongly happens before +relation, the order in which they are called is unspecified.

    -The registration function is not called from within the constructor. +__cxa_atexit returns zero if registration is successful, +nonzero on failure. + + +

    3.3.6.4 Destructors for thread-local objects

    -

  2. User atexit calls: +After constructing an object with thread storage duration +that will require destruction on process or thread exit, +a thread-local termination function is registered for the +current thread by calling the following function: + +
    extern "C" int __cxa_thread_atexit(void (*f)(void *), void *p, void *d);
    + +

    The third argument, d, must be the value +&__dso_handle for the DSO which defines the object; +see below. The first and second arguments may be chosen at the +implementation's convenience. +

    -When the user registers exit functions with atexit, -they should be registered with NULL parameters and DSO handles, i.e. -

    - __cxa_atexit ( f, NULL, NULL ); -
    -It is expected that implementations supporting both C and C++ will -integrate this capability into the libc atexit -implementation so that C-only DSOs will nevertheless interact with C++ -programs in a C++-standard-conforming manner. -No user interface to __cxa_atexit is supported, -so the user is not able to register an atexit function -with a parameter or a home DSO. +The runtime library will call f(p) if the +registering thread either terminates or exits the process (e.g. +by calling std::exit). Calls will be made in the +reverse order of registration. Calls will be made from the +registering thread.

    -

  3. Termination: +If the process is exited by a thread, it is unspecified whether +thread-local termination functions registered for different +threads are called. This applies even if another thread has +terminated but has not yet finished calling all of its +termination functions. +

    -When linking any DSO containing a call to __cxa_atexit, +If the unloading of a DSO is required other than during process +exit (e.g. by calling dlclose), and there are any +any thread-local termination functions associated with that DSO, +the behavior is undefined. Some implementations choose to support +this by delaying the unloading of the DSO until all such functions +have been called on all threads. Implementations that wish to +unload the DSO immediately are encouraged to at least call +thread-local termination functions registered for the current +thread. + +

    +__cxa_thread_atexit returns zero if registration +is successful, nonzero on failure. + + +

    3.3.6.5 User calls to atexit
    + +

    +The C++ standard requires calls to exit functions registered with +atexit to occur in reverse order of registration, +appropriately interordered with the destruction of global objects +according to the completion order of their initialization; see +[basic.start.term]. It is expected +that implementations supporting C++ will integrate support for +__cxa_atexit into the C library in order to achieve +these semantics. + +

    +There is no analogous thread-specific atexit API +in the C or C++ standards, or in POSIX threads. If there were, +it would be expected to be appropriately interordered with the +destruction of thread-local objects. It is currently unclear +what the appropriate interordering rules are for the destruction +of thread-local storage such as C11's tss_create or +POSIX's pthread_key_create; these APIs do not +specify any particular destruction order for multiple keys. + +

    +The C++ standard does not provide a user interface corresponding +to __cxa_atexit or __cxa_thread_atexit. +There is no way to register an atexit function +with a parameter or a home DSO. + + +

    3.3.6.6 Termination
    + +

    +When linking any DSO containing a call to __cxa_atexit +or __cxa_thread_atexit, the linker should define a hidden symbol __dso_handle, with a value which is an address in one of the object's segments. -(It does not matter what address, -as long as they are different in different DSOs.) -It should also include a call to the following function in the FINI +(It does not matter what address, as long as they are different in +different DSOs.) + +

    +Additionally, DSOs that contain a call to __cxa_atexit ++should also include a call to the following function in the FINI list (to be executed first): -

    -extern "C" void __cxa_finalize ( void *d ); -
    +
    extern "C" void __cxa_finalize ( void *d );
    The parameter passed should be &__dso_handle.

    @@ -4196,8 +4278,10 @@

    3.3.6.3 Runtime API

    When the main program calls exit, -it must call any remaining __cxa_atexit-registered functions, -either by calling __cxa_finalize(NULL), +it must first call any __cxa_thread_atexit-registered +functions for the exiting thread. +Next, it must call any remaining __cxa_atexit-registered +functions, either by calling __cxa_finalize(NULL), or by walking the registration list itself.

    @@ -4208,8 +4292,9 @@

    3.3.6.3 Runtime API

-Since __cxa_atexit and __cxa_finalize -must both manipulate the same termination function list, +Since calls to __cxa_atexit, +__cxa_thread_atexit, and __cxa_finalize +must manipulate the same termination function lists, they must be defined in the implementation's runtime library, rather than in the individual linked objects.