summaryrefslogtreecommitdiffstats
path: root/Lib/test/lock_tests.py
diff options
context:
space:
mode:
authorVictor Stinner <vstinner@python.org>2020-04-07 21:11:49 (GMT)
committerGitHub <noreply@github.com>2020-04-07 21:11:49 (GMT)
commit87255be6964979b5abdc4b9dcf81cdcfdad6e753 (patch)
tree30f3c5a680dd7ed6435841ecd38166de7654503e /Lib/test/lock_tests.py
parent48b069a003ba6c684a9ba78493fbbec5e89f10b8 (diff)
downloadcpython-87255be6964979b5abdc4b9dcf81cdcfdad6e753.zip
cpython-87255be6964979b5abdc4b9dcf81cdcfdad6e753.tar.gz
cpython-87255be6964979b5abdc4b9dcf81cdcfdad6e753.tar.bz2
bpo-40089: Add _at_fork_reinit() method to locks (GH-19195)
Add a private _at_fork_reinit() method to _thread.Lock, _thread.RLock, threading.RLock and threading.Condition classes: reinitialize the lock after fork in the child process; reset the lock to the unlocked state. Rename also the private _reset_internal_locks() method of threading.Event to _at_fork_reinit(). * Add _PyThread_at_fork_reinit() private function. It is excluded from the limited C API. * threading.Thread._reset_internal_locks() now calls _at_fork_reinit() on self._tstate_lock rather than creating a new Python lock object.
Diffstat (limited to 'Lib/test/lock_tests.py')
-rw-r--r--Lib/test/lock_tests.py30
1 files changed, 28 insertions, 2 deletions
diff --git a/Lib/test/lock_tests.py b/Lib/test/lock_tests.py
index cd1155d..b397525 100644
--- a/Lib/test/lock_tests.py
+++ b/Lib/test/lock_tests.py
@@ -2,6 +2,7 @@
Various tests for synchronization primitives.
"""
+import os
import sys
import time
from _thread import start_new_thread, TIMEOUT_MAX
@@ -12,6 +13,11 @@ import weakref
from test import support
+requires_fork = unittest.skipUnless(hasattr(os, 'fork'),
+ "platform doesn't support fork "
+ "(no _at_fork_reinit method)")
+
+
def _wait():
# A crude wait/yield function not relying on synchronization primitives.
time.sleep(0.01)
@@ -265,6 +271,25 @@ class LockTests(BaseLockTests):
self.assertFalse(lock.locked())
self.assertTrue(lock.acquire(blocking=False))
+ @requires_fork
+ def test_at_fork_reinit(self):
+ def use_lock(lock):
+ # make sure that the lock still works normally
+ # after _at_fork_reinit()
+ lock.acquire()
+ lock.release()
+
+ # unlocked
+ lock = self.locktype()
+ lock._at_fork_reinit()
+ use_lock(lock)
+
+ # locked: _at_fork_reinit() resets the lock to the unlocked state
+ lock2 = self.locktype()
+ lock2.acquire()
+ lock2._at_fork_reinit()
+ use_lock(lock2)
+
class RLockTests(BaseLockTests):
"""
@@ -417,12 +442,13 @@ class EventTests(BaseTestCase):
b.wait_for_finished()
self.assertEqual(results, [True] * N)
- def test_reset_internal_locks(self):
+ @requires_fork
+ def test_at_fork_reinit(self):
# ensure that condition is still using a Lock after reset
evt = self.eventtype()
with evt._cond:
self.assertFalse(evt._cond.acquire(False))
- evt._reset_internal_locks()
+ evt._at_fork_reinit()
with evt._cond:
self.assertFalse(evt._cond.acquire(False))