summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--arch/i386/bits/pthread.h6
-rw-r--r--arch/i386/bits/syscall.h4
-rw-r--r--arch/i386/pthread_arch.h4
-rw-r--r--arch/x86_64/bits/syscall.h3
-rw-r--r--arch/x86_64/pthread_arch.h4
-rw-r--r--src/fcntl/fcntl.c7
-rw-r--r--src/fcntl/open.c6
-rw-r--r--src/fcntl/openat.c6
-rw-r--r--src/internal/libc.h8
-rw-r--r--src/internal/pthread_impl.h4
-rw-r--r--src/internal/syscall.h14
-rw-r--r--src/ipc/msgrcv.c8
-rw-r--r--src/ipc/msgsnd.c8
-rw-r--r--src/network/accept.c6
-rw-r--r--src/network/connect.c6
-rw-r--r--src/network/recvfrom.c6
-rw-r--r--src/network/recvmsg.c4
-rw-r--r--src/network/sendmsg.c6
-rw-r--r--src/network/sendto.c6
-rw-r--r--src/process/waitid.c7
-rw-r--r--src/process/waitpid.c7
-rw-r--r--src/select/poll.c6
-rw-r--r--src/select/pselect.c7
-rw-r--r--src/select/select.c7
-rw-r--r--src/signal/sigsuspend.c7
-rw-r--r--src/signal/sigtimedwait.c8
-rw-r--r--src/termios/tcdrain.c8
-rw-r--r--src/thread/__timedwait.c2
-rw-r--r--src/thread/__timedwait_cp.c23
-rw-r--r--src/thread/cancel_dummy.c8
-rw-r--r--src/thread/cancel_impl.c70
-rw-r--r--src/thread/i386/syscall_cp.s36
-rw-r--r--src/thread/pthread_cancel.c7
-rw-r--r--src/thread/pthread_cond_timedwait.c11
-rw-r--r--src/thread/pthread_create.c48
-rw-r--r--src/thread/pthread_join.c4
-rw-r--r--src/thread/pthread_testcancel.c3
-rw-r--r--src/thread/sem_timedwait.c5
-rw-r--r--src/thread/syscall_cp.c0
-rw-r--r--src/thread/x86_64/syscall_cp.s24
-rw-r--r--src/time/clock_nanosleep.c6
-rw-r--r--src/time/nanosleep.c7
-rw-r--r--src/unistd/close.c5
-rw-r--r--src/unistd/pause.c6
-rw-r--r--src/unistd/pread.c6
-rw-r--r--src/unistd/pwrite.c6
-rw-r--r--src/unistd/read.c6
-rw-r--r--src/unistd/readv.c6
-rw-r--r--src/unistd/write.c6
-rw-r--r--src/unistd/writev.c6
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);
}