overhaul pthread cancellation
authorRich Felker <dalias@aerifal.cx>
Sun, 17 Apr 2011 15:43:03 +0000 (11:43 -0400)
committerRich Felker <dalias@aerifal.cx>
Sun, 17 Apr 2011 15:43:03 +0000 (11:43 -0400)
this patch improves the correctness, simplicity, and size of
cancellation-related code. modulo any small errors, it should now be
completely conformant, safe, and resource-leak free.

the notion of entering and exiting cancellation-point context has been
completely eliminated and replaced with alternative syscall assembly
code for cancellable syscalls. the assembly is responsible for setting
up execution context information (stack pointer and address of the
syscall instruction) which the cancellation signal handler can use to
determine whether the interrupted code was in a cancellable state.

these changes eliminate race conditions in the previous generation of
cancellation handling code (whereby a cancellation request received
just prior to the syscall would not be processed, leaving the syscall
to block, potentially indefinitely), and remedy an issue where
non-cancellable syscalls made from signal handlers became cancellable
if the signal handler interrupted a cancellation point.

x86_64 asm is untested and may need a second try to get it right.

50 files changed:
arch/i386/bits/pthread.h
arch/i386/bits/syscall.h
arch/i386/pthread_arch.h
arch/x86_64/bits/syscall.h
arch/x86_64/pthread_arch.h
src/fcntl/fcntl.c
src/fcntl/open.c
src/fcntl/openat.c
src/internal/libc.h
src/internal/pthread_impl.h
src/internal/syscall.h
src/ipc/msgrcv.c
src/ipc/msgsnd.c
src/network/accept.c
src/network/connect.c
src/network/recvfrom.c
src/network/recvmsg.c
src/network/sendmsg.c
src/network/sendto.c
src/process/waitid.c
src/process/waitpid.c
src/select/poll.c
src/select/pselect.c
src/select/select.c
src/signal/sigsuspend.c
src/signal/sigtimedwait.c
src/termios/tcdrain.c
src/thread/__timedwait.c
src/thread/__timedwait_cp.c [new file with mode: 0644]
src/thread/cancel_dummy.c [new file with mode: 0644]
src/thread/cancel_impl.c [new file with mode: 0644]
src/thread/i386/syscall_cp.s [new file with mode: 0644]
src/thread/pthread_cancel.c [deleted file]
src/thread/pthread_cond_timedwait.c
src/thread/pthread_create.c
src/thread/pthread_join.c
src/thread/pthread_testcancel.c
src/thread/sem_timedwait.c
src/thread/syscall_cp.c [new file with mode: 0644]
src/thread/x86_64/syscall_cp.s [new file with mode: 0644]
src/time/clock_nanosleep.c
src/time/nanosleep.c
src/unistd/close.c
src/unistd/pause.c
src/unistd/pread.c
src/unistd/pwrite.c
src/unistd/read.c
src/unistd/readv.c
src/unistd/write.c
src/unistd/writev.c

index 7690ea3..c119dc8 100644 (file)
@@ -7,17 +7,17 @@ struct __ptcb {
 
 static inline void __pthread_register_cancel_2(struct __ptcb *__cb)
 {
-       __asm__ __volatile__( "call __pthread_register_cancel" : : "a"(__cb) );
+       __asm__ __volatile__( "call __pthread_register_cancel" : : "a"(__cb) : "ecx", "edx", "memory" );
 }
 
 static inline void __pthread_unregister_cancel_2(struct __ptcb *__cb)
 {
-       __asm__ __volatile__( "call __pthread_unregister_cancel" : : "a"(__cb) );
+       __asm__ __volatile__( "call __pthread_unregister_cancel" : : "a"(__cb) : "ecx", "edx", "memory" );
 }
 
 static inline void __pthread_unwind_next_2(struct __ptcb *__cb)
 {
-       __asm__ __volatile__( "call __pthread_unwind_next" : : "a"(__cb) );
+       __asm__ __volatile__( "call __pthread_unwind_next" : : "a"(__cb) : "ecx", "edx", "memory" );
 }
 
 #define __pthread_register_cancel __pthread_register_cancel_2
index 519e2dc..274f205 100644 (file)
@@ -122,7 +122,9 @@ static inline long __syscall6(long __n, long __a1, long __a2, long __a3, long __
 #define __SC_sendmsg     16
 #define __SC_recvmsg     17
 
-#define __socketcall(nm, a, b, c, d, e, f) syscall(SYS_socketcall, __SC_##nm, \
+#define __socketcall(nm,a,b,c,d,e,f) syscall(SYS_socketcall, __SC_##nm, \
+    ((long [6]){ (long)a, (long)b, (long)c, (long)d, (long)e, (long)f }))
+#define __socketcall_cp(nm,a,b,c,d,e,f) syscall_cp(SYS_socketcall, __SC_##nm, \
     ((long [6]){ (long)a, (long)b, (long)c, (long)d, (long)e, (long)f }))
 
 #define __NR_restart_syscall      0
index 64d75cb..b17dc87 100644 (file)
@@ -5,5 +5,5 @@ static inline struct pthread *__pthread_self()
        return self;
 }
 
-#define PC_AT_SYS(c) \
-       (*(uint16_t *)(((ucontext_t *)(c))->uc_mcontext.__gregs[14])==0x80cd)
+#define CANCEL_REG_SP 7
+#define CANCEL_REG_IP 14
index d18edec..21d4c23 100644 (file)
@@ -60,7 +60,8 @@ static inline long __syscall6(long __n, long __a1, long __a2, long __a3, long __
        return __ret;
 }
 
-#define __socketcall(nm, a, b, c, d, e, f) syscall(__NR_##nm, a, b, c, d, e, f)
+#define __socketcall(nm,a,b,c,d,e,f) syscall(__NR_##nm, a, b, c, d, e, f)
+#define __socketcall_cp(nm,a,b,c,d,e,f) syscall_cp(__NR_##nm, a, b, c, d, e, f)
 
 #define __NR_read                              0
 #define __NR_write                             1
index af7ae86..c424493 100644 (file)
@@ -5,5 +5,5 @@ static inline struct pthread *__pthread_self()
        return self;
 }
 
-#define PC_AT_SYS(c) \
-       (*(uint16_t *)(((ucontext_t *)(c))->uc_mcontext.__gregs[16])==0x050f)
+#define CANCEL_REG_SP 15
+#define CANCEL_REG_IP 16
index ab0ebec..2c9fb6f 100644 (file)
@@ -6,17 +6,14 @@
 
 int fcntl(int fd, int cmd, ...)
 {
-       int r;
        long arg;
        va_list ap;
        va_start(ap, cmd);
        arg = va_arg(ap, long);
        va_end(ap);
        if (cmd == F_SETFL) arg |= O_LARGEFILE;
-       if (cmd == F_SETLKW) CANCELPT_BEGIN;
-       r = syscall(SYS_fcntl, fd, cmd, arg);
-       if (cmd == F_SETLKW) CANCELPT_END;
-       return r;
+       if (cmd == F_SETLKW) return syscall_cp(SYS_fcntl, fd, cmd, arg);
+       return syscall(SYS_fcntl, fd, cmd, arg);
 }
 
 LFS64(fcntl);
index 064d298..31d6744 100644 (file)
@@ -6,16 +6,12 @@
 
 int open(const char *filename, int flags, ...)
 {
-       int r;
        mode_t mode;
        va_list ap;
        va_start(ap, flags);
        mode = va_arg(ap, mode_t);
        va_end(ap);
-       CANCELPT_BEGIN;
-       r = syscall(SYS_open, filename, flags|O_LARGEFILE, mode);
-       CANCELPT_END;
-       return r;
+       return syscall_cp(SYS_open, filename, flags|O_LARGEFILE, mode);
 }
 
 LFS64(open);
index 1a2d953..bdecb8c 100644 (file)
@@ -6,16 +6,12 @@
 
 int openat(int fd, const char *filename, int flags, ...)
 {
-       int r;
        mode_t mode;
        va_list ap;
        va_start(ap, flags);
        mode = va_arg(ap, mode_t);
        va_end(ap);
-       CANCELPT_BEGIN;
-       r = syscall(SYS_openat, fd, filename, flags|O_LARGEFILE, mode);
-       CANCELPT_END;
-       return r;
+       return syscall_cp(SYS_openat, fd, filename, flags|O_LARGEFILE, mode);
 }
 
 LFS64(openat);
index c0039e7..3f1e55e 100644 (file)
@@ -6,7 +6,7 @@
 
 struct __libc {
        int *(*errno_location)(void);
-       void (*cancelpt)(int);
+       void (*testcancel)(void);
        void (*lock)(volatile int *);
        void (*lockfile)(FILE *);
        void (*fork_handler)(int);
@@ -40,12 +40,6 @@ void __lock(volatile int *);
 void __lockfile(FILE *);
 #define LOCK(x) (libc.threads_minus_1 ? (__lock(x),1) : ((void)(x),1))
 #define UNLOCK(x) (*(x)=0)
-#define CANCELPT(x) (libc.cancelpt ? libc.cancelpt((x)),0 : (void)(x),0)
-#define CANCELPT_BEGIN CANCELPT(1)
-#define CANCELPT_TRY CANCELPT(0)
-#define CANCELPT_END CANCELPT(-1)
-#define CANCELPT_INHIBIT CANCELPT(2)
-#define CANCELPT_RESUME CANCELPT(-2)
 
 int __rsyscall(int, long, long, long, long, long, long);
 
index a6d90e9..304bf98 100644 (file)
@@ -24,7 +24,8 @@ struct pthread {
        unsigned long tlsdesc[4];
        pid_t tid, pid;
        int tsd_used, errno_val, *errno_ptr;
-       volatile int canceldisable, cancelasync, cancelpoint, cancel;
+       volatile uintptr_t cp_sp, cp_ip;
+       volatile int cancel, canceldisable, cancelasync;
        unsigned char *map_base;
        size_t map_size;
        void *start_arg;
@@ -85,6 +86,7 @@ void __lock(volatile int *);
 void __unmapself(void *, size_t);
 
 int __timedwait(volatile int *, int, clockid_t, const struct timespec *, int);
+int __timedwait_cp(volatile int *, int, clockid_t, const struct timespec *, int);
 void __wait(volatile int *, volatile int *, int, int);
 void __wake(volatile int *, int, int);
 
index 39efc42..0c71eca 100644 (file)
@@ -6,5 +6,19 @@
 #include <sys/syscall.h>
 
 #define socketcall __socketcall
+#define socketcall_cp __socketcall_cp
+
+#define __syscall_cp0(n) __syscall_cp(n,0,0,0,0,0,0)
+#define __syscall_cp1(n,a) __syscall_cp(n,(long)(a),0,0,0,0,0)
+#define __syscall_cp2(n,a,b) __syscall_cp(n,(long)(a),(long)(b),0,0,0,0)
+#define __syscall_cp3(n,a,b,c) __syscall_cp(n,(long)(a),(long)(b),(long)(c),0,0,0)
+#define __syscall_cp4(n,a,b,c,d) __syscall_cp(n,(long)(a),(long)(b),(long)(c),(long)(d),0,0)
+#define __syscall_cp5(n,a,b,c,d,e) __syscall_cp(n,(long)(a),(long)(b),(long)(c),(long)(d),(long)(e),0)
+#define __syscall_cp6(n,a,b,c,d,e,f) __syscall_cp(n,(long)(a),(long)(b),(long)(c),(long)(d),(long)(e),(long)(f))
+
+long (__syscall_cp)(long, long, long, long, long, long, long);
+
+#define __syscall_cp(...) __SYSCALL_DISP(__syscall_cp,__VA_ARGS__)
+#define syscall_cp(...) __syscall_ret(__syscall_cp(__VA_ARGS__))
 
 #endif
index 13c282e..ed4a448 100644 (file)
@@ -5,13 +5,9 @@
 
 ssize_t msgrcv(int q, void *m, size_t len, long type, int flag)
 {
-       ssize_t r;
-       CANCELPT_BEGIN;
 #ifdef SYS_msgrcv
-       r = syscall(SYS_msgrcv, q, m, len, type, flag);
+       return syscall_cp(SYS_msgrcv, q, m, len, type, flag);
 #else
-       r = syscall(SYS_ipc, IPCOP_msgrcv, q, len, flag, ((long[]){ (long)m, type }));
+       return syscall_cp(SYS_ipc, IPCOP_msgrcv, q, len, flag, ((long[]){ (long)m, type }));
 #endif
-       CANCELPT_END;
-       return r;
 }
index 1e0b2fa..23f4a4c 100644 (file)
@@ -5,13 +5,9 @@
 
 int msgsnd(int q, const void *m, size_t len, int flag)
 {
-       ssize_t r;
-       CANCELPT_BEGIN;
 #ifdef SYS_msgsnd
-       r = syscall(SYS_msgsnd, q, m, len, flag);
+       return syscall_cp(SYS_msgsnd, q, m, len, flag);
 #else
-       r = syscall(SYS_ipc, IPCOP_msgsnd, q, len, flag, m);
+       return syscall_cp(SYS_ipc, IPCOP_msgsnd, q, len, flag, m);
 #endif
-       CANCELPT_END;
-       return r;
 }
index 46adff5..f6b75ba 100644 (file)
@@ -4,9 +4,5 @@
 
 int accept(int fd, struct sockaddr *addr, socklen_t *len)
 {
-       int ret;
-       CANCELPT_BEGIN;
-       ret = socketcall(accept, fd, addr, len, 0, 0, 0);
-       CANCELPT_END;
-       return ret;
+       return socketcall_cp(accept, fd, addr, len, 0, 0, 0);
 }
index 29bffbc..57f01a1 100644 (file)
@@ -4,9 +4,5 @@
 
 int connect(int fd, const struct sockaddr *addr, socklen_t len)
 {
-       int ret;
-       CANCELPT_BEGIN;
-       ret = socketcall(connect, fd, addr, len, 0, 0, 0);
-       CANCELPT_END;
-       return ret;
+       return socketcall_cp(connect, fd, addr, len, 0, 0, 0);
 }
index d522293..035a15f 100644 (file)
@@ -4,9 +4,5 @@
 
 ssize_t recvfrom(int fd, void *buf, size_t len, int flags, struct sockaddr *addr, socklen_t *alen)
 {
-       ssize_t r;
-       CANCELPT_BEGIN;
-       r = socketcall(recvfrom, fd, buf, len, flags, addr, alen);
-       CANCELPT_END;
-       return r;
+       return socketcall_cp(recvfrom, fd, buf, len, flags, addr, alen);
 }
index 65094fc..4f52665 100644 (file)
@@ -14,9 +14,7 @@ ssize_t recvmsg(int fd, struct msghdr *msg, int flags)
                msg = &h;
        }
 #endif
-       CANCELPT_BEGIN;
-       r = socketcall(recvmsg, fd, msg, flags, 0, 0, 0);
-       CANCELPT_END;
+       r = socketcall_cp(recvmsg, fd, msg, flags, 0, 0, 0);
 #if LONG_MAX > INT_MAX
        if (orig) *orig = h;
 #endif
index 047c0ef..164c28d 100644 (file)
@@ -5,7 +5,6 @@
 
 ssize_t sendmsg(int fd, const struct msghdr *msg, int flags)
 {
-       ssize_t r;
 #if LONG_MAX > INT_MAX
        struct msghdr h;
        if (msg) {
@@ -14,8 +13,5 @@ ssize_t sendmsg(int fd, const struct msghdr *msg, int flags)
                msg = &h;
        }
 #endif
-       CANCELPT_BEGIN;
-       r = socketcall(sendmsg, fd, msg, flags, 0, 0, 0);
-       CANCELPT_END;
-       return r;
+       return socketcall_cp(sendmsg, fd, msg, flags, 0, 0, 0);
 }
index 1cfc621..899eecf 100644 (file)
@@ -4,9 +4,5 @@
 
 ssize_t sendto(int fd, const void *buf, size_t len, int flags, const struct sockaddr *addr, socklen_t alen)
 {
-       ssize_t r;
-       CANCELPT_BEGIN;
-       r = socketcall(sendto, fd, buf, len, flags, addr, alen);
-       CANCELPT_END;
-       return r;
+       return socketcall_cp(sendto, fd, buf, len, flags, addr, alen);
 }
index 4fa7c02..c67feac 100644 (file)
@@ -4,10 +4,5 @@
 
 int waitid(idtype_t type, id_t id, siginfo_t *info, int options)
 {
-       int r;
-       CANCELPT_BEGIN;
-       r = syscall(SYS_waitid, type, id, info, options, 0);
-       if (r<0) CANCELPT_TRY;
-       CANCELPT_END;
-       return r;
+       return syscall_cp(SYS_waitid, type, id, info, options, 0);
 }
index 5e0320f..f75e31e 100644 (file)
@@ -4,10 +4,5 @@
 
 pid_t waitpid(pid_t pid, int *status, int options)
 {
-       int r;
-       CANCELPT_BEGIN;
-       r = syscall(SYS_wait4, pid, status, options, 0);
-       if (r<0) CANCELPT_TRY;
-       CANCELPT_END;
-       return r;
+       return syscall_cp(SYS_wait4, pid, status, options, 0);
 }
index caceeba..f1e73e8 100644 (file)
@@ -4,9 +4,5 @@
 
 int poll(struct pollfd *fds, nfds_t n, int timeout)
 {
-       int r;
-       CANCELPT_BEGIN;
-       r = syscall(SYS_poll, fds, n, timeout);
-       CANCELPT_END;
-       return r;
+       return syscall_cp(SYS_poll, fds, n, timeout);
 }
index 155a6eb..f28887f 100644 (file)
@@ -4,13 +4,8 @@
 
 int pselect(int n, fd_set *rfds, fd_set *wfds, fd_set *efds, const struct timespec *ts, const sigset_t *mask)
 {
-       int r;
        long data[2] = { (long)mask, 8 };
        struct timespec ts_tmp;
        if (ts) ts_tmp = *ts;
-       CANCELPT_BEGIN;
-       r = syscall(SYS_pselect6, n, rfds, wfds, efds, ts ? &ts_tmp : 0, data);
-       CANCELPT_TRY;
-       CANCELPT_END;
-       return r;
+       return syscall_cp(SYS_pselect6, n, rfds, wfds, efds, ts ? &ts_tmp : 0, data);
 }
index b38e7fd..696cb28 100644 (file)
@@ -4,10 +4,5 @@
 
 int select(int n, fd_set *rfds, fd_set *wfds, fd_set *efds, struct timeval *tv)
 {
-       int r;
-       CANCELPT_BEGIN;
-       r = syscall(SYS_select, n, rfds, wfds, efds, tv);
-       CANCELPT_TRY;
-       CANCELPT_END;
-       return r;
+       return syscall_cp(SYS_select, n, rfds, wfds, efds, tv);
 }
index cec5ddc..cd3a7b5 100644 (file)
@@ -4,10 +4,5 @@
 
 int sigsuspend(const sigset_t *mask)
 {
-       int ret;
-       CANCELPT_BEGIN;
-       ret = syscall(SYS_rt_sigsuspend, mask, 8);
-       if (ret<0) CANCELPT_TRY;
-       CANCELPT_END;
-       return ret;
+       return syscall_cp(SYS_rt_sigsuspend, mask, 8);
 }
index 1694cbe..7eea58a 100644 (file)
@@ -6,11 +6,7 @@
 int sigtimedwait(const sigset_t *mask, siginfo_t *si, const struct timespec *timeout)
 {
        int ret;
-       CANCELPT_BEGIN;
-       do {
-               ret = syscall(SYS_rt_sigtimedwait, mask, si, timeout, 8);
-               if (ret<0) CANCELPT_TRY;
-       } while (ret<0 && errno==EINTR);
-       CANCELPT_END;
+       do ret = syscall_cp(SYS_rt_sigtimedwait, mask, si, timeout, 8);
+       while (ret<0 && errno==EINTR);
        return ret;
 }
index 9ff1ecd..6e43afb 100644 (file)
@@ -1,13 +1,9 @@
 #include <termios.h>
 #include <sys/ioctl.h>
 #include "libc.h"
+#include "syscall.h"
 
 int tcdrain(int fd)
 {
-       int ret;
-       CANCELPT_BEGIN;
-       ret = ioctl(fd, TCSBRK, 1);
-       CANCELPT_TRY;
-       CANCELPT_END;
-       return ret;
+       return syscall_cp(SYS_ioctl, fd, TCSBRK, 1);
 }
index 5c84e80..b1d3af2 100644 (file)
@@ -2,7 +2,7 @@
 #include <errno.h>
 #include "futex.h"
 #include "syscall.h"
-#include <stdio.h>
+
 int __timedwait(volatile int *addr, int val, clockid_t clk, const struct timespec *at, int priv)
 {
        int r;
diff --git a/src/thread/__timedwait_cp.c b/src/thread/__timedwait_cp.c
new file mode 100644 (file)
index 0000000..c289098
--- /dev/null
@@ -0,0 +1,23 @@
+#include <time.h>
+#include <errno.h>
+#include "futex.h"
+#include "syscall.h"
+
+int __timedwait_cp(volatile int *addr, int val, clockid_t clk, const struct timespec *at, int priv)
+{
+       int r;
+       struct timespec to;
+       if (at) {
+               clock_gettime(clk, &to);
+               to.tv_sec = at->tv_sec - to.tv_sec;
+               if ((to.tv_nsec = at->tv_nsec - to.tv_nsec) < 0) {
+                       to.tv_sec--;
+                       to.tv_nsec += 1000000000;
+               }
+               if (to.tv_sec < 0) return ETIMEDOUT;
+       }
+       if (priv) priv = 128; priv=0;
+       r = -__syscall_cp(SYS_futex, (long)addr, FUTEX_WAIT | priv, val, at ? (long)&to : 0);
+       if (r == ETIMEDOUT || r == EINTR) return r;
+       return 0;
+}
diff --git a/src/thread/cancel_dummy.c b/src/thread/cancel_dummy.c
new file mode 100644 (file)
index 0000000..a39117e
--- /dev/null
@@ -0,0 +1,8 @@
+#include "pthread_impl.h"
+
+static long sccp(long nr, long u, long v, long w, long x, long y, long z)
+{
+       return (__syscall)(nr, u, v, w, x, y, z);
+}
+
+weak_alias(sccp, __syscall_cp);
diff --git a/src/thread/cancel_impl.c b/src/thread/cancel_impl.c
new file mode 100644 (file)
index 0000000..5ce545d
--- /dev/null
@@ -0,0 +1,70 @@
+#include "pthread_impl.h"
+
+long __syscall_cp_asm(volatile void *, long, long, long, long, long, long, long);
+
+long (__syscall_cp)(long nr, long u, long v, long w, long x, long y, long z)
+{
+       pthread_t self;
+       uintptr_t old_sp, old_ip;
+       long r;
+
+       if (!libc.lock || (self = __pthread_self())->canceldisable)
+               return __syscall(nr, u, v, w, x, y, z);
+
+       old_sp = self->cp_sp;
+       old_ip = self->cp_ip;
+       self->cp_sp = 0;
+       self->cp_ip = 0;
+       r = __syscall_cp_asm(&self->cp_sp, nr, u, v, w, x, y, z);
+       self->cp_sp = old_sp;
+       self->cp_ip = old_ip;
+       if (r == -EINTR && self->cancel) pthread_exit(PTHREAD_CANCELED);
+       return r;
+}
+
+static void cancel_handler(int sig, siginfo_t *si, void *ctx)
+{
+       pthread_t self = __pthread_self();
+       ucontext_t *uc = ctx;
+       uintptr_t sp = ((uintptr_t *)&uc->uc_mcontext)[CANCEL_REG_SP];
+       uintptr_t ip = ((uintptr_t *)&uc->uc_mcontext)[CANCEL_REG_IP];
+
+       if (!self->cancel || self->canceldisable) return;
+
+       if (self->cancelasync) pthread_exit(PTHREAD_CANCELED);
+
+       if (sp != self->cp_sp) {
+               if (!sp) return;
+               sigaddset(&uc->uc_sigmask, SIGCANCEL);
+               __syscall(SYS_tgkill, self->pid, self->tid, SIGCANCEL);
+               return;
+       }
+
+       if (ip <= self->cp_ip) pthread_exit(PTHREAD_CANCELED);
+}
+
+static void testcancel()
+{
+       pthread_t self = __pthread_self();
+       if (self->cancel && !self->canceldisable)
+               pthread_exit(PTHREAD_CANCELED);
+}
+
+static void init_cancellation()
+{
+       struct sigaction sa = {
+               .sa_flags = SA_SIGINFO | SA_RESTART,
+               .sa_sigaction = cancel_handler
+       };
+       sigfillset(&sa.sa_mask);
+       __libc_sigaction(SIGCANCEL, &sa, 0);
+       libc.testcancel = testcancel;
+}
+
+int pthread_cancel(pthread_t t)
+{
+       static pthread_once_t once;
+       pthread_once(&once, init_cancellation);
+       a_store(&t->cancel, 1);
+       return pthread_kill(t, SIGCANCEL);
+}
diff --git a/src/thread/i386/syscall_cp.s b/src/thread/i386/syscall_cp.s
new file mode 100644 (file)
index 0000000..6f98a77
--- /dev/null
@@ -0,0 +1,36 @@
+.text
+.global __syscall_cp_asm
+.type   __syscall_cp_asm,%function
+__syscall_cp_asm:
+       pushl %ebx
+       pushl %esi
+       pushl %edi
+       pushl %ebp
+       leal 20(%esp),%ebp
+       call 1f
+1:     popl %eax
+       movl (%ebp),%ecx
+       addl $[1f-1b],%eax
+       movl %eax,4(%ecx)
+       movl %esp,(%ecx)
+       movl 8(%ecx),%eax
+       testl %eax,%eax
+       jnz 2f
+       movl 4(%ebp),%eax
+       movl 8(%ebp),%ebx
+       movl 12(%ebp),%ecx
+       movl 16(%ebp),%edx
+       movl 20(%ebp),%esi
+       movl 24(%ebp),%edi
+       movl 28(%ebp),%ebp
+1:     int $128
+       popl %ebp
+       popl %edi
+       popl %esi
+       popl %ebx
+       ret
+2:     xorl %eax,%eax
+       movl %eax,4(%ecx)
+       movl %eax,(%ecx)
+       pushl $-1
+       call pthread_exit
diff --git a/src/thread/pthread_cancel.c b/src/thread/pthread_cancel.c
deleted file mode 100644 (file)
index c497dbe..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-#include "pthread_impl.h"
-
-int pthread_cancel(pthread_t t)
-{
-       a_store(&t->cancel, 1);
-       return pthread_kill(t, SIGCANCEL);
-}
index 7a19fc5..1372828 100644 (file)
@@ -8,22 +8,19 @@ static void relock(void *m)
 int pthread_cond_timedwait(pthread_cond_t *c, pthread_mutex_t *m, const struct timespec *ts)
 {
        int r, e=0;
-       CANCELPT_BEGIN;
-       CANCELPT_END;
+
+       pthread_testcancel();
 
        pthread_cleanup_push(relock, m);
        c->_c_block = 1;
        if ((r=pthread_mutex_unlock(m))) return r;
 
-       CANCELPT_BEGIN;
-       do e = __timedwait(&c->_c_block, 1, c->_c_clock, ts, 0);
+       do e = __timedwait_cp(&c->_c_block, 1, c->_c_clock, ts, 0);
        while (e == EINTR);
-       CANCELPT_END;
 
        pthread_cleanup_pop(0);
        if ((r=pthread_mutex_lock(m))) return r;
 
-       CANCELPT_BEGIN;
-       CANCELPT_END;
+       pthread_testcancel();
        return e;
 }
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);
 }
index 5210ed4..ba7bb7d 100644 (file)
@@ -3,9 +3,7 @@
 int pthread_join(pthread_t t, void **res)
 {
        int tmp = t->tid;
-       CANCELPT_BEGIN;
-       if (tmp) __wait(&t->tid, 0, tmp, 1);
-       CANCELPT_END;
+       if (tmp) __timedwait_cp(&t->tid, tmp, 0, 0, 1);
        if (res) *res = t->result;
        if (t->map_base) munmap(t->map_base, t->map_size);
        return 0;
index 774b706..c6b250b 100644 (file)
@@ -2,6 +2,5 @@
 
 void pthread_testcancel()
 {
-       CANCELPT_BEGIN;
-       CANCELPT_END;
+       if (libc.testcancel) libc.testcancel();
 }
index 4f45c17..db05b41 100644 (file)
@@ -21,19 +21,16 @@ int sem_timedwait(sem_t *sem, const struct timespec *at)
        a_inc(sem->__val+1);
        pthread_cleanup_push(cleanup, sem->__val+1)
 
-       CANCELPT_BEGIN;
        for (;;) {
                r = 0;
                if (!sem_trywait(sem)) break;
-               r = __timedwait(sem->__val, 0, CLOCK_REALTIME, at, 0);
+               r = __timedwait_cp(sem->__val, 0, CLOCK_REALTIME, at, 0);
                if (r) {
                        errno = r;
                        r = -1;
                        break;
                }
-               CANCELPT_TRY;
        }
-       CANCELPT_END;
 
        pthread_cleanup_pop(1);
 
diff --git a/src/thread/syscall_cp.c b/src/thread/syscall_cp.c
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/src/thread/x86_64/syscall_cp.s b/src/thread/x86_64/syscall_cp.s
new file mode 100644 (file)
index 0000000..1894ce1
--- /dev/null
@@ -0,0 +1,24 @@
+.text
+.global __syscall_cp_asm
+.type   __syscall_cp_asm,%function
+__syscall_cp_asm:
+       lea 1f(%rip),%rax
+       mov %rax,8(%rdi)
+       mov %rsp,(%rdi)
+       mov 16(%rdi),%eax
+       test %eax,%eax
+       jnz 2f
+       mov %rsi,%rax
+       mov %rdx,%rdi
+       mov %rcx,%rsi
+       mov %r8,%rdx
+       mov %r9,%r10
+       mov 8(%rsp),%r8
+       mov 16(%rsp),%r9
+1:     syscall
+       ret
+2:     xor %edi,%edi
+       mov %rdi,8(%r10)
+       mov %rdi,(%r10)
+       dec %rdi
+       jmp pthread_exit
index 4667725..ec87b9e 100644 (file)
@@ -4,9 +4,5 @@
 
 int clock_nanosleep(clockid_t clk, int flags, const struct timespec *req, struct timespec *rem)
 {
-       int ret;
-       CANCELPT_BEGIN;
-       ret = -__syscall(SYS_clock_nanosleep, clk, flags, req, rem);
-       CANCELPT_END;
-       return ret;
+       return -__syscall_cp(SYS_clock_nanosleep, clk, flags, req, rem);
 }
index 0e0753f..c8878b1 100644 (file)
@@ -5,10 +5,5 @@
 
 int nanosleep(const struct timespec *req, struct timespec *rem)
 {
-       int ret;
-       CANCELPT_BEGIN;
-       ret = syscall(SYS_nanosleep, req, rem);
-       CANCELPT_TRY;
-       CANCELPT_END;
-       return ret;
+       return syscall_cp(SYS_nanosleep, req, rem);
 }
index f52c0ef..231f79e 100644 (file)
@@ -4,8 +4,7 @@
 
 int close(int fd)
 {
-       int ret = syscall(SYS_close, fd);
-       CANCELPT_BEGIN;
-       CANCELPT_END;
+       int ret = syscall_cp(SYS_close, fd);
+       if (libc.testcancel) libc.testcancel();
        return ret;
 }
index 57ed25e..f7ed17d 100644 (file)
@@ -4,9 +4,5 @@
 
 int pause(void)
 {
-       int r;
-       CANCELPT_BEGIN;
-       r = syscall(SYS_pause);
-       CANCELPT_END;
-       return r;
+       return syscall_cp(SYS_pause);
 }
index 0a04501..1bf0c75 100644 (file)
@@ -4,11 +4,7 @@
 
 ssize_t pread(int fd, void *buf, size_t size, off_t ofs)
 {
-       ssize_t r;
-       CANCELPT_BEGIN;
-       r = syscall(SYS_pread, fd, buf, size, __SYSCALL_LL(ofs));
-       CANCELPT_END;
-       return r;
+       return syscall_cp(SYS_pread, fd, buf, size, __SYSCALL_LL(ofs));
 }
 
 LFS64(pread);
index f878bb6..224eacd 100644 (file)
@@ -4,11 +4,7 @@
 
 ssize_t pwrite(int fd, const void *buf, size_t size, off_t ofs)
 {
-       ssize_t r;
-       CANCELPT_BEGIN;
-       r = syscall(SYS_pwrite, fd, buf, size, __SYSCALL_LL(ofs));
-       CANCELPT_END;
-       return r;
+       return syscall_cp(SYS_pwrite, fd, buf, size, __SYSCALL_LL(ofs));
 }
 
 LFS64(pwrite);
index 194b389..eb882fc 100644 (file)
@@ -4,9 +4,5 @@
 
 ssize_t read(int fd, void *buf, size_t count)
 {
-       ssize_t r;
-       CANCELPT_BEGIN;
-       r = syscall(SYS_read, fd, buf, count);
-       CANCELPT_END;
-       return r;
+       return syscall_cp(SYS_read, fd, buf, count);
 }
index 9b87728..e45cb48 100644 (file)
@@ -4,9 +4,5 @@
 
 ssize_t readv(int fd, const struct iovec *iov, int count)
 {
-       ssize_t r;
-       CANCELPT_BEGIN;
-       r = syscall(SYS_readv, fd, iov, count);
-       CANCELPT_END;
-       return r;
+       return syscall_cp(SYS_readv, fd, iov, count);
 }
index a8284b3..e2f7e1f 100644 (file)
@@ -4,9 +4,5 @@
 
 ssize_t write(int fd, const void *buf, size_t count)
 {
-       int r;
-       CANCELPT_BEGIN;
-       r = syscall(SYS_write, fd, buf, count);
-       CANCELPT_END;
-       return r;
+       return syscall_cp(SYS_write, fd, buf, count);
 }
index a45afeb..ef300dd 100644 (file)
@@ -4,9 +4,5 @@
 
 ssize_t writev(int fd, const struct iovec *iov, int count)
 {
-       ssize_t r;
-       CANCELPT_BEGIN;
-       r = syscall(SYS_writev, fd, iov, count);
-       CANCELPT_END;
-       return r;
+       return syscall_cp(SYS_writev, fd, iov, count);
 }