Subversion Repositories Kolibri OS

Rev

Rev 4921 | Blame | Compare with Previous | Last modification | View Log | RSS feed

  1. /*
  2.  *  Common routine to implement atexit-like functionality.
  3.  *
  4.  *  This is also the key function to be configured as lite exit, a size-reduced
  5.  *  implementation of exit that doesn't invoke clean-up functions such as _fini
  6.  *  or global destructors.
  7.  *
  8.  *  Default (without lite exit) call graph is like:
  9.  *  _start -> atexit -> __register_exitproc
  10.  *  _start -> __libc_init_array -> __cxa_atexit -> __register_exitproc
  11.  *  on_exit -> __register_exitproc
  12.  *  _start -> exit -> __call_exitprocs
  13.  *
  14.  *  Here an -> means arrow tail invokes arrow head. All invocations here
  15.  *  are non-weak reference in current newlib/libgloss.
  16.  *
  17.  *  Lite exit makes some of above calls as weak reference, so that size expansive
  18.  *  functions __register_exitproc and __call_exitprocs may not be linked. These
  19.  *  calls are:
  20.  *    _start w-> atexit
  21.  *    __cxa_atexit w-> __register_exitproc
  22.  *    exit w-> __call_exitprocs
  23.  *
  24.  *  Lite exit also makes sure that __call_exitprocs will be referenced as non-weak
  25.  *  whenever __register_exitproc is referenced as non-weak.
  26.  *
  27.  *  Thus with lite exit libs, a program not explicitly calling atexit or on_exit
  28.  *  will escape from the burden of cleaning up code. A program with atexit or on_exit
  29.  *  will work consistently to normal libs.
  30.  *
  31.  *  Lite exit is enabled with --enable-lite-exit, and is controlled with macro
  32.  *  _LITE_EXIT.
  33.  */
  34.  
  35. #include <stddef.h>
  36. #include <stdlib.h>
  37. #include <reent.h>
  38. #include <sys/lock.h>
  39. #include "atexit.h"
  40.  
  41. /* Make this a weak reference to avoid pulling in malloc.  */
  42. void * malloc(size_t) _ATTRIBUTE((__weak__));
  43.  
  44. #ifdef _LITE_EXIT
  45. /* As __call_exitprocs is weak reference in lite exit, make a
  46.    non-weak reference to it here.  */
  47. const void * __atexit_dummy = &__call_exitprocs;
  48. #endif
  49.  
  50. #ifndef __SINGLE_THREAD__
  51. extern _LOCK_RECURSIVE_T __atexit_lock;
  52. #endif
  53.  
  54. #ifdef _REENT_GLOBAL_ATEXIT
  55. static struct _atexit _global_atexit0 = _ATEXIT_INIT;
  56. # define _GLOBAL_ATEXIT0 (&_global_atexit0)
  57. #else
  58. # define _GLOBAL_ATEXIT0 (&_GLOBAL_REENT->_atexit0)
  59. #endif
  60.  
  61. /*
  62.  * Register a function to be performed at exit or on shared library unload.
  63.  */
  64.  
  65. int
  66. _DEFUN (__register_exitproc,
  67.         (type, fn, arg, d),
  68.         int type _AND
  69.         void (*fn) (void) _AND
  70.         void *arg _AND
  71.         void *d)
  72. {
  73.   struct _on_exit_args * args;
  74.   register struct _atexit *p;
  75.  
  76. #ifndef __SINGLE_THREAD__
  77.   __lock_acquire_recursive(__atexit_lock);
  78. #endif
  79.  
  80.   p = _GLOBAL_ATEXIT;
  81.   if (p == NULL)
  82.     {
  83.       _GLOBAL_ATEXIT = p = _GLOBAL_ATEXIT0;
  84. #ifdef _REENT_SMALL
  85.       extern struct _on_exit_args * const __on_exit_args _ATTRIBUTE ((weak));
  86.       if (&__on_exit_args != NULL)
  87.         p->_on_exit_args_ptr = __on_exit_args;
  88. #endif  /* def _REENT_SMALL */
  89.     }
  90.   if (p->_ind >= _ATEXIT_SIZE)
  91.     {
  92. #ifndef _ATEXIT_DYNAMIC_ALLOC
  93. #ifndef __SINGLE_THREAD__
  94.       __lock_release_recursive(__atexit_lock);
  95. #endif
  96.       return -1;
  97. #else
  98.       /* Don't dynamically allocate the atexit array if malloc is not
  99.          available.  */
  100.       if (!malloc)
  101.         {
  102. #ifndef __SINGLE_THREAD__
  103.           __lock_release_recursive(__atexit_lock);
  104. #endif
  105.           return -1;
  106.         }
  107.  
  108.       p = (struct _atexit *) malloc (sizeof *p);
  109.       if (p == NULL)
  110.         {
  111. #ifndef __SINGLE_THREAD__
  112.           __lock_release_recursive(__atexit_lock);
  113. #endif
  114.           return -1;
  115.         }
  116.       p->_ind = 0;
  117.       p->_next = _GLOBAL_ATEXIT;
  118.       _GLOBAL_ATEXIT = p;
  119. #ifndef _REENT_SMALL
  120.       p->_on_exit_args._fntypes = 0;
  121.       p->_on_exit_args._is_cxa = 0;
  122. #else
  123.       p->_on_exit_args_ptr = NULL;
  124. #endif
  125. #endif
  126.     }
  127.  
  128.   if (type != __et_atexit)
  129.     {
  130. #ifdef _REENT_SMALL
  131.       args = p->_on_exit_args_ptr;
  132.       if (args == NULL)
  133.         {
  134. #ifndef _ATEXIT_DYNAMIC_ALLOC
  135. #ifndef __SINGLE_THREAD__
  136.           __lock_release_recursive(__atexit_lock);
  137. #endif
  138.           return -1;
  139. #else
  140.           if (malloc)
  141.             args = malloc (sizeof * p->_on_exit_args_ptr);
  142.  
  143.           if (args == NULL)
  144.             {
  145. #ifndef __SINGLE_THREAD__
  146.               __lock_release(__atexit_lock);
  147. #endif
  148.               return -1;
  149.             }
  150.           args->_fntypes = 0;
  151.           args->_is_cxa = 0;
  152.           p->_on_exit_args_ptr = args;
  153. #endif
  154.         }
  155. #else
  156.       args = &p->_on_exit_args;
  157. #endif
  158.       args->_fnargs[p->_ind] = arg;
  159.       args->_fntypes |= (1 << p->_ind);
  160.       args->_dso_handle[p->_ind] = d;
  161.       if (type == __et_cxa)
  162.         args->_is_cxa |= (1 << p->_ind);
  163.     }
  164.   p->_fns[p->_ind++] = fn;
  165. #ifndef __SINGLE_THREAD__
  166.   __lock_release_recursive(__atexit_lock);
  167. #endif
  168.   return 0;
  169. }
  170.