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