diff options
Diffstat (limited to 'Python/thread_pthread.h')
-rw-r--r-- | Python/thread_pthread.h | 81 |
1 files changed, 62 insertions, 19 deletions
diff --git a/Python/thread_pthread.h b/Python/thread_pthread.h index 09e53a14aa..25f58d9446 100644 --- a/Python/thread_pthread.h +++ b/Python/thread_pthread.h @@ -56,16 +56,6 @@ #endif #endif -#if !defined(pthread_attr_default) -# define pthread_attr_default ((pthread_attr_t *)NULL) -#endif -#if !defined(pthread_mutexattr_default) -# define pthread_mutexattr_default ((pthread_mutexattr_t *)NULL) -#endif -#if !defined(pthread_condattr_default) -# define pthread_condattr_default ((pthread_condattr_t *)NULL) -#endif - /* Whether or not to use semaphores directly rather than emulating them with * mutexes and condition variables: @@ -110,6 +100,56 @@ do { \ } while(0) +/* + * 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; + +static void +init_condattr() +{ +#ifdef CONDATTR_MONOTONIC + static pthread_condattr_t ca; + pthread_condattr_init(&ca); + if (pthread_condattr_setclock(&ca, CLOCK_MONOTONIC) == 0) { + condattr_monotonic = &ca; // Use monotonic clock + } +#endif +} + +int +_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; + return; + } +#endif + + struct timespec ts; + MICROSECONDS_TO_TIMESPEC(us, ts); + *abs = ts; +} + + /* A pthread mutex isn't sufficient to model the Python lock type * because, according to Draft 5 of the docs (P1003.4a/D5), both of the * following are undefined: @@ -146,6 +186,7 @@ PyThread__init_thread(void) extern void pthread_init(void); pthread_init(); #endif + init_condattr(); } /* @@ -462,8 +503,7 @@ PyThread_allocate_lock(void) memset((void *)lock, '\0', sizeof(pthread_lock)); lock->locked = 0; - status = pthread_mutex_init(&lock->mut, - pthread_mutexattr_default); + status = pthread_mutex_init(&lock->mut, NULL); CHECK_STATUS_PTHREAD("pthread_mutex_init"); /* Mark the pthread mutex underlying a Python mutex as pure happens-before. We can't simply mark the @@ -472,8 +512,7 @@ PyThread_allocate_lock(void) will cause errors. */ _Py_ANNOTATE_PURE_HAPPENS_BEFORE_MUTEX(&lock->mut); - status = pthread_cond_init(&lock->lock_released, - pthread_condattr_default); + status = _PyThread_cond_init(&lock->lock_released); CHECK_STATUS_PTHREAD("pthread_cond_init"); if (error) { @@ -532,9 +571,10 @@ PyThread_acquire_lock_timed(PyThread_type_lock lock, PY_TIMEOUT_T microseconds, success = PY_LOCK_ACQUIRED; } else if (microseconds != 0) { - struct timespec ts; - if (microseconds > 0) - MICROSECONDS_TO_TIMESPEC(microseconds, ts); + struct timespec abs; + if (microseconds > 0) { + _PyThread_cond_after(microseconds, &abs); + } /* continue trying until we get the lock */ /* mut must be locked by me -- part of the condition @@ -543,10 +583,13 @@ PyThread_acquire_lock_timed(PyThread_type_lock lock, PY_TIMEOUT_T microseconds, if (microseconds > 0) { status = pthread_cond_timedwait( &thelock->lock_released, - &thelock->mut, &ts); + &thelock->mut, &abs); + if (status == 1) { + break; + } if (status == ETIMEDOUT) break; - CHECK_STATUS_PTHREAD("pthread_cond_timed_wait"); + CHECK_STATUS_PTHREAD("pthread_cond_timedwait"); } else { status = pthread_cond_wait( |