Subversion Repositories Kolibri OS

Rev

Rev 4874 | Go to most recent revision | 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.     _GLOBAL_ATEXIT = p = _GLOBAL_ATEXIT0;
  83.   if (p->_ind >= _ATEXIT_SIZE)
  84.     {
  85. #ifndef _ATEXIT_DYNAMIC_ALLOC
  86.       return -1;
  87. #else
  88.       /* Don't dynamically allocate the atexit array if malloc is not
  89.          available.  */
  90.       if (!malloc)
  91.         return -1;
  92.  
  93.       p = (struct _atexit *) malloc (sizeof *p);
  94.       if (p == NULL)
  95.         {
  96. #ifndef __SINGLE_THREAD__
  97.           __lock_release_recursive(__atexit_lock);
  98. #endif
  99.           return -1;
  100.         }
  101.       p->_ind = 0;
  102.       p->_next = _GLOBAL_ATEXIT;
  103.       _GLOBAL_ATEXIT = p;
  104. #ifndef _REENT_SMALL
  105.       p->_on_exit_args._fntypes = 0;
  106.       p->_on_exit_args._is_cxa = 0;
  107. #else
  108.       p->_on_exit_args_ptr = NULL;
  109. #endif
  110. #endif
  111.     }
  112.  
  113.   if (type != __et_atexit)
  114.     {
  115. #ifdef _REENT_SMALL
  116.       args = p->_on_exit_args_ptr;
  117.       if (args == NULL)
  118.         {
  119.           if (malloc)
  120.             args = malloc (sizeof * p->_on_exit_args_ptr);
  121.  
  122.           if (args == NULL)
  123.             {
  124. #ifndef __SINGLE_THREAD__
  125.               __lock_release(__atexit_lock);
  126. #endif
  127.               return -1;
  128.             }
  129.           args->_fntypes = 0;
  130.           args->_is_cxa = 0;
  131.           p->_on_exit_args_ptr = args;
  132.         }
  133. #else
  134.       args = &p->_on_exit_args;
  135. #endif
  136.       args->_fnargs[p->_ind] = arg;
  137.       args->_fntypes |= (1 << p->_ind);
  138.       args->_dso_handle[p->_ind] = d;
  139.       if (type == __et_cxa)
  140.         args->_is_cxa |= (1 << p->_ind);
  141.     }
  142.   p->_fns[p->_ind++] = fn;
  143. #ifndef __SINGLE_THREAD__
  144.   __lock_release_recursive(__atexit_lock);
  145. #endif
  146.   return 0;
  147. }
  148.