overhaul pthread cancellation
[musl] / src / thread / pthread_create.c
index a722a2d..844d7bf 100644 (file)
@@ -19,6 +19,7 @@ weak_alias(dummy_1, __pthread_tsd_run_dtors);
 void __pthread_unwind_next(struct __ptcb *cb)
 {
        pthread_t self;
+       int n;
 
        if (cb->__next) longjmp((void *)cb->__next->__jb, 1);
 
@@ -31,8 +32,9 @@ void __pthread_unwind_next(struct __ptcb *cb)
        /* Mark this thread dead before decrementing count */
        self->dead = 1;
 
-       if (!a_fetch_add(&libc.threads_minus_1, -1))
-               exit(0);
+       do n = libc.threads_minus_1;
+       while (n && a_cas(&libc.threads_minus_1, n, n-1)!=n);
+       if (!n) exit(0);
 
        if (self->detached && self->map_base) {
                __syscall(SYS_rt_sigprocmask, SIG_BLOCK, (long)(uint64_t[1]){-1},0,8);
@@ -42,43 +44,16 @@ void __pthread_unwind_next(struct __ptcb *cb)
        __syscall(SYS_exit, 0);
 }
 
-static void docancel(struct pthread *self)
-{
-       struct __ptcb cb = { .__next = self->cancelbuf };
-       self->canceldisable = 1;
-       self->cancelasync = 0;
-       __pthread_unwind_next(&cb);
-}
-
-static void cancel_handler(int sig, siginfo_t *si, void *ctx)
-{
-       struct pthread *self = __pthread_self();
-       if (self->cancel && !self->canceldisable &&
-           (self->cancelasync || (self->cancelpoint==1 && PC_AT_SYS(ctx))))
-               docancel(self);
-}
-
-static void cancelpt(int x)
-{
-       struct pthread *self = __pthread_self();
-       if ((self->cancelpoint+=x)==1 && self->cancel
-               && x<2U && !self->canceldisable) docancel(self);
-}
-
 static void init_threads()
 {
-       struct sigaction sa = { .sa_flags = SA_SIGINFO | SA_RESTART };
+       sigset_t set;
        libc.lock = __lock;
        libc.lockfile = __lockfile;
-       libc.cancelpt = cancelpt;
-
-       sigemptyset(&sa.sa_mask);
-       sa.sa_sigaction = cancel_handler;
-       __libc_sigaction(SIGCANCEL, &sa, 0);
 
-       sigaddset(&sa.sa_mask, SIGSYSCALL);
-       sigaddset(&sa.sa_mask, SIGCANCEL);
-       __libc_sigprocmask(SIG_UNBLOCK, &sa.sa_mask, 0);
+       sigemptyset(&set);
+       sigaddset(&set, SIGSYSCALL);
+       sigaddset(&set, SIGCANCEL);
+       __libc_sigprocmask(SIG_UNBLOCK, &set, 0);
 }
 
 static int start(void *p)
@@ -159,6 +134,9 @@ int pthread_create(pthread_t *res, const pthread_attr_t *attr, void *(*entry)(vo
 void pthread_exit(void *result)
 {
        struct pthread *self = pthread_self();
+       struct __ptcb cb = { .__next = self->cancelbuf };
        self->result = result;
-       docancel(self);
+       self->canceldisable = 1;
+       self->cancelasync = 0;
+       __pthread_unwind_next(&cb);
 }