overhaul pthread cancellation

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.
This commit is contained in:
Rich Felker
2011-04-17 11:43:03 -04:00
parent 90f09a0dde
commit feee98903c
50 changed files with 247 additions and 227 deletions

View 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

View 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

View 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

View 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

View 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

View 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);

View 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);

View 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);

View 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);

View 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);

View 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

View 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;
}

View 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;
}

View 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);
}

View 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);
}

View 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);
}

View 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

View 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);
}

View 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);
}

View 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);
}

View 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);
}

View 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);
}

View 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);
}

View 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);
}

View 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);
}

View 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;
}

View 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);
}

View 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;

View File

@ -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;
}

View File

@ -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);

70
src/thread/cancel_impl.c Normal file
View File

@ -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);
}

View File

@ -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

View File

@ -1,7 +0,0 @@
#include "pthread_impl.h"
int pthread_cancel(pthread_t t)
{
a_store(&t->cancel, 1);
return pthread_kill(t, SIGCANCEL);
}

View 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;
}

View 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);
}

View 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;

View File

@ -2,6 +2,5 @@
void pthread_testcancel()
{
CANCELPT_BEGIN;
CANCELPT_END;
if (libc.testcancel) libc.testcancel();
}

View 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);

0
src/thread/syscall_cp.c Normal file
View File

View File

@ -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

View 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);
}

View 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);
}

View 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;
}

View 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);
}

View 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);

View 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);

View 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);
}

View 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);
}

View 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);
}

View 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);
}