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);