summaryrefslogtreecommitdiffstats
path: root/Python/thread_pthread.h
diff options
context:
space:
mode:
Diffstat (limited to 'Python/thread_pthread.h')
-rw-r--r--Python/thread_pthread.h66
1 files changed, 47 insertions, 19 deletions
diff --git a/Python/thread_pthread.h b/Python/thread_pthread.h
index ec7d737..35b9810 100644
--- a/Python/thread_pthread.h
+++ b/Python/thread_pthread.h
@@ -32,18 +32,17 @@
#define THREAD_STACK_SIZE 0 /* use default stack size */
#endif
-/* The default stack size for new threads on OSX and BSD is small enough that
+/* The default stack size for new threads on BSD is small enough that
* we'll get hard crashes instead of 'maximum recursion depth exceeded'
* exceptions.
*
- * The default stack sizes below are the empirically determined minimal stack
+ * The default stack size below is the empirically determined minimal stack
* sizes where a simple recursive function doesn't cause a hard crash.
+ *
+ * For macOS the value of THREAD_STACK_SIZE is determined in configure.ac
+ * as it also depends on the other configure options like chosen sanitizer
+ * runtimes.
*/
-#if defined(__APPLE__) && defined(THREAD_STACK_SIZE) && THREAD_STACK_SIZE == 0
-#undef THREAD_STACK_SIZE
-/* Note: This matches the value of -Wl,-stack_size in configure.ac */
-#define THREAD_STACK_SIZE 0x1000000
-#endif
#if defined(__FreeBSD__) && defined(THREAD_STACK_SIZE) && THREAD_STACK_SIZE == 0
#undef THREAD_STACK_SIZE
#define THREAD_STACK_SIZE 0x400000
@@ -93,12 +92,17 @@
* mutexes and condition variables:
*/
#if (defined(_POSIX_SEMAPHORES) && !defined(HAVE_BROKEN_POSIX_SEMAPHORES) && \
- defined(HAVE_SEM_TIMEDWAIT))
+ (defined(HAVE_SEM_TIMEDWAIT) || defined(HAVE_SEM_CLOCKWAIT)))
# define USE_SEMAPHORES
#else
# undef USE_SEMAPHORES
#endif
+#if defined(HAVE_PTHREAD_CONDATTR_SETCLOCK) && defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC)
+// monotonic is supported statically. It doesn't mean it works on runtime.
+#define CONDATTR_MONOTONIC
+#endif
+
/* On platforms that don't use standard POSIX threads pthread_sigmask()
* isn't present. DEC threads uses sigprocmask() instead as do most
@@ -124,16 +128,23 @@ do { \
ts.tv_nsec = tv.tv_usec * 1000; \
} while(0)
+#if defined(CONDATTR_MONOTONIC) || defined(HAVE_SEM_CLOCKWAIT)
+static void
+monotonic_abs_timeout(long long us, struct timespec *abs)
+{
+ clock_gettime(CLOCK_MONOTONIC, abs);
+ abs->tv_sec += us / 1000000;
+ abs->tv_nsec += (us % 1000000) * 1000;
+ abs->tv_sec += abs->tv_nsec / 1000000000;
+ abs->tv_nsec %= 1000000000;
+}
+#endif
+
/*
* pthread_cond support
*/
-#if defined(HAVE_PTHREAD_CONDATTR_SETCLOCK) && defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC)
-// monotonic is supported statically. It doesn't mean it works on runtime.
-#define CONDATTR_MONOTONIC
-#endif
-
// NULL when pthread_condattr_setclock(CLOCK_MONOTONIC) is not supported.
static pthread_condattr_t *condattr_monotonic = NULL;
@@ -155,16 +166,13 @@ _PyThread_cond_init(PyCOND_T *cond)
return pthread_cond_init(cond, condattr_monotonic);
}
+
void
_PyThread_cond_after(long long us, struct timespec *abs)
{
#ifdef CONDATTR_MONOTONIC
if (condattr_monotonic) {
- clock_gettime(CLOCK_MONOTONIC, abs);
- abs->tv_sec += us / 1000000;
- abs->tv_nsec += (us % 1000000) * 1000;
- abs->tv_sec += abs->tv_nsec / 1000000000;
- abs->tv_nsec %= 1000000000;
+ monotonic_abs_timeout(us, abs);
return;
}
#endif
@@ -435,7 +443,9 @@ PyThread_acquire_lock_timed(PyThread_type_lock lock, PY_TIMEOUT_T microseconds,
sem_t *thelock = (sem_t *)lock;
int status, error = 0;
struct timespec ts;
+#ifndef HAVE_SEM_CLOCKWAIT
_PyTime_t deadline = 0;
+#endif
(void) error; /* silence unused-but-set-variable warning */
dprintf(("PyThread_acquire_lock_timed(%p, %lld, %d) called\n",
@@ -446,6 +456,9 @@ PyThread_acquire_lock_timed(PyThread_type_lock lock, PY_TIMEOUT_T microseconds,
}
if (microseconds > 0) {
+#ifdef HAVE_SEM_CLOCKWAIT
+ monotonic_abs_timeout(microseconds, &ts);
+#else
MICROSECONDS_TO_TIMESPEC(microseconds, ts);
if (!intr_flag) {
@@ -454,11 +467,17 @@ PyThread_acquire_lock_timed(PyThread_type_lock lock, PY_TIMEOUT_T microseconds,
_PyTime_t timeout = _PyTime_FromNanoseconds(microseconds * 1000);
deadline = _PyTime_GetMonotonicClock() + timeout;
}
+#endif
}
while (1) {
if (microseconds > 0) {
+#ifdef HAVE_SEM_CLOCKWAIT
+ status = fix_status(sem_clockwait(thelock, CLOCK_MONOTONIC,
+ &ts));
+#else
status = fix_status(sem_timedwait(thelock, &ts));
+#endif
}
else if (microseconds == 0) {
status = fix_status(sem_trywait(thelock));
@@ -473,6 +492,9 @@ PyThread_acquire_lock_timed(PyThread_type_lock lock, PY_TIMEOUT_T microseconds,
break;
}
+ // sem_clockwait() uses an absolute timeout, there is no need
+ // to recompute the relative timeout.
+#ifndef HAVE_SEM_CLOCKWAIT
if (microseconds > 0) {
/* wait interrupted by a signal (EINTR): recompute the timeout */
_PyTime_t dt = deadline - _PyTime_GetMonotonicClock();
@@ -494,13 +516,19 @@ PyThread_acquire_lock_timed(PyThread_type_lock lock, PY_TIMEOUT_T microseconds,
microseconds = 0;
}
}
+#endif
}
/* Don't check the status if we're stopping because of an interrupt. */
if (!(intr_flag && status == EINTR)) {
if (microseconds > 0) {
- if (status != ETIMEDOUT)
+ if (status != ETIMEDOUT) {
+#ifdef HAVE_SEM_CLOCKWAIT
+ CHECK_STATUS("sem_clockwait");
+#else
CHECK_STATUS("sem_timedwait");
+#endif
+ }
}
else if (microseconds == 0) {
if (status != EAGAIN)