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