os/ossrv/genericopenlibs/cppstdlib/stl/src/cxa.c
author sl@SLION-WIN7.fritz.box
Fri, 15 Jun 2012 03:10:57 +0200
changeset 0 bde4ae8d615e
permissions -rw-r--r--
First public contribution.
     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