summaryrefslogtreecommitdiffstats
path: root/lib/libthr/thread
diff options
context:
space:
mode:
authorkib <kib@FreeBSD.org>2010-08-23 15:38:02 +0000
committerkib <kib@FreeBSD.org>2010-08-23 15:38:02 +0000
commitdf9bc4850f3a6aef289d53c0c3d1fc78d63bdda2 (patch)
tree509be3ad57df8011e952d3da4691f43abd346d2e /lib/libthr/thread
parent7ca1c6f40abcb8550b7bbf0c67ceb3a73d93b342 (diff)
downloadFreeBSD-src-df9bc4850f3a6aef289d53c0c3d1fc78d63bdda2.zip
FreeBSD-src-df9bc4850f3a6aef289d53c0c3d1fc78d63bdda2.tar.gz
On shared object unload, in __cxa_finalize, call and clear all installed
atexit and __cxa_atexit handlers that are either installed by unloaded dso, or points to the functions provided by the dso. Use _rtld_addr_phdr to locate segment information from the address of private variable belonging to the dso, supplied by crtstuff.c. Provide utility function __elf_phdr_match_addr to do the match of address against dso executable segment. Call back into libthr from __cxa_finalize using weak __pthread_cxa_finalize symbol to remove any atfork handler which function points into unloaded object. The rtld needs private __pthread_cxa_finalize symbol to not require resolution of the weak undefined symbol at initialization time. This cannot work, since rtld is relocated before sym_zero is set up. Idea by: kan Reviewed by: kan (previous version) MFC after: 3 weeks
Diffstat (limited to 'lib/libthr/thread')
-rw-r--r--lib/libthr/thread/thr_fork.c22
-rw-r--r--lib/libthr/thread/thr_private.h3
2 files changed, 25 insertions, 0 deletions
diff --git a/lib/libthr/thread/thr_fork.c b/lib/libthr/thread/thr_fork.c
index 529f38f..b1c221e 100644
--- a/lib/libthr/thread/thr_fork.c
+++ b/lib/libthr/thread/thr_fork.c
@@ -59,6 +59,7 @@
#include "namespace.h"
#include <errno.h>
+#include <link.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
@@ -94,6 +95,27 @@ _pthread_atfork(void (*prepare)(void), void (*parent)(void),
return (0);
}
+void
+__pthread_cxa_finalize(struct dl_phdr_info *phdr_info)
+{
+ struct pthread *curthread;
+ struct pthread_atfork *af, *af1;
+
+ _thr_check_init();
+
+ curthread = _get_curthread();
+ THR_UMUTEX_LOCK(curthread, &_thr_atfork_lock);
+ TAILQ_FOREACH_SAFE(af, &_thr_atfork_list, qe, af1) {
+ if (__elf_phdr_match_addr(phdr_info, af->prepare) ||
+ __elf_phdr_match_addr(phdr_info, af->parent) ||
+ __elf_phdr_match_addr(phdr_info, af->child)) {
+ TAILQ_REMOVE(&_thr_atfork_list, af, qe);
+ free(af);
+ }
+ }
+ THR_UMUTEX_UNLOCK(curthread, &_thr_atfork_lock);
+}
+
__weak_reference(_fork, fork);
pid_t _fork(void);
diff --git a/lib/libthr/thread/thr_private.h b/lib/libthr/thread/thr_private.h
index 465f725..f0c3aa0 100644
--- a/lib/libthr/thread/thr_private.h
+++ b/lib/libthr/thread/thr_private.h
@@ -740,6 +740,9 @@ _thr_check_init(void)
_libpthread_init(NULL);
}
+struct dl_phdr_info;
+void __pthread_cxa_finalize(struct dl_phdr_info *phdr_info);
+
__END_DECLS
#endif /* !_THR_PRIVATE_H */
OpenPOWER on IntegriCloud