summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAntoine Pitrou <pitrou@free.fr>2017-06-26 18:41:07 (GMT)
committerGitHub <noreply@github.com>2017-06-26 18:41:07 (GMT)
commitf84ac420c2af98339678744953869cad3c253281 (patch)
treec43cedbdbae29574ee72815ffe348c33bbfedf68
parent63f54c68936d648c70ca411661e4208329edcf26 (diff)
downloadcpython-f84ac420c2af98339678744953869cad3c253281.zip
cpython-f84ac420c2af98339678744953869cad3c253281.tar.gz
cpython-f84ac420c2af98339678744953869cad3c253281.tar.bz2
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
-rw-r--r--Misc/NEWS.d/next/Core and Builtins/2017-06-26-14-29-50.bpo-30765.Q5iBmf.rst2
-rw-r--r--Python/thread_pthread.h95
2 files changed, 52 insertions, 45 deletions
diff --git a/Misc/NEWS.d/next/Core and Builtins/2017-06-26-14-29-50.bpo-30765.Q5iBmf.rst b/Misc/NEWS.d/next/Core and Builtins/2017-06-26-14-29-50.bpo-30765.Q5iBmf.rst
new file mode 100644
index 0000000..08d76cb
--- /dev/null
+++ b/Misc/NEWS.d/next/Core and Builtins/2017-06-26-14-29-50.bpo-30765.Q5iBmf.rst
@@ -0,0 +1,2 @@
+Avoid blocking in pthread_mutex_lock() when PyThread_acquire_lock() is asked
+not to block.
diff --git a/Python/thread_pthread.h b/Python/thread_pthread.h
index b95840c..399d28c 100644
--- a/Python/thread_pthread.h
+++ b/Python/thread_pthread.h
@@ -466,61 +466,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("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("pthread_mutex_trylock[1]");
+ }
+ else {
+ status = pthread_mutex_lock( &thelock->mut );
+ CHECK_STATUS_PTHREAD("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("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;
- 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;
- } 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("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;
dprintf(("PyThread_acquire_lock_timed(%p, %lld, %d) -> %d\n",