/home/ntakagi/work/STLport-5.1.5/src/cxa.cGo to the documentation of this file.00001 #include "stlport_prefix.h" 00002 00003 #if defined(__unix) && defined(__GNUC__) 00004 00005 #ifdef __FreeBSD__ 00006 # include <osreldate.h> 00007 #endif 00008 00009 #if (defined(__FreeBSD__) && (__FreeBSD_version < 503001)) || defined(__sun) 00010 /* Note: __cxa_finalize and __cxa_atexit present in libc in FreeBSD 5.3, but again absent in 6.0 */ 00011 00012 #include <stdlib.h> 00013 #include <stdio.h> 00014 #include <pthread.h> 00015 00016 /* __asm__ (".symver " "__cxa_finalize" "," "__cxa_finalize" "@" "STLPORT_5_0_0"); */ 00017 /* __asm__ (".symver " "__cxa_finalize" "," "__cxa_finalize" "@@" "STLPORT_5_0_0"); */ 00018 00019 /* Not atomic! */ 00020 /* But we can use static mutexes here: I hope that performance issue isn't very 00021 significant on unloading (for only few calls, ~10) - ptr */ 00022 00023 /* 00024 #define atomic_compare_and_exchange_bool_acq(mem, newval, oldval) \ 00025 ({ __typeof (mem) __gmemp = (mem); \ 00026 __typeof (*mem) __gnewval = (newval); \ 00027 \ 00028 *__gmemp == (oldval) ? (*__gmemp = __gnewval, 0) : 1; }) 00029 */ 00030 00031 enum { 00032 ef_free, /* `ef_free' MUST be zero! */ 00033 ef_us, 00034 ef_on, 00035 ef_at, 00036 ef_cxa 00037 }; 00038 00039 struct exit_function 00040 { 00041 /* `flavour' should be of type of the `enum' above but since we need 00042 this element in an atomic operation we have to use `long int'. */ 00043 long int flavor; 00044 union { 00045 void (*at)(void); 00046 struct { 00047 void (*fn)(int status, void *arg); 00048 void *arg; 00049 } on; 00050 struct { 00051 void (*fn)(void *arg, int status); 00052 void *arg; 00053 void *dso_handle; 00054 } cxa; 00055 } func; 00056 }; 00057 00058 struct exit_function_list 00059 { 00060 struct exit_function_list *next; 00061 size_t idx; 00062 struct exit_function fns[32]; 00063 }; 00064 00065 struct exit_function *__new_exitfn (void); 00066 00067 /* Register a function to be called by exit or when a shared library 00068 is unloaded. This function is only called from code generated by 00069 the C++ compiler. */ 00070 int __cxa_atexit(void (*func)(void *), void *arg, void *d) 00071 { 00072 struct exit_function *new = __new_exitfn (); 00073 00074 if ( new == NULL ) 00075 return -1; 00076 00077 new->flavor = ef_cxa; 00078 new->func.cxa.fn = (void (*) (void *, int)) func; 00079 new->func.cxa.arg = arg; 00080 new->func.cxa.dso_handle = d; 00081 return 0; 00082 } 00083 00084 00085 /* We change global data, so we need locking. */ 00086 #ifdef __linux__ 00087 static pthread_mutex_t lock = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP; 00088 #endif 00089 #ifdef __FreeBSD__ 00090 static pthread_mutex_t lock = 00091 { PTHREAD_MUTEX_RECURSIVE /* PTHREAD_MUTEX_DEFAULT */, PTHREAD_PRIO_NONE, {NULL,NULL}, 00092 NULL, { NULL }, /* MUTEX_FLAGS_PRIVATE */ 0x1, 0, 0, 0, {NULL, NULL}, 00093 { 0, 0, 0, 0 } }; 00094 #endif 00095 #ifdef __sun 00096 static pthread_mutex_t lock = 00097 {{0, 0, 0, PTHREAD_MUTEX_RECURSIVE, _MUTEX_MAGIC}, {{{0}}}, 0}; 00098 #endif 00099 00100 00101 static struct exit_function_list initial; 00102 struct exit_function_list *__exit_funcs = &initial; 00103 00104 struct exit_function *__new_exitfn(void) 00105 { 00106 struct exit_function_list *l; 00107 size_t i = 0; 00108 00109 pthread_mutex_lock( &lock ); 00110 00111 for (l = __exit_funcs; l != NULL; l = l->next) { 00112 for (i = 0; i < l->idx; ++i) 00113 if (l->fns[i].flavor == ef_free) 00114 break; 00115 if ( i < l->idx ) 00116 break; 00117 00118 if (l->idx < sizeof (l->fns) / sizeof (l->fns[0])) { 00119 i = l->idx++; 00120 break; 00121 } 00122 } 00123 00124 if (l == NULL) { 00125 l = (struct exit_function_list *)malloc( sizeof(struct exit_function_list) ); 00126 if (l != NULL) { 00127 l->next = __exit_funcs; 00128 __exit_funcs = l; 00129 00130 l->idx = 1; 00131 i = 0; 00132 } 00133 } 00134 00135 /* Mark entry as used, but we don't know the flavor now. */ 00136 if ( l != NULL ) 00137 l->fns[i].flavor = ef_us; 00138 00139 pthread_mutex_unlock( &lock ); 00140 00141 return l == NULL ? NULL : &l->fns[i]; 00142 } 00143 00144 /* If D is non-NULL, call all functions registered with `__cxa_atexit' 00145 with the same dso handle. Otherwise, if D is NULL, call all of the 00146 registered handlers. */ 00147 00148 /* 00149 * Note, that original __cxa_finalize don't use lock, but use __exit_funcs 00150 * i.e. global data. 00151 */ 00152 void __cxa_finalize(void *d) 00153 { 00154 struct exit_function_list *funcs; 00155 00156 pthread_mutex_lock( &lock ); 00157 for (funcs = __exit_funcs; funcs; funcs = funcs->next) { 00158 struct exit_function *f; 00159 00160 for (f = &funcs->fns[funcs->idx - 1]; f >= &funcs->fns[0]; --f) { 00161 if ( (d == NULL || d == f->func.cxa.dso_handle) && (f->flavor == ef_cxa) ) { 00162 f->flavor = ef_free; 00163 (*f->func.cxa.fn) (f->func.cxa.arg, 0); 00164 } 00165 } 00166 } 00167 00168 /* Remove the registered fork handlers. We do not have to 00169 unregister anything if the program is going to terminate anyway. */ 00170 #ifdef UNREGISTER_ATFORK 00171 if (d != NULL) 00172 UNREGISTER_ATFORK (d); 00173 #endif 00174 pthread_mutex_unlock( &lock ); 00175 } 00176 00177 /* __asm__ (".symver " "__cxa_finalize" "," "__cxa_finalize" "@@" "STLPORT_5_0_0"); */ 00178 /* void __cxa_finalize(void *d) __attribute__ ((weak)); */ 00179 00180 #endif /* OS name */ 00181 #endif /* __unix */ 00182
Generated on Mon Mar 10 15:32:16 2008 by ![]() |