patcher: set locked RLocks' owner only when patching existing locks
For Python 2, patching existing locks replaces RLock._RLock__owner with current thread ID no matter the old lock is locked or not and thus an unlocked RLock would have a non None owner (e.g. <_RLock owner=140106584489808 count=0>). Then if we acquire the RLock in the same thread, the method RLock.acquire would not invoke the _RLock__block.acquire() since it treats this is a recursive acquire by checking current thread ID. And then the following RLock.release would invoke the _RLock__block.release method resulting in the counter of Semaphore being improved to 2. There should be only two states being expected for RLock: 1. owner != None and count > 0 2. owner == None and count == 0 This patch fixs it by only setting locked RLocks' owner during patching.
This commit is contained in:
parent
7f53465578
commit
f72cc96a70
|
@ -358,7 +358,7 @@ def _fix_py2_rlock(rlock, tid):
|
|||
rlock._RLock__block = new
|
||||
if old.locked():
|
||||
new.acquire()
|
||||
rlock._RLock__owner = tid
|
||||
rlock._RLock__owner = tid
|
||||
|
||||
|
||||
def _fix_py3_rlock(old):
|
||||
|
|
|
@ -123,6 +123,15 @@ def skip_if_no_itimer(func):
|
|||
return skip_unless(has_itimer)(func)
|
||||
|
||||
|
||||
def skip_if_CRLock_exist(func):
|
||||
""" Decorator that skips a test if the `_thread.RLock` class exists """
|
||||
try:
|
||||
from _thread import RLock
|
||||
return skipped(func)
|
||||
except ImportError:
|
||||
return func
|
||||
|
||||
|
||||
def skip_if_no_ssl(func):
|
||||
""" Decorator that skips a test if SSL is not available."""
|
||||
try:
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
__test__ = False
|
||||
|
||||
|
||||
def take(lock, e1, e2):
|
||||
with lock:
|
||||
e1.set()
|
||||
e2.wait()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
import sys
|
||||
import threading
|
||||
lock = threading.RLock()
|
||||
import eventlet
|
||||
eventlet.monkey_patch()
|
||||
|
||||
lock.acquire()
|
||||
lock.release()
|
||||
|
||||
e1, e2 = threading.Event(), threading.Event()
|
||||
eventlet.spawn(take, lock, e1, e2)
|
||||
e1.wait()
|
||||
assert not lock.acquire(blocking=0)
|
||||
e2.set()
|
||||
print('pass')
|
|
@ -493,6 +493,11 @@ def test_patcher_existing_locks_locked():
|
|||
tests.run_isolated('patcher_existing_locks_locked.py')
|
||||
|
||||
|
||||
@tests.skip_if_CRLock_exist
|
||||
def test_patcher_existing_locks_unlocked():
|
||||
tests.run_isolated('patcher_existing_locks_unlocked.py')
|
||||
|
||||
|
||||
def test_importlib_lock():
|
||||
tests.run_isolated('patcher_importlib_lock.py')
|
||||
|
||||
|
|
Loading…
Reference in New Issue