summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lib/libthr/thread/thr_init.c26
-rw-r--r--lib/libthr/thread/thr_kern.c13
-rw-r--r--lib/libthr/thread/thr_private.h3
3 files changed, 31 insertions, 11 deletions
diff --git a/lib/libthr/thread/thr_init.c b/lib/libthr/thread/thr_init.c
index c404651..671bd6f 100644
--- a/lib/libthr/thread/thr_init.c
+++ b/lib/libthr/thread/thr_init.c
@@ -66,6 +66,14 @@
#include "thr_private.h"
+/*
+ * Early implementations of sigtimedwait interpreted the signal
+ * set incorrectly.
+ */
+#define SIGTIMEDWAIT_SET_IS_INVERTED(osreldate) \
+ ((500100 <= (osreldate) && (osreldate) <= 500113) || \
+ (osreldate) == 501000 || (osreldate) == 501100)
+
extern void _thread_init_hack(void);
/*
@@ -168,6 +176,7 @@ _thread_init(void)
size_t len;
int mib[2];
sigset_t set;
+ int osreldate;
int error;
struct clockinfo clockinfo;
@@ -324,6 +333,23 @@ _thread_init(void)
SIGADDSET(set, SIGTHR);
__sys_sigprocmask(SIG_BLOCK, &set, 0);
+ /*
+ * Precompute the signal set used by _thread_suspend to wait
+ * for SIGTHR.
+ */
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_OSRELDATE;
+ len = sizeof(osreldate);
+ if (sysctl(mib, 2, &osreldate, &len, NULL, 0) == 0 &&
+ SIGTIMEDWAIT_SET_IS_INVERTED(osreldate)) {
+ /* Kernel bug requires an inverted signal set. */
+ SIGFILLSET(_thread_suspend_sigset);
+ SIGDELSET(_thread_suspend_sigset, SIGTHR);
+ } else {
+ SIGEMPTYSET(_thread_suspend_sigset);
+ SIGADDSET(_thread_suspend_sigset, SIGTHR);
+ }
+
/* Get the kernel clockrate: */
mib[0] = CTL_KERN;
mib[1] = KERN_CLOCKRATE;
diff --git a/lib/libthr/thread/thr_kern.c b/lib/libthr/thread/thr_kern.c
index 1c9a8ce..f45cae5 100644
--- a/lib/libthr/thread/thr_kern.c
+++ b/lib/libthr/thread/thr_kern.c
@@ -179,16 +179,9 @@ _thread_suspend(pthread_t pthread, struct timespec *abstime)
struct timespec remaining;
struct timespec *ts;
siginfo_t info;
- sigset_t set;
int error;
/*
- * Catch SIGTHR.
- */
- SIGFILLSET(set);
- SIGDELSET(set, SIGTHR);
-
- /*
* Compute the remainder of the run time.
*/
if (abstime) {
@@ -204,9 +197,7 @@ _thread_suspend(pthread_t pthread, struct timespec *abstime)
} else
ts = NULL;
- error = sigtimedwait(&set, &info, ts);
- if (error == -1)
- error = errno;
-
+ error = sigtimedwait(&_thread_suspend_sigset, &info, ts);
+ error = (error == -1) ? errno : 0;
return (error);
}
diff --git a/lib/libthr/thread/thr_private.h b/lib/libthr/thread/thr_private.h
index 9989342..b273890 100644
--- a/lib/libthr/thread/thr_private.h
+++ b/lib/libthr/thread/thr_private.h
@@ -692,6 +692,9 @@ SCLASS pthread_cond_t _gc_cond
*/
SCLASS struct sigaction _thread_sigact[NSIG];
+/* Precomputed signal set for _thread_suspend. */
+SCLASS sigset_t _thread_suspend_sigset;
+
/* Tracks the number of threads blocked while waiting for a spinlock. */
SCLASS volatile int _spinblock_count
#ifdef GLOBAL_PTHREAD_PRIVATE
OpenPOWER on IntegriCloud