diff options
author | Rich Felker <dalias@aerifal.cx> | 2011-02-13 19:58:30 -0500 |
---|---|---|
committer | Rich Felker <dalias@aerifal.cx> | 2011-02-13 19:58:30 -0500 |
commit | 1a9a2ff7b0daf99100db53440a0b18b2801566ca (patch) | |
tree | 2dba96173c946fc846059f65e4651bc648353ff5 /src/thread/pthread_create.c | |
parent | 50e26f09eb13f6568113a05dbcfe94a6b1010da0 (diff) | |
download | musl-1a9a2ff7b0daf99100db53440a0b18b2801566ca.tar.gz musl-1a9a2ff7b0daf99100db53440a0b18b2801566ca.tar.xz musl-1a9a2ff7b0daf99100db53440a0b18b2801566ca.zip |
reorganize thread exit code, make pthread_exit call cancellation handlers (pt2)
Diffstat (limited to 'src/thread/pthread_create.c')
-rw-r--r-- | src/thread/pthread_create.c | 63 |
1 files changed, 50 insertions, 13 deletions
diff --git a/src/thread/pthread_create.c b/src/thread/pthread_create.c index 6fa484c7..72d7acbc 100644 --- a/src/thread/pthread_create.c +++ b/src/thread/pthread_create.c @@ -1,6 +1,38 @@ #include "pthread_impl.h" -#define pthread_self __pthread_self +void __pthread_unwind_next(struct __ptcb *cb) +{ + int i, j, not_finished; + pthread_t self; + + if (cb->__next) longjmp((void *)cb->__next->__jb, 1); + + self = pthread_self(); + if (self->cancel) self->result = PTHREAD_CANCELLED; + + if (!a_fetch_add(&libc.threads_minus_1, -1)) + exit(0); + + LOCK(&self->exitlock); + + not_finished = self->tsd_used; + for (j=0; not_finished && j<PTHREAD_DESTRUCTOR_ITERATIONS; j++) { + not_finished = 0; + for (i=0; i<PTHREAD_KEYS_MAX; i++) { + if (self->tsd[i] && libc.tsd_keys[i]) { + void *tmp = self->tsd[i]; + self->tsd[i] = 0; + libc.tsd_keys[i](tmp); + not_finished = 1; + } + } + } + + if (self->detached && self->map_base) + __unmapself(self->map_base, self->map_size); + + __syscall_exit(0); +} static void docancel(struct pthread *self) { @@ -10,13 +42,21 @@ static void docancel(struct pthread *self) static void cancel_handler(int sig, siginfo_t *si, void *ctx) { - struct pthread *self = pthread_self(); + struct pthread *self = __pthread_self(); self->cancel = 1; if (self->canceldisable || (!self->cancelasync && !self->cancelpoint)) return; docancel(self); } +static void cancelpt(int x) +{ + struct pthread *self = __pthread_self(); + if (self->canceldisable) return; + self->cancelpoint = x; + if (self->cancel) docancel(self); +} + /* "rsyscall" is a mechanism by which a thread can synchronously force all * other threads to perform an arbitrary syscall. It is necessary to work * around the non-conformant implementation of setuid() et al on Linux, @@ -50,7 +90,7 @@ static int rsyscall(int nr, long a, long b, long c, long d, long e, long f) { int i, ret; sigset_t set = { 0 }; - struct pthread *self = pthread_self(); + struct pthread *self = __pthread_self(); sigaddset(&set, SIGSYSCALL); LOCK(&rs.lock); @@ -90,14 +130,6 @@ static int rsyscall(int nr, long a, long b, long c, long d, long e, long f) return ret; } -static void cancelpt(int x) -{ - struct pthread *self = pthread_self(); - if (self->canceldisable) return; - self->cancelpoint = x; - if (self->cancel) docancel(self); -} - static void init_threads() { struct sigaction sa = { .sa_flags = SA_SIGINFO | SA_RESTART }; @@ -120,8 +152,6 @@ static int start(void *p) return 0; } -#undef pthread_self - #define CLONE_MAGIC 0x7d0f00 int __clone(int (*)(void *), void *, int, void *, pid_t *, void *, pid_t *); @@ -187,3 +217,10 @@ int pthread_create(pthread_t *res, const pthread_attr_t *attr, void *(*entry)(vo *res = new; return 0; } + +void pthread_exit(void *result) +{ + struct pthread *self = pthread_self(); + self->result = result; + docancel(self); +} |