diff -r 000000000000 -r bde4ae8d615e os/ossrv/genericopenlibs/cppstdlib/stl/src/cxa.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/os/ossrv/genericopenlibs/cppstdlib/stl/src/cxa.c Fri Jun 15 03:10:57 2012 +0200 @@ -0,0 +1,182 @@ +#include "stlport_prefix.h" + +#if defined(__unix) && defined(__GNUC__) + +#ifdef __FreeBSD__ +# include +#endif + +#if (defined(__FreeBSD__) && (__FreeBSD_version < 503001)) || defined(__sun) +/* Note: __cxa_finalize and __cxa_atexit present in libc in FreeBSD 5.3, but again absent in 6.0 */ + +#include +#include +#include + +/* __asm__ (".symver " "__cxa_finalize" "," "__cxa_finalize" "@" "STLPORT_5_0_0"); */ +/* __asm__ (".symver " "__cxa_finalize" "," "__cxa_finalize" "@@" "STLPORT_5_0_0"); */ + +/* Not atomic! */ +/* But we can use static mutexes here: I hope that performance issue isn't very + significant on unloading (for only few calls, ~10) - ptr */ + +/* +#define atomic_compare_and_exchange_bool_acq(mem, newval, oldval) \ + ({ __typeof (mem) __gmemp = (mem); \ + __typeof (*mem) __gnewval = (newval); \ + \ + *__gmemp == (oldval) ? (*__gmemp = __gnewval, 0) : 1; }) +*/ + +enum { + ef_free, /* `ef_free' MUST be zero! */ + ef_us, + ef_on, + ef_at, + ef_cxa +}; + +struct exit_function +{ + /* `flavour' should be of type of the `enum' above but since we need + this element in an atomic operation we have to use `long int'. */ + long int flavor; + union { + void (*at)(void); + struct { + void (*fn)(int status, void *arg); + void *arg; + } on; + struct { + void (*fn)(void *arg, int status); + void *arg; + void *dso_handle; + } cxa; + } func; +}; + +struct exit_function_list +{ + struct exit_function_list *next; + size_t idx; + struct exit_function fns[32]; +}; + +struct exit_function *__new_exitfn (void); + +/* Register a function to be called by exit or when a shared library + is unloaded. This function is only called from code generated by + the C++ compiler. */ +int __cxa_atexit(void (*func)(void *), void *arg, void *d) +{ + struct exit_function *new = __new_exitfn (); + + if ( new == NULL ) + return -1; + + new->flavor = ef_cxa; + new->func.cxa.fn = (void (*) (void *, int)) func; + new->func.cxa.arg = arg; + new->func.cxa.dso_handle = d; + return 0; +} + + +/* We change global data, so we need locking. */ +#ifdef __linux__ +static pthread_mutex_t lock = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP; +#endif +#ifdef __FreeBSD__ +static pthread_mutex_t lock = + { PTHREAD_MUTEX_RECURSIVE /* PTHREAD_MUTEX_DEFAULT */, PTHREAD_PRIO_NONE, {NULL,NULL}, + NULL, { NULL }, /* MUTEX_FLAGS_PRIVATE */ 0x1, 0, 0, 0, {NULL, NULL}, + { 0, 0, 0, 0 } }; +#endif +#ifdef __sun +static pthread_mutex_t lock = + {{0, 0, 0, PTHREAD_MUTEX_RECURSIVE, _MUTEX_MAGIC}, {{{0}}}, 0}; +#endif + + +static struct exit_function_list initial; +struct exit_function_list *__exit_funcs = &initial; + +struct exit_function *__new_exitfn(void) +{ + struct exit_function_list *l; + size_t i = 0; + + pthread_mutex_lock( &lock ); + + for (l = __exit_funcs; l != NULL; l = l->next) { + for (i = 0; i < l->idx; ++i) + if (l->fns[i].flavor == ef_free) + break; + if ( i < l->idx ) + break; + + if (l->idx < sizeof (l->fns) / sizeof (l->fns[0])) { + i = l->idx++; + break; + } + } + + if (l == NULL) { + l = (struct exit_function_list *)malloc( sizeof(struct exit_function_list) ); + if (l != NULL) { + l->next = __exit_funcs; + __exit_funcs = l; + + l->idx = 1; + i = 0; + } + } + + /* Mark entry as used, but we don't know the flavor now. */ + if ( l != NULL ) + l->fns[i].flavor = ef_us; + + pthread_mutex_unlock( &lock ); + + return l == NULL ? NULL : &l->fns[i]; +} + +/* If D is non-NULL, call all functions registered with `__cxa_atexit' + with the same dso handle. Otherwise, if D is NULL, call all of the + registered handlers. */ + +/* + * Note, that original __cxa_finalize don't use lock, but use __exit_funcs + * i.e. global data. + */ +void __cxa_finalize(void *d) +{ + struct exit_function_list *funcs; + + pthread_mutex_lock( &lock ); + for (funcs = __exit_funcs; funcs; funcs = funcs->next) { + struct exit_function *f; + + for (f = &funcs->fns[funcs->idx - 1]; f >= &funcs->fns[0]; --f) { + if ( (d == NULL || d == f->func.cxa.dso_handle) && (f->flavor == ef_cxa) ) { + f->flavor = ef_free; + (*f->func.cxa.fn) (f->func.cxa.arg, 0); + } + } + } + + /* Remove the registered fork handlers. We do not have to + unregister anything if the program is going to terminate anyway. */ +#ifdef UNREGISTER_ATFORK + if (d != NULL) + UNREGISTER_ATFORK (d); +#endif + pthread_mutex_unlock( &lock ); +} + +/* __asm__ (".symver " "__cxa_finalize" "," "__cxa_finalize" "@@" "STLPORT_5_0_0"); */ +/* void __cxa_finalize(void *d) __attribute__ ((weak)); */ + +#endif /* OS name */ +#endif /* __unix */ +