summaryrefslogtreecommitdiffstats
path: root/Python
diff options
context:
space:
mode:
authorAntoine Pitrou <pitrou@free.fr>2017-06-26 20:07:20 (GMT)
committerGitHub <noreply@github.com>2017-06-26 20:07:20 (GMT)
commit85b34edd8b575b918490afbcb0db6f791874dbdd (patch)
treee55ccb20bdbf009fb9957a91515534fa98071916 /Python
parent849b062a82ca2f09e33259d34067faba196c9e23 (diff)
downloadcpython-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.h95
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",