openbmc/build/tmp/deploy/sdk/witherspoon-2019-08-08/sysroots/armv6-openbmc-linux-gnueabi/usr/src/debug/glibc/2.29-r0/git/stdlib/cxa_finalize.c
void __cxa_finalize(void* d)
{
    struct exit_function_list* funcs;

    __libc_lock_lock(__exit_funcs_lock);

restart:
    for (funcs = __exit_funcs; funcs; funcs = funcs->next)
    {
        struct exit_function* f;

        for (f = &funcs->fns[funcs->idx - 1]; f >= &funcs->fns[0]; --f)
            if ((d == NULL || d == f->func.cxa.dso_handle) &&
                f->flavor == ef_cxa)
            {
                const uint64_t check = __new_exitfn_called;
                void (*cxafn)(void* arg, int status) = f->func.cxa.fn;
                void* cxaarg = f->func.cxa.arg;

                /* We don't want to run this cleanup more than once.  The
                   Itanium C++ ABI requires that multiple calls to
                   __cxa_finalize not result in calling termination functions
                   more than once.  One potential scenario where that could
                   happen is with a concurrent dlclose and exit, where the
                   running dlclose must at some point release the list lock, an
                   exiting thread may acquire it, and without setting flavor to
                   ef_free, might re-run this destructor which could result in
                   undefined behaviour.  Therefore we must set flavor to ef_free
                   to avoid calling this destructor again. Note that the
                   concurrent exit must also take the dynamic loader lock (for
                   library finalizer processing) and therefore will block while
                   dlclose completes the processing of any in-progress exit
                   functions. Lastly, once we release the list lock for the
                   entry marked ef_free, we must not read from that entry again
                   since it may have been reused by the time we take the list
                   lock again.  Lastly the detection of new registered exit
                   functions is based on a monotonically incrementing counter,
                   and there is an ABA if between the unlock to run the exit
                   function and the re-lock after completion the user registers
                   2^64 exit functions, the implementation will not detect this
                   and continue without executing any more functions.

                   One minor issue remains: A registered exit function that is
                   in progress by a call to dlclose() may not completely finish
                   before the next registered exit function is run. This may,
                   according to some readings of POSIX violate the requirement
                   that functions run in effective LIFO order.  This should
                   probably be fixed in a future implementation to ensure the
                   functions do not run in parallel.  */
                f->flavor = ef_free;

#ifdef PTR_DEMANGLE
                PTR_DEMANGLE(cxafn);
#endif
                /* Unlock the list while we call a foreign function.  */
                __libc_lock_unlock(__exit_funcs_lock);
                cxafn(cxaarg, 0);
                __libc_lock_lock(__exit_funcs_lock);

                /* It is possible that that last exit function registered
                   more exit functions.  Start the loop over.  */
                if (__glibc_unlikely(check != __new_exitfn_called))
                    goto restart;
            }
    }

    /* Also remove the quick_exit handlers, but do not call them.  */
    for (funcs = __quick_exit_funcs; funcs; funcs = funcs->next)
    {
        struct exit_function* f;

        for (f = &funcs->fns[funcs->idx - 1]; f >= &funcs->fns[0]; --f)
            if (d == NULL || d == f->func.cxa.dso_handle)
                f->flavor = ef_free;
    }

    /* Remove the registered fork handlers.  We do not have to
       unregister anything if the program is going to terminate anyway.  */
#ifdef UNREGISTER_ATFORK
    if (d != NULL)
        UNREGISTER_ATFORK(d);
#endif
    __libc_lock_unlock(__exit_funcs_lock);
}
/* If D is non-NULL, call all functions registered with `__cxa_atexit'
   with the same dso handle.  Otherwise, if D is NULL, call all of the
   registered handlers.  */
If D is non-NULL, call all functions registered with `__cxa_atexit'
with the same dso handle.  Otherwise, if D is NULL, call all of the
registered handlers.
If D is non - NULL call all functions registered with ` __cxa_atexit ' with the same dso handle . Otherwise if D is NULL call all of the registered handlers .
void __cxa_finalize(void* d)
{
    struct exit_function_list* funcs;
    __libc_lock_lock(__exit_funcs_lock);
restart:
    for (funcs = __exit_funcs; funcs; funcs = funcs->next)
    {
        struct exit_function* f;
        for (f = &funcs->fns[funcs->idx - 1]; f >= &funcs->fns[0]; --f)
            if ((d == NULL || d == f->func.cxa.dso_handle) &&
                f->flavor == ef_cxa)
            {
                const uint64_t check = __new_exitfn_called;
                void (*cxafn)(void* arg, int status) = f->func.cxa.fn;
                void* cxaarg = f->func.cxa.arg;
                f->flavor = ef_free;
#ifdef PTR_DEMANGLE
                PTR_DEMANGLE(cxafn);
#endif
                __libc_lock_unlock(__exit_funcs_lock);
                cxafn(cxaarg, 0);
                __libc_lock_lock(__exit_funcs_lock);
                if (__glibc_unlikely(check != __new_exitfn_called))
                    goto restart;
            }
    }
    for (funcs = __quick_exit_funcs; funcs; funcs = funcs->next)
    {
        struct exit_function* f;
        for (f = &funcs->fns[funcs->idx - 1]; f >= &funcs->fns[0]; --f)
            if (d == NULL || d == f->func.cxa.dso_handle)
                f->flavor = ef_free;
    }
#ifdef UNREGISTER_ATFORK
    if (d != NULL)
        UNREGISTER_ATFORK(d);
#endif
    __libc_lock_unlock(__exit_funcs_lock);
}
void __cxa_finalize ( void * d ) { struct exit_function_list * funcs ; __libc_lock_lock ( __exit_funcs_lock ) ; restart : for ( funcs = __exit_funcs ; funcs ; funcs = funcs -> next ) { struct exit_function * f ; for ( f = & funcs -> fns [ funcs -> idx - 1 ] ; f >= & funcs -> fns [ 0 ] ; -- f ) if ( ( d == NULL || d == f -> func . cxa . dso_handle ) && f -> flavor == ef_cxa ) { const uint64_t check = __new_exitfn_called ; void ( * cxafn ) ( void * arg , int status ) = f -> func . cxa . fn ; void * cxaarg = f -> func . cxa . arg ; f -> flavor = ef_free ; #ifdef PTR_DEMANGLE PTR_DEMANGLE ( cxafn ) ; #endif __libc_lock_unlock ( __exit_funcs_lock ) ; cxafn ( cxaarg , 0 ) ; __libc_lock_lock ( __exit_funcs_lock ) ; if ( __glibc_unlikely ( check != __new_exitfn_called ) ) goto restart ; } } for ( funcs = __quick_exit_funcs ; funcs ; funcs = funcs -> next ) { struct exit_function * f ; for ( f = & funcs -> fns [ funcs -> idx - 1 ] ; f >= & funcs -> fns [ 0 ] ; -- f ) if ( d == NULL || d == f -> func . cxa . dso_handle ) f -> flavor = ef_free ; } #ifdef UNREGISTER_ATFORK if ( d != NULL ) UNREGISTER_ATFORK ( d ) ; #endif __libc_lock_unlock ( __exit_funcs_lock ) ; }
If D is non-NULL, call all functions registered with `__cxa_atexit'
with the same dso handle.
If D is non - NULL call all functions registered with ` __cxa_atexit ' with the same dso handle .
/* We don't want to run this cleanup more than once.  The
                   Itanium C++ ABI requires that multiple calls to
                   __cxa_finalize not result in calling termination functions
                   more than once.  One potential scenario where that could
                   happen is with a concurrent dlclose and exit, where the
                   running dlclose must at some point release the list lock, an
                   exiting thread may acquire it, and without setting flavor to
                   ef_free, might re-run this destructor which could result in
                   undefined behaviour.  Therefore we must set flavor to ef_free
                   to avoid calling this destructor again. Note that the
                   concurrent exit must also take the dynamic loader lock (for
                   library finalizer processing) and therefore will block while
                   dlclose completes the processing of any in-progress exit
                   functions. Lastly, once we release the list lock for the
                   entry marked ef_free, we must not read from that entry again
                   since it may have been reused by the time we take the list
                   lock again.  Lastly the detection of new registered exit
                   functions is based on a monotonically incrementing counter,
                   and there is an ABA if between the unlock to run the exit
                   function and the re-lock after completion the user registers
                   2^64 exit functions, the implementation will not detect this
                   and continue without executing any more functions.

                   One minor issue remains: A registered exit function that is
                   in progress by a call to dlclose() may not completely finish
                   before the next registered exit function is run. This may,
                   according to some readings of POSIX violate the requirement
                   that functions run in effective LIFO order.  This should
                   probably be fixed in a future implementation to ensure the
                   functions do not run in parallel.  */ /* Unlock the list while we call a foreign function.  */ /* It is possible that that last exit function registered
                   more exit functions.  Start the loop over.  */ /* Also remove the quick_exit handlers, but do not call them.  */ /* Remove the registered fork handlers.  We do not have to
       unregister anything if the program is going to terminate anyway.  */