Home | History | Annotate | Download | only in src
      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) || defined (__hpux)
     10 /* Note: __cxa_finalize and __cxa_atexit present in libc in FreeBSD 5.3 */
     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 #if 0
     91 static pthread_mutex_t lock =
     92   { PTHREAD_MUTEX_RECURSIVE /* PTHREAD_MUTEX_DEFAULT */, PTHREAD_PRIO_NONE, {NULL,NULL},
     93     NULL, { NULL }, /* MUTEX_FLAGS_PRIVATE */ 0x1, 0, 0, 0, {NULL, NULL},
     94     { 0, 0, 0, 0 } };
     95 #endif
     96 #ifdef __sun
     97 static pthread_mutex_t lock =
     98   {{0, 0, 0, PTHREAD_MUTEX_RECURSIVE, _MUTEX_MAGIC}, {{{0}}}, 0};
     99 #endif
    100 #ifdef __hpux
    101 static pthread_mutex_t lock = PTHREAD_MUTEX_RECURSIVE_INITIALIZER_NP;
    102 #  ifdef __ia64
    103 void *__dso_handle = (void *) &__dso_handle;
    104 #  endif
    105 #endif
    106 
    107 
    108 static struct exit_function_list initial;
    109 struct exit_function_list *__exit_funcs = &initial;
    110 
    111 struct exit_function *__new_exitfn(void)
    112 {
    113   struct exit_function_list *l;
    114   size_t i = 0;
    115 
    116 #ifndef __FreeBSD__
    117   pthread_mutex_lock( &lock );
    118 #endif
    119 
    120   for (l = __exit_funcs; l != NULL; l = l->next) {
    121     for (i = 0; i < l->idx; ++i)
    122       if (l->fns[i].flavor == ef_free)
    123         break;
    124     if ( i < l->idx )
    125       break;
    126 
    127     if (l->idx < sizeof (l->fns) / sizeof (l->fns[0])) {
    128       i = l->idx++;
    129       break;
    130     }
    131   }
    132 
    133   if (l == NULL) {
    134     l = (struct exit_function_list *)malloc( sizeof(struct exit_function_list) );
    135     if (l != NULL) {
    136       l->next = __exit_funcs;
    137       __exit_funcs = l;
    138 
    139       l->idx = 1;
    140       i = 0;
    141     }
    142   }
    143 
    144   /* Mark entry as used, but we don't know the flavor now.  */
    145   if ( l != NULL )
    146     l->fns[i].flavor = ef_us;
    147 
    148 #ifndef __FreeBSD__
    149   pthread_mutex_unlock( &lock );
    150 #endif
    151 
    152   return l == NULL ? NULL : &l->fns[i];
    153 }
    154 
    155 /* If D is non-NULL, call all functions registered with `__cxa_atexit'
    156    with the same dso handle.  Otherwise, if D is NULL, call all of the
    157    registered handlers.  */
    158 
    159 /*
    160  * Note, that original __cxa_finalize don't use lock, but use __exit_funcs
    161  * i.e. global data.
    162  */
    163 void __cxa_finalize(void *d)
    164 {
    165   struct exit_function_list *funcs;
    166 
    167 #ifndef __FreeBSD__
    168   pthread_mutex_lock( &lock );
    169 #endif
    170 
    171   for (funcs = __exit_funcs; funcs; funcs = funcs->next) {
    172     struct exit_function *f;
    173 
    174     for (f = &funcs->fns[funcs->idx - 1]; f >= &funcs->fns[0]; --f) {
    175       if ( (d == NULL || d == f->func.cxa.dso_handle) && (f->flavor == ef_cxa) ) {
    176         f->flavor = ef_free;
    177         (*f->func.cxa.fn) (f->func.cxa.arg, 0);
    178       }
    179     }
    180   }
    181 
    182   /* Remove the registered fork handlers.  We do not have to
    183      unregister anything if the program is going to terminate anyway.  */
    184 #ifdef UNREGISTER_ATFORK
    185   if (d != NULL)
    186     UNREGISTER_ATFORK (d);
    187 #endif
    188 #ifndef __FreeBSD__
    189   pthread_mutex_unlock( &lock );
    190 #endif
    191 }
    192 
    193 /* __asm__ (".symver " "__cxa_finalize" "," "__cxa_finalize" "@@" "STLPORT_5_0_0"); */
    194 /* void __cxa_finalize(void *d) __attribute__ ((weak)); */
    195 
    196 #endif /* OS name */
    197 #endif /* __unix */
    198 
    199