summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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;