os/ossrv/genericopenlibs/cppstdlib/stl/src/cxa.c
changeset 0 bde4ae8d615e
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/os/ossrv/genericopenlibs/cppstdlib/stl/src/cxa.c	Fri Jun 15 03:10:57 2012 +0200
     1.3 @@ -0,0 +1,182 @@
     1.4 +#include "stlport_prefix.h"
     1.5 +
     1.6 +#if defined(__unix) && defined(__GNUC__)
     1.7 +
     1.8 +#ifdef __FreeBSD__
     1.9 +#  include <osreldate.h>
    1.10 +#endif
    1.11 +
    1.12 +#if (defined(__FreeBSD__) && (__FreeBSD_version < 503001)) || defined(__sun)
    1.13 +/* Note: __cxa_finalize and __cxa_atexit present in libc in FreeBSD 5.3, but again absent in 6.0 */
    1.14 +
    1.15 +#include <stdlib.h>
    1.16 +#include <stdio.h>
    1.17 +#include <pthread.h>
    1.18 +
    1.19 +/* __asm__ (".symver " "__cxa_finalize" "," "__cxa_finalize" "@" "STLPORT_5_0_0"); */
    1.20 +/* __asm__ (".symver " "__cxa_finalize" "," "__cxa_finalize" "@@" "STLPORT_5_0_0"); */
    1.21 +
    1.22 +/* Not atomic! */
    1.23 +/* But we can use static mutexes here: I hope that performance issue isn't very
    1.24 +   significant on unloading (for only few calls, ~10) - ptr */
    1.25 +
    1.26 +/*
    1.27 +#define atomic_compare_and_exchange_bool_acq(mem, newval, oldval) \
    1.28 +  ({ __typeof (mem) __gmemp = (mem);                                  \
    1.29 +     __typeof (*mem) __gnewval = (newval);                            \
    1.30 +                                                                      \
    1.31 +     *__gmemp == (oldval) ? (*__gmemp = __gnewval, 0) : 1; })
    1.32 +*/
    1.33 +
    1.34 +enum {
    1.35 +  ef_free, /* `ef_free' MUST be zero!  */
    1.36 +  ef_us,
    1.37 +  ef_on,
    1.38 +  ef_at,
    1.39 +  ef_cxa
    1.40 +};
    1.41 +
    1.42 +struct exit_function
    1.43 +{
    1.44 +  /* `flavour' should be of type of the `enum' above but since we need
    1.45 +     this element in an atomic operation we have to use `long int'.  */
    1.46 +  long int flavor;
    1.47 +  union {
    1.48 +    void (*at)(void);
    1.49 +    struct {
    1.50 +      void (*fn)(int status, void *arg);
    1.51 +      void *arg;
    1.52 +    } on;
    1.53 +    struct {
    1.54 +      void (*fn)(void *arg, int status);
    1.55 +      void *arg;
    1.56 +      void *dso_handle;
    1.57 +    } cxa;
    1.58 +  } func;
    1.59 +};
    1.60 +
    1.61 +struct exit_function_list
    1.62 +{
    1.63 +  struct exit_function_list *next;
    1.64 +  size_t idx;
    1.65 +  struct exit_function fns[32];
    1.66 +};
    1.67 +
    1.68 +struct exit_function *__new_exitfn (void);
    1.69 +
    1.70 +/* Register a function to be called by exit or when a shared library
    1.71 +   is unloaded.  This function is only called from code generated by
    1.72 +   the C++ compiler.  */
    1.73 +int __cxa_atexit(void (*func)(void *), void *arg, void *d)
    1.74 +{
    1.75 +  struct exit_function *new = __new_exitfn ();
    1.76 +
    1.77 +  if ( new == NULL )
    1.78 +    return -1;
    1.79 +
    1.80 +  new->flavor = ef_cxa;
    1.81 +  new->func.cxa.fn = (void (*) (void *, int)) func;
    1.82 +  new->func.cxa.arg = arg;
    1.83 +  new->func.cxa.dso_handle = d;
    1.84 +  return 0;
    1.85 +}
    1.86 +
    1.87 +
    1.88 +/* We change global data, so we need locking.  */
    1.89 +#ifdef __linux__
    1.90 +static pthread_mutex_t lock = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
    1.91 +#endif
    1.92 +#ifdef __FreeBSD__
    1.93 +static pthread_mutex_t lock =
    1.94 +  { PTHREAD_MUTEX_RECURSIVE /* PTHREAD_MUTEX_DEFAULT */, PTHREAD_PRIO_NONE, {NULL,NULL},
    1.95 +    NULL, { NULL }, /* MUTEX_FLAGS_PRIVATE */ 0x1, 0, 0, 0, {NULL, NULL},
    1.96 +    { 0, 0, 0, 0 } };
    1.97 +#endif
    1.98 +#ifdef __sun
    1.99 +static pthread_mutex_t lock =
   1.100 +  {{0, 0, 0, PTHREAD_MUTEX_RECURSIVE, _MUTEX_MAGIC}, {{{0}}}, 0};
   1.101 +#endif
   1.102 +
   1.103 +
   1.104 +static struct exit_function_list initial;
   1.105 +struct exit_function_list *__exit_funcs = &initial;
   1.106 +
   1.107 +struct exit_function *__new_exitfn(void)
   1.108 +{
   1.109 +  struct exit_function_list *l;
   1.110 +  size_t i = 0;
   1.111 +
   1.112 +  pthread_mutex_lock( &lock );
   1.113 +
   1.114 +  for (l = __exit_funcs; l != NULL; l = l->next) {
   1.115 +    for (i = 0; i < l->idx; ++i)
   1.116 +      if (l->fns[i].flavor == ef_free)
   1.117 +        break;
   1.118 +    if ( i < l->idx )
   1.119 +      break;
   1.120 +
   1.121 +    if (l->idx < sizeof (l->fns) / sizeof (l->fns[0])) {
   1.122 +      i = l->idx++;
   1.123 +      break;
   1.124 +    }
   1.125 +  }
   1.126 +
   1.127 +  if (l == NULL) {
   1.128 +    l = (struct exit_function_list *)malloc( sizeof(struct exit_function_list) );
   1.129 +    if (l != NULL) {
   1.130 +      l->next = __exit_funcs;
   1.131 +      __exit_funcs = l;
   1.132 +
   1.133 +      l->idx = 1;
   1.134 +      i = 0;
   1.135 +    }
   1.136 +  }
   1.137 +
   1.138 +  /* Mark entry as used, but we don't know the flavor now.  */
   1.139 +  if ( l != NULL )
   1.140 +    l->fns[i].flavor = ef_us;
   1.141 +
   1.142 +  pthread_mutex_unlock( &lock );
   1.143 +
   1.144 +  return l == NULL ? NULL : &l->fns[i];
   1.145 +}
   1.146 +
   1.147 +/* If D is non-NULL, call all functions registered with `__cxa_atexit'
   1.148 +   with the same dso handle.  Otherwise, if D is NULL, call all of the
   1.149 +   registered handlers.  */
   1.150 +
   1.151 +/*
   1.152 + * Note, that original __cxa_finalize don't use lock, but use __exit_funcs
   1.153 + * i.e. global data.
   1.154 + */
   1.155 +void __cxa_finalize(void *d)
   1.156 +{
   1.157 +  struct exit_function_list *funcs;
   1.158 +
   1.159 +  pthread_mutex_lock( &lock );
   1.160 +  for (funcs = __exit_funcs; funcs; funcs = funcs->next) {
   1.161 +    struct exit_function *f;
   1.162 +
   1.163 +    for (f = &funcs->fns[funcs->idx - 1]; f >= &funcs->fns[0]; --f) {
   1.164 +      if ( (d == NULL || d == f->func.cxa.dso_handle) && (f->flavor == ef_cxa) ) {
   1.165 +        f->flavor = ef_free;
   1.166 +        (*f->func.cxa.fn) (f->func.cxa.arg, 0);
   1.167 +      }
   1.168 +    }
   1.169 +  }
   1.170 +
   1.171 +  /* Remove the registered fork handlers.  We do not have to
   1.172 +     unregister anything if the program is going to terminate anyway.  */
   1.173 +#ifdef UNREGISTER_ATFORK
   1.174 +  if (d != NULL)
   1.175 +    UNREGISTER_ATFORK (d);
   1.176 +#endif
   1.177 +  pthread_mutex_unlock( &lock );
   1.178 +}
   1.179 +
   1.180 +/* __asm__ (".symver " "__cxa_finalize" "," "__cxa_finalize" "@@" "STLPORT_5_0_0"); */
   1.181 +/* void __cxa_finalize(void *d) __attribute__ ((weak)); */
   1.182 +
   1.183 +#endif /* OS name */
   1.184 +#endif /* __unix */
   1.185 +