Skip to content

Commit

Permalink
bpo-36688: Adding an implementation of RLock in _dummy_thread (GH-12943)
Browse files Browse the repository at this point in the history
(cherry picked from commit c5905f3)

Co-authored-by: Joost Lek <vlabakje@gmail.com>
  • Loading branch information
miss-islington and vlabakje committed Jun 17, 2019
1 parent e784f9f commit ad50591
Show file tree
Hide file tree
Showing 2 changed files with 52 additions and 1 deletion.
32 changes: 31 additions & 1 deletion Lib/_dummy_thread.py
Expand Up @@ -14,7 +14,7 @@
# 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
Expand Down Expand Up @@ -148,6 +148,36 @@ def __repr__(self):
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"
Expand Down
21 changes: 21 additions & 0 deletions Lib/test/test_dummy_thread.py
Expand Up @@ -102,6 +102,24 @@ def test_lock_representation(self):
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."""

Expand Down Expand Up @@ -253,3 +271,6 @@ def test_RaiseException(self, mock_print_exc):
func = mock.Mock(side_effect=Exception)
_thread.start_new_thread(func, tuple())
self.assertTrue(mock_print_exc.called)

if __name__ == '__main__':
unittest.main()

0 comments on commit ad50591

Please sign in to comment.