genericopenlibs/cppstdlib/stl/src/cxa.c
changeset 31 ce057bb09d0b
parent 0 e4d67989cc36
equal deleted inserted replaced
30:e20de85af2ee 31:ce057bb09d0b
       
     1 #include "stlport_prefix.h"
       
     2 
       
     3 #if defined(__unix) && defined(__GNUC__)
       
     4 
       
     5 #ifdef __FreeBSD__
       
     6 #  include <osreldate.h>
       
     7 #endif
       
     8 
       
     9 #if (defined(__FreeBSD__) && (__FreeBSD_version < 503001)) || defined(__sun)
       
    10 /* Note: __cxa_finalize and __cxa_atexit present in libc in FreeBSD 5.3, but again absent in 6.0 */
       
    11 
       
    12 #include <stdlib.h>
       
    13 #include <stdio.h>
       
    14 #include <pthread.h>
       
    15 
       
    16 /* __asm__ (".symver " "__cxa_finalize" "," "__cxa_finalize" "@" "STLPORT_5_0_0"); */
       
    17 /* __asm__ (".symver " "__cxa_finalize" "," "__cxa_finalize" "@@" "STLPORT_5_0_0"); */
       
    18 
       
    19 /* Not atomic! */
       
    20 /* But we can use static mutexes here: I hope that performance issue isn't very
       
    21    significant on unloading (for only few calls, ~10) - ptr */
       
    22 
       
    23 /*
       
    24 #define atomic_compare_and_exchange_bool_acq(mem, newval, oldval) \
       
    25   ({ __typeof (mem) __gmemp = (mem);                                  \
       
    26      __typeof (*mem) __gnewval = (newval);                            \
       
    27                                                                       \
       
    28      *__gmemp == (oldval) ? (*__gmemp = __gnewval, 0) : 1; })
       
    29 */
       
    30 
       
    31 enum {
       
    32   ef_free, /* `ef_free' MUST be zero!  */
       
    33   ef_us,
       
    34   ef_on,
       
    35   ef_at,
       
    36   ef_cxa
       
    37 };
       
    38 
       
    39 struct exit_function
       
    40 {
       
    41   /* `flavour' should be of type of the `enum' above but since we need
       
    42      this element in an atomic operation we have to use `long int'.  */
       
    43   long int flavor;
       
    44   union {
       
    45     void (*at)(void);
       
    46     struct {
       
    47       void (*fn)(int status, void *arg);
       
    48       void *arg;
       
    49     } on;
       
    50     struct {
       
    51       void (*fn)(void *arg, int status);
       
    52       void *arg;
       
    53       void *dso_handle;
       
    54     } cxa;
       
    55   } func;
       
    56 };
       
    57 
       
    58 struct exit_function_list
       
    59 {
       
    60   struct exit_function_list *next;
       
    61   size_t idx;
       
    62   struct exit_function fns[32];
       
    63 };
       
    64 
       
    65 struct exit_function *__new_exitfn (void);
       
    66 
       
    67 /* Register a function to be called by exit or when a shared library
       
    68    is unloaded.  This function is only called from code generated by
       
    69    the C++ compiler.  */
       
    70 int __cxa_atexit(void (*func)(void *), void *arg, void *d)
       
    71 {
       
    72   struct exit_function *new = __new_exitfn ();
       
    73 
       
    74   if ( new == NULL )
       
    75     return -1;
       
    76 
       
    77   new->flavor = ef_cxa;
       
    78   new->func.cxa.fn = (void (*) (void *, int)) func;
       
    79   new->func.cxa.arg = arg;
       
    80   new->func.cxa.dso_handle = d;
       
    81   return 0;
       
    82 }
       
    83 
       
    84 
       
    85 /* We change global data, so we need locking.  */
       
    86 #ifdef __linux__
       
    87 static pthread_mutex_t lock = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
       
    88 #endif
       
    89 #ifdef __FreeBSD__
       
    90 static pthread_mutex_t lock =
       
    91   { PTHREAD_MUTEX_RECURSIVE /* PTHREAD_MUTEX_DEFAULT */, PTHREAD_PRIO_NONE, {NULL,NULL},
       
    92     NULL, { NULL }, /* MUTEX_FLAGS_PRIVATE */ 0x1, 0, 0, 0, {NULL, NULL},
       
    93     { 0, 0, 0, 0 } };
       
    94 #endif
       
    95 #ifdef __sun
       
    96 static pthread_mutex_t lock =
       
    97   {{0, 0, 0, PTHREAD_MUTEX_RECURSIVE, _MUTEX_MAGIC}, {{{0}}}, 0};
       
    98 #endif
       
    99 
       
   100 
       
   101 static struct exit_function_list initial;
       
   102 struct exit_function_list *__exit_funcs = &initial;
       
   103 
       
   104 struct exit_function *__new_exitfn(void)
       
   105 {
       
   106   struct exit_function_list *l;
       
   107   size_t i = 0;
       
   108 
       
   109   pthread_mutex_lock( &lock );
       
   110 
       
   111   for (l = __exit_funcs; l != NULL; l = l->next) {
       
   112     for (i = 0; i < l->idx; ++i)
       
   113       if (l->fns[i].flavor == ef_free)
       
   114         break;
       
   115     if ( i < l->idx )
       
   116       break;
       
   117 
       
   118     if (l->idx < sizeof (l->fns) / sizeof (l->fns[0])) {
       
   119       i = l->idx++;
       
   120       break;
       
   121     }
       
   122   }
       
   123 
       
   124   if (l == NULL) {
       
   125     l = (struct exit_function_list *)malloc( sizeof(struct exit_function_list) );
       
   126     if (l != NULL) {
       
   127       l->next = __exit_funcs;
       
   128       __exit_funcs = l;
       
   129 
       
   130       l->idx = 1;
       
   131       i = 0;
       
   132     }
       
   133   }
       
   134 
       
   135   /* Mark entry as used, but we don't know the flavor now.  */
       
   136   if ( l != NULL )
       
   137     l->fns[i].flavor = ef_us;
       
   138 
       
   139   pthread_mutex_unlock( &lock );
       
   140 
       
   141   return l == NULL ? NULL : &l->fns[i];
       
   142 }
       
   143 
       
   144 /* If D is non-NULL, call all functions registered with `__cxa_atexit'
       
   145    with the same dso handle.  Otherwise, if D is NULL, call all of the
       
   146    registered handlers.  */
       
   147 
       
   148 /*
       
   149  * Note, that original __cxa_finalize don't use lock, but use __exit_funcs
       
   150  * i.e. global data.
       
   151  */
       
   152 void __cxa_finalize(void *d)
       
   153 {
       
   154   struct exit_function_list *funcs;
       
   155 
       
   156   pthread_mutex_lock( &lock );
       
   157   for (funcs = __exit_funcs; funcs; funcs = funcs->next) {
       
   158     struct exit_function *f;
       
   159 
       
   160     for (f = &funcs->fns[funcs->idx - 1]; f >= &funcs->fns[0]; --f) {
       
   161       if ( (d == NULL || d == f->func.cxa.dso_handle) && (f->flavor == ef_cxa) ) {
       
   162         f->flavor = ef_free;
       
   163         (*f->func.cxa.fn) (f->func.cxa.arg, 0);
       
   164       }
       
   165     }
       
   166   }
       
   167 
       
   168   /* Remove the registered fork handlers.  We do not have to
       
   169      unregister anything if the program is going to terminate anyway.  */
       
   170 #ifdef UNREGISTER_ATFORK
       
   171   if (d != NULL)
       
   172     UNREGISTER_ATFORK (d);
       
   173 #endif
       
   174   pthread_mutex_unlock( &lock );
       
   175 }
       
   176 
       
   177 /* __asm__ (".symver " "__cxa_finalize" "," "__cxa_finalize" "@@" "STLPORT_5_0_0"); */
       
   178 /* void __cxa_finalize(void *d) __attribute__ ((weak)); */
       
   179 
       
   180 #endif /* OS name */
       
   181 #endif /* __unix */
       
   182