diff --git a/arch/i386/bits/pthread.h b/arch/i386/bits/pthread.h index 7690ea39b15c7d4d704b67bfee61d08b599264c6..c119dc8a9a4da8876bfa2b15fa7d8f11acbe8d33 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 519e2dcd2d8e953b6d649ed0684bd36965ebc855..274f205ccb81ef2c6b92edcf67be7e415b57397b 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 64d75cbcc201c8b08f4be1548c03b2287e178d1a..b17dc87abf302f647c4081bb3345034eb952be95 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 d18edece31a06b56403e195967f806abe764aaab..21d4c23a7f4805967bd1bfc9d82e7436c61d9851 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 af7ae86e2b72f726b81671f120a3cb3d2591add9..c424493a350dd7420dbf5845b2f9462b56774a9d 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 ab0ebecf32d06051aa5aa3245d920e3db70385ad..2c9fb6f37777961d305fa325d097cf84efeaa4d4 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 064d298c01bcd15cb461d6543282b9563b241f6f..31d6744c753ff125b90f8a0c38dd5db3249c7d44 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 1a2d95350fbe8f2c4bbd94e02a4068467038f364..bdecb8c8fcbbbf1d8258c5c0bab56b54297986fe 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 c0039e77913a0d79dd09a08e0bd9a729d96030f3..3f1e55e53ac5e4556c2becced197b75e8203f55b 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 a6d90e9bc184e92555fe507d9520c28cd86e1d4a..304bf98d4e5268637ab384ba0e818f337b1a7a16 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 39efc42de25cfdf45f7f9ba1164efd65340081da..0c71eca63606e191da234a7027978bff5e180a43 100644 --- a/src/internal/syscall.h +++ b/src/internal/syscall.h @@ -6,5 +6,19 @@ #include #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 13c282eeae8b016bfad13aca92a7dcb1f661fb97..ed4a448a7e5e4f2993f99649345b0850529f9563 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 1e0b2fa50dfc0e7cf52bdd2d3d9e4599d53a4023..23f4a4cbf58cc204343eb8fedb34f83bc2bd4de0 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 46adff5ce9cd254672a424574a0059378aca1bcb..f6b75ba4136e018812407c2f0b584e8fcebf50f8 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 29bffbcb639b9082f169e7cfc6212900c467c35d..57f01a1edbea3a8095091ad3a713591147e454e9 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 d5222932efff480e5644c3377bfd9ffe34d378ce..035a15f8a0711fdd096ef4ce95229e6608871d2e 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 65094fc8be4b9e08b95a5671f30bdaed6eca4cea..4f526659183defd2405ed6961b8ccca9e8ded1f5 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 047c0effa7cd25b9b37c29aa0bb3906212f5ffce..164c28d72a0e40e1b83d1ee6d423437e7d95236b 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 1cfc621d2796c64215a8d086bbbab7145262260c..899eecff57befa5a920d504e8fa01ef0db1b4835 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 4fa7c024df4f221a9e859e1b3b8b125f863c16c7..c67feac3836fcfa7487e11560f5990f5021a733c 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 5e0320f7b0bb9f2a935d61b73031425a92dddeee..f75e31ef24674df14252163f858aac6e6ddf8ed2 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 caceebaf08c819c2beae94d19416db78541dd3e9..f1e73e82f75d076f9c7cd32daed202a4f05908cf 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 155a6eb0382ce79a265c9ea10e33d6b89be5e91c..f28887ff25d143c8809554053eb1555496a2ff75 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 b38e7fd287ca3447a86396cc6cb6d0c3b6a9b421..696cb2880efcf1b2c0607f16cb424b203d6d5055 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 cec5ddce67cc966862a1c8602cea3b9528d37c6e..cd3a7b59a0d46b216e285ba0d11f7b0697f9719e 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 1694cbe13cc1e49e985e904e9c38a703639782a2..7eea58ab856b914366bc3a35945a7f8591ac6fd6 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 9ff1ecd5629537346c720e444a2f6ab2c37284e1..6e43afb7564001143ad096e85cb6ba2a93462262 100644 --- a/src/termios/tcdrain.c +++ b/src/termios/tcdrain.c @@ -1,13 +1,9 @@ #include #include #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 5c84e80c1ad7556fc0b94b3c46e4a0fa47e33f00..b1d3af2382fa36ba8715c0731c650873512caff6 100644 --- a/src/thread/__timedwait.c +++ b/src/thread/__timedwait.c @@ -2,7 +2,7 @@ #include #include "futex.h" #include "syscall.h" -#include + 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 0000000000000000000000000000000000000000..c2890985da8fd9b56223a35713946e277d011e5e --- /dev/null +++ b/src/thread/__timedwait_cp.c @@ -0,0 +1,23 @@ +#include +#include +#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 0000000000000000000000000000000000000000..a39117e75c289a4b43c73808265c179ee5751b93 --- /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 0000000000000000000000000000000000000000..5ce545d7597c0730d1420bb8a997e25e4c75aac0 --- /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 0000000000000000000000000000000000000000..6f98a779774889c893690830499fe5b174034bf4 --- /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 c497dbe667d101054158d1399854f2da8469a5cc..0000000000000000000000000000000000000000 --- 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 7a19fc5581f1ac0d72bf75409b71f4c060486aff..13728282df2313b8b4ae2f1b19cac0a6ec2c5861 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 a722a2d6fdbeb0a0e8c9f6e253cd10610c1987b9..844d7bf90e397b1f07b4afc4027b23ca9325cb13 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 5210ed4835b760769b3836e4ba0cf4fab03d9b0a..ba7bb7d54be15ca9ad911af060e2dd75f258abc1 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 774b70689978f0e351fa30b13976ccf227051f24..c6b250b2ccd6cb1af3a65587b21e229b92e055f8 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 4f45c17211bcd1d4da1142c73da44b10e4a7b518..db05b417ca3703c58cea5a5c64148f004b569720 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 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/src/thread/x86_64/syscall_cp.s b/src/thread/x86_64/syscall_cp.s new file mode 100644 index 0000000000000000000000000000000000000000..1894ce191c4dc7f9df3aaf2f9748537e86444343 --- /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 4667725b734874817912e4dafbdb78dbc99bd68a..ec87b9e33252c8f0a1cb9f04794c2365354f74db 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 0e0753f3a78a47ee1a6bd862c39e5123ebcef8f5..c8878b11c7184986d3053e4383cbd57e07e976bf 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 f52c0ef3a91736264a3c9ae0c06e3182ea44d7dc..231f79ef699cfdeedf72cc42505602d1a1ad7e2f 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 57ed25e5d302c08c4dbdcc815293b2e0b4620e9a..f7ed17d16f0fdc481d1bc6d3df37c72eeb82989d 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 0a0450130e892329c7d8f7c1677de3f4f094aee8..1bf0c754bd0cb8cd5a51ec1f06504138be5a28ac 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 f878bb63b80d7bd6d90d9c41ce8477a737a11e8f..224eacdd6df01c9ab9ebc0a7965ba20ddc12bf6d 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 194b389e860e5ee5b9b9487fa0467e76c23cc4bf..eb882fcc1bf62f5be3115ab2a67c9c78da58531a 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 9b87728e08bdb88bed07c13d5cd4453441edb861..e45cb484f09ae3d361824e160d75e3671fb5ae56 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 a8284b3216684c9ed8033b69ae0d73494729f535..e2f7e1f219ad3dedcebe4f1e1362848af72ad5dd 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 a45afeb757af56b1ac21c10e901bb47e656d65b4..ef300ddf81a2b107f28e96d448647b1d9463f368 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); }