]> granicus.if.org Git - python/commitdiff
bpo-36688: Adding an implementation of RLock in _dummy_thread (GH-12943)
authorMiss Islington (bot) <31488909+miss-islington@users.noreply.github.com>
Mon, 17 Jun 2019 08:34:27 +0000 (01:34 -0700)
committerGitHub <noreply@github.com>
Mon, 17 Jun 2019 08:34:27 +0000 (01:34 -0700)
(cherry picked from commit c5905f39bcf4ef895d42eede41bb5a2f071a501d)

Co-authored-by: Joost Lek <vlabakje@gmail.com>
Lib/_dummy_thread.py
Lib/test/test_dummy_thread.py

index a2cae54b0580db35ead36382ad6517c4c03bf4d9..2e46a07603be0916535c47adb8f979501ff794b9 100644 (file)
@@ -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"
index da512167834f7f0cb8c337160acc8485885fa58f..0f56fcf9733638b5c480456926c478ef31421b77 100644 (file)
@@ -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()