Commit f84ac420 authored by Antoine Pitrou's avatar Antoine Pitrou Committed by GitHub

bpo-30765: Avoid blocking when PyThread_acquire_lock() is asked not to (#2403)

* 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
parent 63f54c68
Avoid blocking in pthread_mutex_lock() when PyThread_acquire_lock() is asked
not to block.
...@@ -466,61 +466,66 @@ PyLockStatus ...@@ -466,61 +466,66 @@ PyLockStatus
PyThread_acquire_lock_timed(PyThread_type_lock lock, PY_TIMEOUT_T microseconds, PyThread_acquire_lock_timed(PyThread_type_lock lock, PY_TIMEOUT_T microseconds,
int intr_flag) int intr_flag)
{ {
PyLockStatus success; PyLockStatus success = PY_LOCK_FAILURE;
pthread_lock *thelock = (pthread_lock *)lock; pthread_lock *thelock = (pthread_lock *)lock;
int status, error = 0; int status, error = 0;
dprintf(("PyThread_acquire_lock_timed(%p, %lld, %d) called\n", dprintf(("PyThread_acquire_lock_timed(%p, %lld, %d) called\n",
lock, microseconds, intr_flag)); lock, microseconds, intr_flag));
status = pthread_mutex_lock( &thelock->mut ); if (microseconds == 0) {
CHECK_STATUS_PTHREAD("pthread_mutex_lock[1]"); status = pthread_mutex_trylock( &thelock->mut );
if (status != EBUSY)
if (thelock->locked == 0) { CHECK_STATUS_PTHREAD("pthread_mutex_trylock[1]");
success = PY_LOCK_ACQUIRED; }
} else if (microseconds == 0) { else {
success = PY_LOCK_FAILURE; status = pthread_mutex_lock( &thelock->mut );
} else { CHECK_STATUS_PTHREAD("pthread_mutex_lock[1]");
struct timespec ts; }
if (microseconds > 0) if (status == 0) {
MICROSECONDS_TO_TIMESPEC(microseconds, ts); if (thelock->locked == 0) {
/* continue trying until we get the lock */ success = PY_LOCK_ACQUIRED;
}
/* mut must be locked by me -- part of the condition else if (microseconds != 0) {
* protocol */ struct timespec ts;
success = PY_LOCK_FAILURE; if (microseconds > 0)
while (success == PY_LOCK_FAILURE) { MICROSECONDS_TO_TIMESPEC(microseconds, ts);
if (microseconds > 0) { /* continue trying until we get the lock */
status = pthread_cond_timedwait(
&thelock->lock_released, /* mut must be locked by me -- part of the condition
&thelock->mut, &ts); * protocol */
if (status == ETIMEDOUT) 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("pthread_cond_timed_wait");
}
else {
status = pthread_cond_wait(
&thelock->lock_released,
&thelock->mut);
CHECK_STATUS_PTHREAD("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; break;
CHECK_STATUS_PTHREAD("pthread_cond_timed_wait"); }
} else if (status == 0 && !thelock->locked) {
else { success = PY_LOCK_ACQUIRED;
status = pthread_cond_wait( }
&thelock->lock_released,
&thelock->mut);
CHECK_STATUS_PTHREAD("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;
} }
} }
if (success == PY_LOCK_ACQUIRED) thelock->locked = 1;
status = pthread_mutex_unlock( &thelock->mut );
CHECK_STATUS_PTHREAD("pthread_mutex_unlock[1]");
} }
if (success == PY_LOCK_ACQUIRED) thelock->locked = 1;
status = pthread_mutex_unlock( &thelock->mut );
CHECK_STATUS_PTHREAD("pthread_mutex_unlock[1]");
if (error) success = PY_LOCK_FAILURE; if (error) success = PY_LOCK_FAILURE;
dprintf(("PyThread_acquire_lock_timed(%p, %lld, %d) -> %d\n", dprintf(("PyThread_acquire_lock_timed(%p, %lld, %d) -> %d\n",
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment