diff options
author | Antoine Pitrou <pitrou@free.fr> | 2017-06-26 20:07:20 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-06-26 20:07:20 (GMT) |
commit | 85b34edd8b575b918490afbcb0db6f791874dbdd (patch) | |
tree | e55ccb20bdbf009fb9957a91515534fa98071916 /Python | |
parent | 849b062a82ca2f09e33259d34067faba196c9e23 (diff) | |
download | cpython-85b34edd8b575b918490afbcb0db6f791874dbdd.zip cpython-85b34edd8b575b918490afbcb0db6f791874dbdd.tar.gz cpython-85b34edd8b575b918490afbcb0db6f791874dbdd.tar.bz2 |
[3.5] bpo-30765: Avoid blocking when PyThread_acquire_lock() is asked not to (GH-2403) (#2419)
* bpo-30765: Avoid blocking when PyThread_acquire_lock() is asked not to lock
This is especially important if PyThread_acquire_lock() is called reentrantly
(for example from a signal handler).
* Update 2017-06-26-14-29-50.bpo-30765.Q5iBmf.rst
* Avoid core logic when taking the mutex failed.
(cherry picked from commit f84ac420c2af98339678744953869cad3c253281)
Diffstat (limited to 'Python')
-rw-r--r-- | Python/thread_pthread.h | 95 |
1 files changed, 50 insertions, 45 deletions
diff --git a/Python/thread_pthread.h b/Python/thread_pthread.h index 27e0dc8..8e42262 100644 --- a/Python/thread_pthread.h +++ b/Python/thread_pthread.h @@ -464,61 +464,66 @@ PyLockStatus PyThread_acquire_lock_timed(PyThread_type_lock lock, PY_TIMEOUT_T microseconds, int intr_flag) { - PyLockStatus success; + PyLockStatus success = PY_LOCK_FAILURE; pthread_lock *thelock = (pthread_lock *)lock; int status, error = 0; dprintf(("PyThread_acquire_lock_timed(%p, %lld, %d) called\n", lock, microseconds, intr_flag)); - status = pthread_mutex_lock( &thelock->mut ); - CHECK_STATUS("pthread_mutex_lock[1]"); - - if (thelock->locked == 0) { - success = PY_LOCK_ACQUIRED; - } else if (microseconds == 0) { - success = PY_LOCK_FAILURE; - } else { - struct timespec ts; - if (microseconds > 0) - MICROSECONDS_TO_TIMESPEC(microseconds, ts); - /* continue trying until we get the lock */ - - /* mut must be locked by me -- part of the condition - * protocol */ - success = PY_LOCK_FAILURE; - while (success == PY_LOCK_FAILURE) { - if (microseconds > 0) { - status = pthread_cond_timedwait( - &thelock->lock_released, - &thelock->mut, &ts); - if (status == ETIMEDOUT) + if (microseconds == 0) { + status = pthread_mutex_trylock( &thelock->mut ); + if (status != EBUSY) + CHECK_STATUS("pthread_mutex_trylock[1]"); + } + else { + status = pthread_mutex_lock( &thelock->mut ); + CHECK_STATUS("pthread_mutex_lock[1]"); + } + if (status == 0) { + if (thelock->locked == 0) { + success = PY_LOCK_ACQUIRED; + } + else if (microseconds != 0) { + struct timespec ts; + if (microseconds > 0) + MICROSECONDS_TO_TIMESPEC(microseconds, ts); + /* continue trying until we get the lock */ + + /* mut must be locked by me -- part of the condition + * protocol */ + while (success == PY_LOCK_FAILURE) { + if (microseconds > 0) { + status = pthread_cond_timedwait( + &thelock->lock_released, + &thelock->mut, &ts); + if (status == ETIMEDOUT) + break; + CHECK_STATUS("pthread_cond_timed_wait"); + } + else { + status = pthread_cond_wait( + &thelock->lock_released, + &thelock->mut); + CHECK_STATUS("pthread_cond_wait"); + } + + if (intr_flag && status == 0 && thelock->locked) { + /* We were woken up, but didn't get the lock. We probably received + * a signal. Return PY_LOCK_INTR to allow the caller to handle + * it and retry. */ + success = PY_LOCK_INTR; break; - CHECK_STATUS("pthread_cond_timed_wait"); - } - else { - status = pthread_cond_wait( - &thelock->lock_released, - &thelock->mut); - CHECK_STATUS("pthread_cond_wait"); - } - - if (intr_flag && status == 0 && thelock->locked) { - /* We were woken up, but didn't get the lock. We probably received - * a signal. Return PY_LOCK_INTR to allow the caller to handle - * it and retry. */ - success = PY_LOCK_INTR; - break; - } else if (status == 0 && !thelock->locked) { - success = PY_LOCK_ACQUIRED; - } else { - success = PY_LOCK_FAILURE; + } + else if (status == 0 && !thelock->locked) { + success = PY_LOCK_ACQUIRED; + } } } + if (success == PY_LOCK_ACQUIRED) thelock->locked = 1; + status = pthread_mutex_unlock( &thelock->mut ); + CHECK_STATUS("pthread_mutex_unlock[1]"); } - if (success == PY_LOCK_ACQUIRED) thelock->locked = 1; - status = pthread_mutex_unlock( &thelock->mut ); - CHECK_STATUS("pthread_mutex_unlock[1]"); if (error) success = PY_LOCK_FAILURE; dprintf(("PyThread_acquire_lock_timed(%p, %lld, %d) -> %d\n", |