summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNela Gurevich <nelag@codeaurora.org>2010-07-13 17:00:32 +0300
committerNela Gurevich <nelag@codeaurora.org>2010-08-25 09:25:52 +0300
commit320895d6ee49f70832e7a40e2b87ae7d3a72996a (patch)
tree912ef641e62dfb5e0c72b7597a67b8fae2511206
parenta71ccde9e268205a3603763ba432a3b0098ddd6c (diff)
downloadbionic-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.c32
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;