summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid 'Digit' Turner <digit@google.com>2011-11-14 12:57:47 +0100
committerDavid 'Digit' Turner <digit@google.com>2011-11-14 22:57:24 +0100
commit9bf330b5676d0f60b3e4c3b8985494bcb1134e8b (patch)
treeb45e394b4e8b7fe8cebb1aa4d04b3131e0c4e48b
parent7939908c8310342c8e1b717c4599273a782b3c2b (diff)
downloadbionic-9bf330b5676d0f60b3e4c3b8985494bcb1134e8b.zip
bionic-9bf330b5676d0f60b3e4c3b8985494bcb1134e8b.tar.gz
bionic-9bf330b5676d0f60b3e4c3b8985494bcb1134e8b.tar.bz2
libc: fix the pthread_sigmask implementation
The old code didn't work because the kernel expects a 64-bit sigset_t while the one provided by our ABI is only 32-bit. This is originally due to the fact that the kernel headers themselves define sigset_t as a 32-bit type when __KERNEL__ is not defined (apparently to cater to libc5 or some similarly old C library). We can't modify the size of sigset_t without breaking the NDK ABI, so instead perform runtime translation during the call. Change-Id: Ibfdc3cbceaff864af7a05ca193aa050047b4773f
-rw-r--r--libc/bionic/pthread.c43
1 files changed, 36 insertions, 7 deletions
diff --git a/libc/bionic/pthread.c b/libc/bionic/pthread.c
index 1da2ec9..b893a12 100644
--- a/libc/bionic/pthread.c
+++ b/libc/bionic/pthread.c
@@ -1856,7 +1856,21 @@ int pthread_kill(pthread_t tid, int sig)
return ret;
}
-extern int __rt_sigprocmask(int, const sigset_t *, sigset_t *, size_t);
+/* Despite the fact that our kernel headers define sigset_t explicitly
+ * as a 32-bit integer, the kernel system call really expects a 64-bit
+ * bitmap for the signal set, or more exactly an array of two-32-bit
+ * values (see $KERNEL/arch/$ARCH/include/asm/signal.h for details).
+ *
+ * Unfortunately, we cannot fix the sigset_t definition without breaking
+ * the C library ABI, so perform a little runtime translation here.
+ */
+typedef union {
+ sigset_t bionic;
+ uint32_t kernel[2];
+} kernel_sigset_t;
+
+/* this is a private syscall stub */
+extern int __rt_sigprocmask(int, const kernel_sigset_t *, kernel_sigset_t *, size_t);
int pthread_sigmask(int how, const sigset_t *set, sigset_t *oset)
{
@@ -1865,16 +1879,31 @@ int pthread_sigmask(int how, const sigset_t *set, sigset_t *oset)
*/
int ret, old_errno = errno;
- /* Use NSIG which corresponds to the number of signals in
- * our 32-bit sigset_t implementation. As such, this function, or
- * anything that deals with sigset_t cannot manage real-time signals
- * (signo >= 32). We might want to introduce sigset_rt_t as an
- * extension to do so in the future.
+ /* We must convert *set into a kernel_sigset_t */
+ kernel_sigset_t in_set, *in_set_ptr;
+ kernel_sigset_t out_set;
+
+ in_set.kernel[0] = in_set.kernel[1] = 0;
+ out_set.kernel[0] = out_set.kernel[1] = 0;
+
+ /* 'in_set_ptr' is the second parameter to __rt_sigprocmask. It must be NULL
+ * if 'set' is NULL to ensure correct semantics (which in this case would
+ * be to ignore 'how' and return the current signal set into 'oset'.
*/
- ret = __rt_sigprocmask(how, set, oset, NSIG / 8);
+ if (set == NULL) {
+ in_set_ptr = NULL;
+ } else {
+ in_set.bionic = *set;
+ in_set_ptr = &in_set;
+ }
+
+ ret = __rt_sigprocmask(how, in_set_ptr, &out_set, sizeof(kernel_sigset_t));
if (ret < 0)
ret = errno;
+ if (oset)
+ *oset = out_set.bionic;
+
errno = old_errno;
return ret;
}