diff options
author | Miss Islington (bot) <31488909+miss-islington@users.noreply.github.com> | 2019-06-17 08:34:27 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-06-17 08:34:27 (GMT) |
commit | ad505918a1829e6fa2a48a7665234d60a9377e98 (patch) | |
tree | 5d6d1314baf3721c467f61ba5092da4eef395fc0 /Lib | |
parent | e784f9f1c3fdd2102aae3fc0fe226408ff3a6029 (diff) | |
download | cpython-ad505918a1829e6fa2a48a7665234d60a9377e98.zip cpython-ad505918a1829e6fa2a48a7665234d60a9377e98.tar.gz cpython-ad505918a1829e6fa2a48a7665234d60a9377e98.tar.bz2 |
bpo-36688: Adding an implementation of RLock in _dummy_thread (GH-12943)
(cherry picked from commit c5905f39bcf4ef895d42eede41bb5a2f071a501d)
Co-authored-by: Joost Lek <vlabakje@gmail.com>
Diffstat (limited to 'Lib')
-rw-r--r-- | Lib/_dummy_thread.py | 32 | ||||
-rw-r--r-- | Lib/test/test_dummy_thread.py | 21 |
2 files changed, 52 insertions, 1 deletions
diff --git a/Lib/_dummy_thread.py b/Lib/_dummy_thread.py index a2cae54..2e46a07 100644 --- a/Lib/_dummy_thread.py +++ b/Lib/_dummy_thread.py @@ -14,7 +14,7 @@ Suggested usage is:: # Exports only things specified by thread documentation; # skipping obsolete synonyms allocate(), start_new(), exit_thread(). __all__ = ['error', 'start_new_thread', 'exit', 'get_ident', 'allocate_lock', - 'interrupt_main', 'LockType'] + 'interrupt_main', 'LockType', 'RLock'] # A dummy value TIMEOUT_MAX = 2**31 @@ -148,6 +148,36 @@ class LockType(object): hex(id(self)) ) + +class RLock(LockType): + """Dummy implementation of threading._RLock. + + Re-entrant lock can be aquired multiple times and needs to be released + just as many times. This dummy implemention does not check wheter the + current thread actually owns the lock, but does accounting on the call + counts. + """ + def __init__(self): + super().__init__() + self._levels = 0 + + def acquire(self, waitflag=None, timeout=-1): + """Aquire the lock, can be called multiple times in succession. + """ + locked = super().acquire(waitflag, timeout) + if locked: + self._levels += 1 + return locked + + def release(self): + """Release needs to be called once for every call to acquire(). + """ + if self._levels == 0: + raise error + if self._levels == 1: + super().release() + self._levels -= 1 + # Used to signal that interrupt_main was called in a "thread" _interrupt = False # True when not executing in a "thread" diff --git a/Lib/test/test_dummy_thread.py b/Lib/test/test_dummy_thread.py index da51216..0f56fcf 100644 --- a/Lib/test/test_dummy_thread.py +++ b/Lib/test/test_dummy_thread.py @@ -102,6 +102,24 @@ class LockTests(unittest.TestCase): self.assertIn("unlocked", repr(self.lock)) +class RLockTests(unittest.TestCase): + """Test dummy RLock objects.""" + + def setUp(self): + self.rlock = _thread.RLock() + + def test_multiple_acquire(self): + self.assertIn("unlocked", repr(self.rlock)) + self.rlock.acquire() + self.rlock.acquire() + self.assertIn("locked", repr(self.rlock)) + self.rlock.release() + self.assertIn("locked", repr(self.rlock)) + self.rlock.release() + self.assertIn("unlocked", repr(self.rlock)) + self.assertRaises(RuntimeError, self.rlock.release) + + class MiscTests(unittest.TestCase): """Miscellaneous tests.""" @@ -253,3 +271,6 @@ class ThreadTests(unittest.TestCase): func = mock.Mock(side_effect=Exception) _thread.start_new_thread(func, tuple()) self.assertTrue(mock_print_exc.called) + +if __name__ == '__main__': + unittest.main() |