diff options
50 files changed, 247 insertions, 227 deletions
diff --git a/arch/i386/bits/pthread.h b/arch/i386/bits/pthread.h index 7690ea39..c119dc8a 100644 --- a/arch/i386/bits/pthread.h +++ b/arch/i386/bits/pthread.h @@ -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 diff --git a/arch/i386/bits/syscall.h b/arch/i386/bits/syscall.h index 519e2dcd..274f205c 100644 --- a/arch/i386/bits/syscall.h +++ b/arch/i386/bits/syscall.h @@ -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 diff --git a/arch/i386/pthread_arch.h b/arch/i386/pthread_arch.h index 64d75cbc..b17dc87a 100644 --- a/arch/i386/pthread_arch.h +++ b/arch/i386/pthread_arch.h @@ -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 diff --git a/arch/x86_64/bits/syscall.h b/arch/x86_64/bits/syscall.h index d18edece..21d4c23a 100644 --- a/arch/x86_64/bits/syscall.h +++ b/arch/x86_64/bits/syscall.h @@ -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 diff --git a/arch/x86_64/pthread_arch.h b/arch/x86_64/pthread_arch.h index af7ae86e..c424493a 100644 --- a/arch/x86_64/pthread_arch.h +++ b/arch/x86_64/pthread_arch.h @@ -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 diff --git a/src/fcntl/fcntl.c b/src/fcntl/fcntl.c index ab0ebecf..2c9fb6f3 100644 --- a/src/fcntl/fcntl.c +++ b/src/fcntl/fcntl.c @@ -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); diff --git a/src/fcntl/open.c b/src/fcntl/open.c index 064d298c..31d6744c 100644 --- a/src/fcntl/open.c +++ b/src/fcntl/open.c @@ -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); diff --git a/src/fcntl/openat.c b/src/fcntl/openat.c index 1a2d9535..bdecb8c8 100644 --- a/src/fcntl/openat.c +++ b/src/fcntl/openat.c @@ -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); diff --git a/src/internal/libc.h b/src/internal/libc.h index c0039e77..3f1e55e5 100644 --- a/src/internal/libc.h +++ b/src/internal/libc.h @@ -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); diff --git a/src/internal/pthread_impl.h b/src/internal/pthread_impl.h index a6d90e9b..304bf98d 100644 --- a/src/internal/pthread_impl.h +++ b/src/internal/pthread_impl.h @@ -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); diff --git a/src/internal/syscall.h b/src/internal/syscall.h index 39efc42d..0c71eca6 100644 --- a/src/internal/syscall.h +++ b/src/internal/syscall.h @@ -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 diff --git a/src/ipc/msgrcv.c b/src/ipc/msgrcv.c index 13c282ee..ed4a448a 100644 --- a/src/ipc/msgrcv.c +++ b/src/ipc/msgrcv.c @@ -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; } diff --git a/src/ipc/msgsnd.c b/src/ipc/msgsnd.c index 1e0b2fa5..23f4a4cb 100644 --- a/src/ipc/msgsnd.c +++ b/src/ipc/msgsnd.c @@ -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; } diff --git a/src/network/accept.c b/src/network/accept.c index 46adff5c..f6b75ba4 100644 --- a/src/network/accept.c +++ b/src/network/accept.c @@ -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); } diff --git a/src/network/connect.c b/src/network/connect.c index 29bffbcb..57f01a1e 100644 --- a/src/network/connect.c +++ b/src/network/connect.c @@ -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); } diff --git a/src/network/recvfrom.c b/src/network/recvfrom.c index d5222932..035a15f8 100644 --- a/src/network/recvfrom.c +++ b/src/network/recvfrom.c @@ -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); } diff --git a/src/network/recvmsg.c b/src/network/recvmsg.c index 65094fc8..4f526659 100644 --- a/src/network/recvmsg.c +++ b/src/network/recvmsg.c @@ -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 diff --git a/src/network/sendmsg.c b/src/network/sendmsg.c index 047c0eff..164c28d7 100644 --- a/src/network/sendmsg.c +++ b/src/network/sendmsg.c @@ -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); } diff --git a/src/network/sendto.c b/src/network/sendto.c index 1cfc621d..899eecff 100644 --- a/src/network/sendto.c +++ b/src/network/sendto.c @@ -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); } diff --git a/src/process/waitid.c b/src/process/waitid.c index 4fa7c024..c67feac3 100644 --- a/src/process/waitid.c +++ b/src/process/waitid.c @@ -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); } diff --git a/src/process/waitpid.c b/src/process/waitpid.c index 5e0320f7..f75e31ef 100644 --- a/src/process/waitpid.c +++ b/src/process/waitpid.c @@ -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); } diff --git a/src/select/poll.c b/src/select/poll.c index caceebaf..f1e73e82 100644 --- a/src/select/poll.c +++ b/src/select/poll.c @@ -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); } diff --git a/src/select/pselect.c b/src/select/pselect.c index 155a6eb0..f28887ff 100644 --- a/src/select/pselect.c +++ b/src/select/pselect.c @@ -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); } diff --git a/src/select/select.c b/src/select/select.c index b38e7fd2..696cb288 100644 --- a/src/select/select.c +++ b/src/select/select.c @@ -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); } diff --git a/src/signal/sigsuspend.c b/src/signal/sigsuspend.c index cec5ddce..cd3a7b59 100644 --- a/src/signal/sigsuspend.c +++ b/src/signal/sigsuspend.c @@ -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); } diff --git a/src/signal/sigtimedwait.c b/src/signal/sigtimedwait.c index 1694cbe1..7eea58ab 100644 --- a/src/signal/sigtimedwait.c +++ b/src/signal/sigtimedwait.c @@ -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; } diff --git a/src/termios/tcdrain.c b/src/termios/tcdrain.c index 9ff1ecd5..6e43afb7 100644 --- a/src/termios/tcdrain.c +++ b/src/termios/tcdrain.c @@ -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); } diff --git a/src/thread/__timedwait.c b/src/thread/__timedwait.c index 5c84e80c..b1d3af23 100644 --- a/src/thread/__timedwait.c +++ b/src/thread/__timedwait.c @@ -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 index 00000000..c2890985 --- /dev/null +++ b/src/thread/__timedwait_cp.c @@ -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 index 00000000..a39117e7 --- /dev/null +++ b/src/thread/cancel_dummy.c @@ -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 index 00000000..5ce545d7 --- /dev/null +++ b/src/thread/cancel_impl.c @@ -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 index 00000000..6f98a779 --- /dev/null +++ b/src/thread/i386/syscall_cp.s @@ -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 index c497dbe6..00000000 --- a/src/thread/pthread_cancel.c +++ /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); -} diff --git a/src/thread/pthread_cond_timedwait.c b/src/thread/pthread_cond_timedwait.c index 7a19fc55..13728282 100644 --- a/src/thread/pthread_cond_timedwait.c +++ b/src/thread/pthread_cond_timedwait.c @@ -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; } diff --git a/src/thread/pthread_create.c b/src/thread/pthread_create.c index a722a2d6..844d7bf9 100644 --- a/src/thread/pthread_create.c +++ b/src/thread/pthread_create.c @@ -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); } diff --git a/src/thread/pthread_join.c b/src/thread/pthread_join.c index 5210ed48..ba7bb7d5 100644 --- a/src/thread/pthread_join.c +++ b/src/thread/pthread_join.c @@ -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; diff --git a/src/thread/pthread_testcancel.c b/src/thread/pthread_testcancel.c index 774b7068..c6b250b2 100644 --- a/src/thread/pthread_testcancel.c +++ b/src/thread/pthread_testcancel.c @@ -2,6 +2,5 @@ void pthread_testcancel() { - CANCELPT_BEGIN; - CANCELPT_END; + if (libc.testcancel) libc.testcancel(); } diff --git a/src/thread/sem_timedwait.c b/src/thread/sem_timedwait.c index 4f45c172..db05b417 100644 --- a/src/thread/sem_timedwait.c +++ b/src/thread/sem_timedwait.c @@ -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 index 00000000..e69de29b --- /dev/null +++ b/src/thread/syscall_cp.c diff --git a/src/thread/x86_64/syscall_cp.s b/src/thread/x86_64/syscall_cp.s new file mode 100644 index 00000000..1894ce19 --- /dev/null +++ b/src/thread/x86_64/syscall_cp.s @@ -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 diff --git a/src/time/clock_nanosleep.c b/src/time/clock_nanosleep.c index 4667725b..ec87b9e3 100644 --- a/src/time/clock_nanosleep.c +++ b/src/time/clock_nanosleep.c @@ -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); } diff --git a/src/time/nanosleep.c b/src/time/nanosleep.c index 0e0753f3..c8878b11 100644 --- a/src/time/nanosleep.c +++ b/src/time/nanosleep.c @@ -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); } diff --git a/src/unistd/close.c b/src/unistd/close.c index f52c0ef3..231f79ef 100644 --- a/src/unistd/close.c +++ b/src/unistd/close.c @@ -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; } diff --git a/src/unistd/pause.c b/src/unistd/pause.c index 57ed25e5..f7ed17d1 100644 --- a/src/unistd/pause.c +++ b/src/unistd/pause.c @@ -4,9 +4,5 @@ int pause(void) { - int r; - CANCELPT_BEGIN; - r = syscall(SYS_pause); - CANCELPT_END; - return r; + return syscall_cp(SYS_pause); } diff --git a/src/unistd/pread.c b/src/unistd/pread.c index 0a045013..1bf0c754 100644 --- a/src/unistd/pread.c +++ b/src/unistd/pread.c @@ -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); diff --git a/src/unistd/pwrite.c b/src/unistd/pwrite.c index f878bb63..224eacdd 100644 --- a/src/unistd/pwrite.c +++ b/src/unistd/pwrite.c @@ -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); diff --git a/src/unistd/read.c b/src/unistd/read.c index 194b389e..eb882fcc 100644 --- a/src/unistd/read.c +++ b/src/unistd/read.c @@ -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); } diff --git a/src/unistd/readv.c b/src/unistd/readv.c index 9b87728e..e45cb484 100644 --- a/src/unistd/readv.c +++ b/src/unistd/readv.c @@ -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); } diff --git a/src/unistd/write.c b/src/unistd/write.c index a8284b32..e2f7e1f2 100644 --- a/src/unistd/write.c +++ b/src/unistd/write.c @@ -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); } diff --git a/src/unistd/writev.c b/src/unistd/writev.c index a45afeb7..ef300ddf 100644 --- a/src/unistd/writev.c +++ b/src/unistd/writev.c @@ -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); } |