Print this page
3849 implement __cxa_atexit/__cxa_finalize

*** 50,60 **** * Guide for information on alternate link maps. * * See "thr_uberdata.h" for the definitions of structures used here. */ ! static int in_range(_exithdlr_func_t, Lc_addr_range_t[], uint_t count); extern caddr_t _getfp(void); /* * exitfns_lock is declared to be a recursive mutex so that we --- 50,60 ---- * Guide for information on alternate link maps. * * See "thr_uberdata.h" for the definitions of structures used here. */ ! static int in_range(void *, Lc_addr_range_t[], uint_t count); extern caddr_t _getfp(void); /* * exitfns_lock is declared to be a recursive mutex so that we
*** 86,101 **** atexit_unlocks() { (void) mutex_unlock(&__uberdata.atexit_root.exitfns_lock); } /* * atexit() is called before the primordial thread is fully set up. * Be careful about dereferencing self->ul_uberdata->atexit_root. */ int ! atexit(void (*func)(void)) { ulwp_t *self; atexit_root_t *arp; _exthdlr_t *p; --- 86,102 ---- atexit_unlocks() { (void) mutex_unlock(&__uberdata.atexit_root.exitfns_lock); } + /* * atexit() is called before the primordial thread is fully set up. * Be careful about dereferencing self->ul_uberdata->atexit_root. */ int ! __cxa_atexit(void (*hdlr)(void *), void *arg, void *dso) { ulwp_t *self; atexit_root_t *arp; _exthdlr_t *p;
*** 106,145 **** arp = &__uberdata.atexit_root; else { arp = &self->ul_uberdata->atexit_root; (void) mutex_lock(&arp->exitfns_lock); } ! p->hdlr = func; p->next = arp->head; arp->head = p; if (self != NULL) (void) mutex_unlock(&arp->exitfns_lock); return (0); } void ! _exithandle(void) { atexit_root_t *arp = &curthread->ul_uberdata->atexit_root; ! _exthdlr_t *p; int cancel_state; /* disable cancellation while running atexit handlers */ (void) pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cancel_state); (void) mutex_lock(&arp->exitfns_lock); ! arp->exit_frame_monitor = _getfp() + STACK_BIAS; p = arp->head; while (p != NULL) { arp->head = p->next; ! p->hdlr(); lfree(p, sizeof (_exthdlr_t)); p = arp->head; } (void) mutex_unlock(&arp->exitfns_lock); (void) pthread_setcancelstate(cancel_state, NULL); } /* * _get_exit_frame_monitor is called by the C++ runtimes. */ void * _get_exit_frame_monitor(void) --- 107,181 ---- arp = &__uberdata.atexit_root; else { arp = &self->ul_uberdata->atexit_root; (void) mutex_lock(&arp->exitfns_lock); } ! p->hdlr = hdlr; ! p->arg = arg; ! p->dso = dso; p->next = arp->head; arp->head = p; + if (self != NULL) (void) mutex_unlock(&arp->exitfns_lock); return (0); } + int + atexit(void (*func)(void)) + { + return (__cxa_atexit((_exithdlr_func_t)func, NULL, NULL)); + } + + /* + * Note that we may be entered recursively, as we'll call __cxa_finalize(0) at + * exit, one of our handlers is ld.so.1`atexit_fini, and libraries may call + * __cxa_finalize(__dso_handle) from their _fini. + */ void ! __cxa_finalize(void *dso) { atexit_root_t *arp = &curthread->ul_uberdata->atexit_root; ! _exthdlr_t *p, *o; int cancel_state; /* disable cancellation while running atexit handlers */ (void) pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cancel_state); (void) mutex_lock(&arp->exitfns_lock); ! ! o = NULL; p = arp->head; while (p != NULL) { + if ((dso == NULL) || (p->dso == dso)) { + if (o != NULL) + o->next = p->next; + else arp->head = p->next; ! ! p->hdlr(p->arg); lfree(p, sizeof (_exthdlr_t)); + o = NULL; p = arp->head; + } else { + o = p; + p = p->next; } + } + (void) mutex_unlock(&arp->exitfns_lock); (void) pthread_setcancelstate(cancel_state, NULL); } + void + _exithandle(void) + { + atexit_root_t *arp = &curthread->ul_uberdata->atexit_root; + + arp->exit_frame_monitor = _getfp() + STACK_BIAS; + __cxa_finalize(NULL); + } + /* * _get_exit_frame_monitor is called by the C++ runtimes. */ void * _get_exit_frame_monitor(void)
*** 167,177 **** for (sig = 1; sig < NSIG; sig++) { sap = (struct sigaction *)&udp->siguaction[sig].sig_uaction; again: handler = sap->sa_handler; if (handler != SIG_DFL && handler != SIG_IGN && ! in_range(handler, range, count)) { rwlp = &udp->siguaction[sig].sig_lock; lrw_wrlock(rwlp); if (handler != sap->sa_handler) { lrw_unlock(rwlp); goto again; --- 203,213 ---- for (sig = 1; sig < NSIG; sig++) { sap = (struct sigaction *)&udp->siguaction[sig].sig_uaction; again: handler = sap->sa_handler; if (handler != SIG_DFL && handler != SIG_IGN && ! in_range((void *)handler, range, count)) { rwlp = &udp->siguaction[sig].sig_lock; lrw_wrlock(rwlp); if (handler != sap->sa_handler) { lrw_unlock(rwlp); goto again;
*** 211,225 **** do { next = atfp->forw; start_again = 0; if (((func = atfp->prepare) != NULL && ! in_range(func, range, count)) || ((func = atfp->parent) != NULL && ! in_range(func, range, count)) || ((func = atfp->child) != NULL && ! in_range(func, range, count))) { if (self->ul_fork) { /* * dlclose() called from a fork handler. * Deleting the entry would wreak havoc. * Just null out the function pointers --- 247,261 ---- do { next = atfp->forw; start_again = 0; if (((func = atfp->prepare) != NULL && ! in_range((void *)func, range, count)) || ((func = atfp->parent) != NULL && ! in_range((void *)func, range, count)) || ((func = atfp->child) != NULL && ! in_range((void *)func, range, count))) { if (self->ul_fork) { /* * dlclose() called from a fork handler. * Deleting the entry would wreak havoc. * Just null out the function pointers
*** 266,276 **** lmutex_lock(&tsdm->tsdm_lock); for (key = 1; key < tsdm->tsdm_nused; key++) { if ((func = tsdm->tsdm_destro[key]) != NULL && func != TSD_UNALLOCATED && ! in_range((_exithdlr_func_t)func, range, count)) tsdm->tsdm_destro[key] = NULL; } lmutex_unlock(&tsdm->tsdm_lock); } --- 302,312 ---- lmutex_lock(&tsdm->tsdm_lock); for (key = 1; key < tsdm->tsdm_nused; key++) { if ((func = tsdm->tsdm_destro[key]) != NULL && func != TSD_UNALLOCATED && ! in_range((void *)func, range, count)) tsdm->tsdm_destro[key] = NULL; } lmutex_unlock(&tsdm->tsdm_lock); }
*** 294,310 **** (void) pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cancel_state); (void) mutex_lock(&arp->exitfns_lock); o = NULL; p = arp->head; while (p != NULL) { ! if (in_range(p->hdlr, range, count)) { /* We need to execute this one */ if (o != NULL) o->next = p->next; else arp->head = p->next; ! p->hdlr(); lfree(p, sizeof (_exthdlr_t)); o = NULL; p = arp->head; } else { o = p; --- 330,357 ---- (void) pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cancel_state); (void) mutex_lock(&arp->exitfns_lock); o = NULL; p = arp->head; while (p != NULL) { ! /* ! * We call even CXA handlers of functions present in the ! * library being unloaded. The specification isn't ! * particularly clear on this, and this seems the most sane. ! * This is the behaviour of FreeBSD 9.1 (GNU libc leaves the ! * handler on the exit list, and crashes at exit time). ! * ! * This won't cause handlers to be called twice, because ! * anything called from a __cxa_finalize call from the ! * language runtime will have been removed from the list. ! */ ! if (in_range((void *)p->hdlr, range, count)) { /* We need to execute this one */ if (o != NULL) o->next = p->next; else arp->head = p->next; ! p->hdlr(p->arg); lfree(p, sizeof (_exthdlr_t)); o = NULL; p = arp->head; } else { o = p;
*** 320,336 **** return (0); } static int ! in_range(_exithdlr_func_t addr, Lc_addr_range_t ranges[], uint_t count) { uint_t idx; for (idx = 0; idx < count; idx++) { ! if ((void *)addr >= ranges[idx].lb && ! (void *)addr < ranges[idx].ub) { return (1); } } return (0); --- 367,383 ---- return (0); } static int ! in_range(void *addr, Lc_addr_range_t ranges[], uint_t count) { uint_t idx; for (idx = 0; idx < count; idx++) { ! if (addr >= ranges[idx].lb && ! addr < ranges[idx].ub) { return (1); } } return (0);