@@ -1247,50 +1247,56 @@ def __del__(self):
12471247 self .assertEqual (err , b"" )
12481248 self .assertIn (b"all clear" , out )
12491249
1250- def test_acquire_daemon_thread_lock_in_finalization (self ):
1250+ @support .subTests ('lock_class_name' , ['Lock' , 'RLock' ])
1251+ def test_acquire_daemon_thread_lock_in_finalization (self , lock_class_name ):
12511252 # gh-123940: Py_Finalize() prevents other threads from running Python
12521253 # code (and so, releasing locks), so acquiring a locked lock can not
12531254 # succeed.
12541255 # We raise an exception rather than hang.
1255- for timeout in (None , 10 ):
1256- with self .subTest (timeout = timeout ):
1257- code = textwrap .dedent (f"""
1258- import threading
1259- import time
1256+ code = textwrap .dedent (f"""
1257+ import threading
1258+ import time
12601259
1261- thread_started_event = threading.Event()
1260+ thread_started_event = threading.Event()
12621261
1263- lock = threading.Lock ()
1264- def loop():
1265- with lock:
1266- thread_started_event.set()
1267- while True:
1268- time.sleep(1)
1262+ lock = threading.{ lock_class_name } ()
1263+ def loop():
1264+ with lock:
1265+ thread_started_event.set()
1266+ while True:
1267+ time.sleep(1)
12691268
1270- class Cycle:
1271- def __init__(self):
1272- self.self_ref = self
1273- self.thr = threading.Thread(
1274- target=loop, daemon=True)
1275- self.thr.start()
1276- thread_started_event.wait()
1269+ uncontested_lock = threading.{ lock_class_name } ()
12771270
1278- def __del__(self) :
1279- assert self.thr.is_alive()
1280- try:
1281- lock.acquire()
1282- except PythonFinalizationError:
1283- assert self.thr.is_alive ()
1284- print('got the correct exception!' )
1271+ class Cycle :
1272+ def __init__(self):
1273+ self.self_ref = self
1274+ self.thr = threading.Thread(
1275+ target=loop, daemon=True)
1276+ self.thr.start ()
1277+ thread_started_event.wait( )
12851278
1286- # Cycle holds a reference to itself, which ensures it is
1287- # cleaned up during the GC that runs after daemon threads
1288- # have been forced to exit during finalization.
1289- Cycle()
1290- """ )
1291- rc , out , err = assert_python_ok ("-c" , code )
1292- self .assertEqual (err , b"" )
1293- self .assertIn (b"got the correct exception" , out )
1279+ def __del__(self):
1280+ assert self.thr.is_alive()
1281+
1282+ # We *can* acquire an unlocked lock
1283+ uncontested_lock.acquire()
1284+
1285+ # Acquiring a locked one fails
1286+ try:
1287+ lock.acquire()
1288+ except PythonFinalizationError:
1289+ assert self.thr.is_alive()
1290+ print('got the correct exception!')
1291+
1292+ # Cycle holds a reference to itself, which ensures it is
1293+ # cleaned up during the GC that runs after daemon threads
1294+ # have been forced to exit during finalization.
1295+ Cycle()
1296+ """ )
1297+ rc , out , err = assert_python_ok ("-c" , code )
1298+ self .assertEqual (err , b"" )
1299+ self .assertIn (b"got the correct exception" , out )
12941300
12951301 def test_start_new_thread_failed (self ):
12961302 # gh-109746: if Python fails to start newly created thread
0 commit comments