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