Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Blame | Last modification | View Log | RSS feed

  1. /*
  2.  * COmmon routine to call call registered atexit-like routines.
  3.  */
  4.  
  5.  
  6. #include <stdlib.h>
  7. #include <reent.h>
  8. #include <sys/lock.h>
  9. #include "atexit.h"
  10.  
  11. /* Make this a weak reference to avoid pulling in free.  */
  12. void free(void *) _ATTRIBUTE((__weak__));
  13.  
  14. #ifndef __SINGLE_THREAD__
  15. extern _LOCK_RECURSIVE_T __atexit_lock;
  16. #endif
  17.  
  18. #ifdef _WANT_REGISTER_FINI
  19.  
  20. /* If "__libc_fini" is defined, finalizers (either
  21.    "__libc_fini_array", or "_fini", as appropriate) will be run after
  22.    all user-specified atexit handlers.  For example, you can define
  23.    "__libc_fini" to "_fini" in your linker script if you want the C
  24.    library, rather than startup code, to register finalizers.  If you
  25.    do that, then your startup code need not contain references to
  26.    "atexit" or "exit".  As a result, only applications that reference
  27.    "exit" explicitly will pull in finalization code.
  28.  
  29.    The choice of whether to register finalizers from libc or from
  30.    startup code is deferred to link-time, rather than being a
  31.    configure-time option, so that the same C library binary can be
  32.    used with multiple BSPs, some of which register finalizers from
  33.    startup code, while others defer to the C library.  */
  34. extern char __libc_fini __attribute__((weak));
  35.  
  36. /* Register the application finalization function with atexit.  These
  37.    finalizers should run last.  Therefore, we want to call atexit as
  38.    soon as possible.  */
  39. static void
  40. register_fini(void) __attribute__((constructor (0)));
  41.  
  42. static void
  43. register_fini(void)
  44. {
  45.   if (&__libc_fini) {
  46. #ifdef HAVE_INITFINI_ARRAY
  47.     extern void __libc_fini_array (void);
  48.     atexit (__libc_fini_array);
  49. #else
  50.     extern void _fini (void);
  51.     atexit (_fini);
  52. #endif
  53.   }
  54. }
  55.  
  56. #endif /* _WANT_REGISTER_FINI  */
  57.  
  58. /*
  59.  * Call registered exit handlers.  If D is null then all handlers are called,
  60.  * otherwise only the handlers from that DSO are called.
  61.  */
  62.  
  63. void
  64. _DEFUN (__call_exitprocs, (code, d),
  65.         int code _AND _PTR d)
  66. {
  67.   register struct _atexit *p;
  68.   struct _atexit **lastp;
  69.   register struct _on_exit_args * args;
  70.   register int n;
  71.   int i;
  72.   void (*fn) (void);
  73.  
  74.  
  75. #ifndef __SINGLE_THREAD__
  76.   __lock_acquire_recursive(__atexit_lock);
  77. #endif
  78.  
  79.  restart:
  80.  
  81.   p = _GLOBAL_REENT->_atexit;
  82.   lastp = &_GLOBAL_REENT->_atexit;
  83.   while (p)
  84.     {
  85. #ifdef _REENT_SMALL
  86.       args = p->_on_exit_args_ptr;
  87. #else
  88.       args = &p->_on_exit_args;
  89. #endif
  90.       for (n = p->_ind - 1; n >= 0; n--)
  91.         {
  92.           int ind;
  93.  
  94.           i = 1 << n;
  95.  
  96.           /* Skip functions not from this dso.  */
  97.           if (d && (!args || args->_dso_handle[n] != d))
  98.             continue;
  99.  
  100.           /* Remove the function now to protect against the
  101.              function calling exit recursively.  */
  102.           fn = p->_fns[n];
  103.           if (n == p->_ind - 1)
  104.             p->_ind--;
  105.           else
  106.             p->_fns[n] = NULL;
  107.  
  108.           /* Skip functions that have already been called.  */
  109.           if (!fn)
  110.             continue;
  111.  
  112.           ind = p->_ind;
  113.  
  114.           /* Call the function.  */
  115.           if (!args || (args->_fntypes & i) == 0)
  116.             fn ();
  117.           else if ((args->_is_cxa & i) == 0)
  118.             (*((void (*)(int, _PTR)) fn))(code, args->_fnargs[n]);
  119.           else
  120.             (*((void (*)(_PTR)) fn))(args->_fnargs[n]);
  121.  
  122.           /* The function we called call atexit and registered another
  123.              function (or functions).  Call these new functions before
  124.              continuing with the already registered functions.  */
  125.           if (ind != p->_ind || *lastp != p)
  126.             goto restart;
  127.         }
  128.  
  129. #ifndef _ATEXIT_DYNAMIC_ALLOC
  130.       break;
  131. #else
  132.       /* Don't dynamically free the atexit array if free is not
  133.          available.  */
  134.       if (!free)
  135.         break;
  136.  
  137.       /* Move to the next block.  Free empty blocks except the last one,
  138.          which is part of _GLOBAL_REENT.  */
  139.       if (p->_ind == 0 && p->_next)
  140.         {
  141.           /* Remove empty block from the list.  */
  142.           *lastp = p->_next;
  143. #ifdef _REENT_SMALL
  144.           if (args)
  145.             free (args);
  146. #endif
  147.           free (p);
  148.           p = *lastp;
  149.         }
  150.       else
  151.         {
  152.           lastp = &p->_next;
  153.           p = p->_next;
  154.         }
  155. #endif
  156.     }
  157. #ifndef __SINGLE_THREAD__
  158.   __lock_release_recursive(__atexit_lock);
  159. #endif
  160.  
  161. }
  162.