[2.7] bpo-30765: Avoid blocking when PyThread_acquire_lock() is asked not to (GH-2403) (#2420)
* [2.7] bpo-30765: Avoid blocking when PyThread_acquire_lock() is asked not to (GH-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.
(cherry picked from commit f84ac420c2af98339678744953869cad3c253281)
* Remove test undef
diff --git a/Python/thread_pthread.h b/Python/thread_pthread.h
index c9ed796..79c66d4 100644
--- a/Python/thread_pthread.h
+++ b/Python/thread_pthread.h
@@ -410,31 +410,41 @@
int
PyThread_acquire_lock(PyThread_type_lock lock, int waitflag)
{
- int success;
+ int success = 0;
pthread_lock *thelock = (pthread_lock *)lock;
int status, error = 0;
dprintf(("PyThread_acquire_lock(%p, %d) called\n", lock, waitflag));
- status = pthread_mutex_lock( &thelock->mut );
- CHECK_STATUS("pthread_mutex_lock[1]");
- success = thelock->locked == 0;
-
- if ( !success && waitflag ) {
- /* continue trying until we get the lock */
-
- /* mut must be locked by me -- part of the condition
- * protocol */
- while ( thelock->locked ) {
- status = pthread_cond_wait(&thelock->lock_released,
- &thelock->mut);
- CHECK_STATUS("pthread_cond_wait");
- }
- success = 1;
+ if (waitflag) {
+ status = pthread_mutex_lock( &thelock->mut );
+ CHECK_STATUS("pthread_mutex_lock[1]");
}
- if (success) thelock->locked = 1;
- status = pthread_mutex_unlock( &thelock->mut );
- CHECK_STATUS("pthread_mutex_unlock[1]");
+ else {
+ status = pthread_mutex_trylock( &thelock->mut );
+ if (status != EBUSY)
+ CHECK_STATUS("pthread_mutex_trylock[1]");
+ }
+ if (status == 0) {
+ success = thelock->locked == 0;
+
+ if ( !success && waitflag ) {
+ /* continue trying until we get the lock */
+
+ /* mut must be locked by me -- part of the condition
+ * protocol */
+ while ( thelock->locked ) {
+ status = pthread_cond_wait(&thelock->lock_released,
+ &thelock->mut);
+ CHECK_STATUS("pthread_cond_wait");
+ }
+ success = 1;
+ }
+
+ if (success) thelock->locked = 1;
+ status = pthread_mutex_unlock( &thelock->mut );
+ CHECK_STATUS("pthread_mutex_unlock[1]");
+ }
if (error) success = 0;
dprintf(("PyThread_acquire_lock(%p, %d) -> %d\n", lock, waitflag, success));