From d96b12b755483208673fb05e2e60a15d3822752d Mon Sep 17 00:00:00 2001 From: Rich Felker Date: Sun, 6 Jul 2014 22:56:25 -0400 Subject: rework cancellation weak alias logic not to depend on archive order if the order of object files in the static archive libc.a was not respected by the linker, the old logic could wrongly cause POSIX symbols outside of the ISO C namespace to be pulled into pure C programs. this should not happen with well-behaved linkers, but relying on the link order was a bad idea anyway. files are renamed to better reflect their contents now that they don't need names to control their order as members in the archive file. --- src/thread/__syscall_cp.c | 18 +++++++++ src/thread/cancel_dummy.c | 17 --------- src/thread/cancel_impl.c | 85 ----------------------------------------- src/thread/pthread_cancel.c | 85 +++++++++++++++++++++++++++++++++++++++++ src/thread/pthread_testcancel.c | 7 +++- 5 files changed, 109 insertions(+), 103 deletions(-) create mode 100644 src/thread/__syscall_cp.c delete mode 100644 src/thread/cancel_dummy.c delete mode 100644 src/thread/cancel_impl.c create mode 100644 src/thread/pthread_cancel.c (limited to 'src') diff --git a/src/thread/__syscall_cp.c b/src/thread/__syscall_cp.c new file mode 100644 index 00000000..a48cee9b --- /dev/null +++ b/src/thread/__syscall_cp.c @@ -0,0 +1,18 @@ +#include "pthread_impl.h" +#include "syscall.h" + +static long sccp(syscall_arg_t nr, + syscall_arg_t u, syscall_arg_t v, syscall_arg_t w, + syscall_arg_t x, syscall_arg_t y, syscall_arg_t z) +{ + return (__syscall)(nr, u, v, w, x, y, z); +} + +weak_alias(sccp, __syscall_cp_c); + +long (__syscall_cp)(syscall_arg_t nr, + syscall_arg_t u, syscall_arg_t v, syscall_arg_t w, + syscall_arg_t x, syscall_arg_t y, syscall_arg_t z) +{ + return __syscall_cp_c(nr, u, v, w, x, y, z); +} diff --git a/src/thread/cancel_dummy.c b/src/thread/cancel_dummy.c deleted file mode 100644 index b630b02c..00000000 --- a/src/thread/cancel_dummy.c +++ /dev/null @@ -1,17 +0,0 @@ -#include "pthread_impl.h" -#include "syscall.h" - -static long sccp(syscall_arg_t nr, - syscall_arg_t u, syscall_arg_t v, syscall_arg_t w, - syscall_arg_t x, syscall_arg_t y, syscall_arg_t z) -{ - return (__syscall)(nr, u, v, w, x, y, z); -} - -weak_alias(sccp, __syscall_cp); - -static void dummy() -{ -} - -weak_alias(dummy, __testcancel); diff --git a/src/thread/cancel_impl.c b/src/thread/cancel_impl.c deleted file mode 100644 index 069b2796..00000000 --- a/src/thread/cancel_impl.c +++ /dev/null @@ -1,85 +0,0 @@ -#include "pthread_impl.h" -#include "syscall.h" - -void __cancel() -{ - pthread_t self = __pthread_self(); - self->canceldisable = 1; - self->cancelasync = 0; - pthread_exit(PTHREAD_CANCELED); -} - -long __syscall_cp_asm(volatile void *, syscall_arg_t, - syscall_arg_t, syscall_arg_t, syscall_arg_t, - syscall_arg_t, syscall_arg_t, syscall_arg_t); - -long (__syscall_cp)(syscall_arg_t nr, - syscall_arg_t u, syscall_arg_t v, syscall_arg_t w, - syscall_arg_t x, syscall_arg_t y, syscall_arg_t z) -{ - pthread_t self; - long r; - - if (!libc.has_thread_pointer || (self = __pthread_self())->canceldisable) - return __syscall(nr, u, v, w, x, y, z); - - r = __syscall_cp_asm(&self->cancel, nr, u, v, w, x, y, z); - if (r==-EINTR && nr!=SYS_close && self->cancel && !self->canceldisable) - __cancel(); - return r; -} - -static void _sigaddset(sigset_t *set, int sig) -{ - unsigned s = sig-1; - set->__bits[s/8/sizeof *set->__bits] |= 1UL<<(s&8*sizeof *set->__bits-1); -} - -static void cancel_handler(int sig, siginfo_t *si, void *ctx) -{ - pthread_t self = __pthread_self(); - ucontext_t *uc = ctx; - const char *ip = ((char **)&uc->uc_mcontext)[CANCEL_REG_IP]; - extern const char __cp_begin[1], __cp_end[1]; - - if (!self->cancel || self->canceldisable) return; - - _sigaddset(&uc->uc_sigmask, SIGCANCEL); - - if (self->cancelasync || ip >= __cp_begin && ip < __cp_end) { - self->canceldisable = 1; - pthread_sigmask(SIG_SETMASK, &uc->uc_sigmask, 0); - __cancel(); - } - - __syscall(SYS_tkill, self->tid, SIGCANCEL); -} - -void __testcancel() -{ - if (!libc.has_thread_pointer) return; - pthread_t self = __pthread_self(); - if (self->cancel && !self->canceldisable) - __cancel(); -} - -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); -} - -int pthread_cancel(pthread_t t) -{ - static int init; - if (!init) { - init_cancellation(); - init = 1; - } - a_store(&t->cancel, 1); - return pthread_kill(t, SIGCANCEL); -} diff --git a/src/thread/pthread_cancel.c b/src/thread/pthread_cancel.c new file mode 100644 index 00000000..e3d291ee --- /dev/null +++ b/src/thread/pthread_cancel.c @@ -0,0 +1,85 @@ +#include "pthread_impl.h" +#include "syscall.h" + +void __cancel() +{ + pthread_t self = __pthread_self(); + self->canceldisable = 1; + self->cancelasync = 0; + pthread_exit(PTHREAD_CANCELED); +} + +long __syscall_cp_asm(volatile void *, syscall_arg_t, + syscall_arg_t, syscall_arg_t, syscall_arg_t, + syscall_arg_t, syscall_arg_t, syscall_arg_t); + +long __syscall_cp_c(syscall_arg_t nr, + syscall_arg_t u, syscall_arg_t v, syscall_arg_t w, + syscall_arg_t x, syscall_arg_t y, syscall_arg_t z) +{ + pthread_t self; + long r; + + if (!libc.has_thread_pointer || (self = __pthread_self())->canceldisable) + return __syscall(nr, u, v, w, x, y, z); + + r = __syscall_cp_asm(&self->cancel, nr, u, v, w, x, y, z); + if (r==-EINTR && nr!=SYS_close && self->cancel && !self->canceldisable) + __cancel(); + return r; +} + +static void _sigaddset(sigset_t *set, int sig) +{ + unsigned s = sig-1; + set->__bits[s/8/sizeof *set->__bits] |= 1UL<<(s&8*sizeof *set->__bits-1); +} + +static void cancel_handler(int sig, siginfo_t *si, void *ctx) +{ + pthread_t self = __pthread_self(); + ucontext_t *uc = ctx; + const char *ip = ((char **)&uc->uc_mcontext)[CANCEL_REG_IP]; + extern const char __cp_begin[1], __cp_end[1]; + + if (!self->cancel || self->canceldisable) return; + + _sigaddset(&uc->uc_sigmask, SIGCANCEL); + + if (self->cancelasync || ip >= __cp_begin && ip < __cp_end) { + self->canceldisable = 1; + pthread_sigmask(SIG_SETMASK, &uc->uc_sigmask, 0); + __cancel(); + } + + __syscall(SYS_tkill, self->tid, SIGCANCEL); +} + +void __testcancel() +{ + if (!libc.has_thread_pointer) return; + pthread_t self = __pthread_self(); + if (self->cancel && !self->canceldisable) + __cancel(); +} + +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); +} + +int pthread_cancel(pthread_t t) +{ + static int init; + if (!init) { + init_cancellation(); + init = 1; + } + a_store(&t->cancel, 1); + return pthread_kill(t, SIGCANCEL); +} diff --git a/src/thread/pthread_testcancel.c b/src/thread/pthread_testcancel.c index 33238c0f..ba5f7c6c 100644 --- a/src/thread/pthread_testcancel.c +++ b/src/thread/pthread_testcancel.c @@ -1,6 +1,11 @@ #include "pthread_impl.h" +#include "libc.h" -void __testcancel(void); +static void dummy() +{ +} + +weak_alias(dummy, __testcancel); void pthread_testcancel() { -- cgit v1.2.1