diff options
author | Nela Gurevich <nelag@codeaurora.org> | 2010-07-13 17:00:32 +0300 |
---|---|---|
committer | Nela Gurevich <nelag@codeaurora.org> | 2010-08-25 09:25:52 +0300 |
commit | 320895d6ee49f70832e7a40e2b87ae7d3a72996a (patch) | |
tree | 912ef641e62dfb5e0c72b7597a67b8fae2511206 | |
parent | a71ccde9e268205a3603763ba432a3b0098ddd6c (diff) | |
download | bionic-320895d6ee49f70832e7a40e2b87ae7d3a72996a.zip bionic-320895d6ee49f70832e7a40e2b87ae7d3a72996a.tar.gz bionic-320895d6ee49f70832e7a40e2b87ae7d3a72996a.tar.bz2 |
bionic: Fix signal mask size mismatch between bionic and kernel
The bionic library assumes that signal mask size is
32 bit, where the kernel expects to receive a 64 bit mask.
In this fix, the signal mask size is extended to 64 bit
before calling the kernel.
Please note that this is a known problem and is common in Linux
across many platforms.
This fix is based on a similar fix that already exists in
libc/unistd/sigwait.c
Change-Id: I01d40ef78fae25cabb357b0052fe58671026374e
-rw-r--r-- | libc/bionic/pthread.c | 32 |
1 files changed, 28 insertions, 4 deletions
diff --git a/libc/bionic/pthread.c b/libc/bionic/pthread.c index ae44b06..dbd34bb 100644 --- a/libc/bionic/pthread.c +++ b/libc/bionic/pthread.c @@ -1833,14 +1833,39 @@ int pthread_kill(pthread_t tid, int sig) extern int __rt_sigprocmask(int, const sigset_t *, sigset_t *, size_t); +/* <asm/signal.h> defines sigset_t differently when you're in the + * kernel or in the C library. + * + * in the kernel, this is an array of 2 32-bit unsigned longs + * in the C library, this is a single 32-bit unsigned long + * + * moreover, the kernel implementation of rt_sigprocmask doesn't + * accept anything except kernel-sized signal sets (probably a bug !) + * + * we thus need to create a fake kernel sigset !! + */ int pthread_sigmask(int how, const sigset_t *set, sigset_t *oset) { /* pthread_sigmask must return the error code, but the syscall - * will set errno instead and return 0/-1 - */ + * will set errno instead and return 0/-1 + */ + sigset_t kernelMaskIn[2]; int ret, old_errno = errno; - ret = __rt_sigprocmask(how, set, oset, _NSIG / 8); + kernelMaskIn[0] = *set; + kernelMaskIn[1] = 0; + + if (oset) + { + sigset_t kernelMaskOut[2]; + ret = __rt_sigprocmask(how, kernelMaskIn, kernelMaskOut, sizeof(kernelMaskIn)); + *oset = kernelMaskOut[0]; + } + else + { + ret = __rt_sigprocmask(how, kernelMaskIn, NULL, sizeof(kernelMaskIn)); + } + if (ret < 0) ret = errno; @@ -1848,7 +1873,6 @@ int pthread_sigmask(int how, const sigset_t *set, sigset_t *oset) return ret; } - int pthread_getcpuclockid(pthread_t tid, clockid_t *clockid) { const int CLOCK_IDTYPE_BITS = 3; |