@@ -115,6 +115,7 @@ def tearDown(self):
115
115
116
116
117
117
class ThreadTests (BaseTestCase ):
118
+ maxDiff = 9999
118
119
119
120
@cpython_only
120
121
def test_name (self ):
@@ -627,19 +628,25 @@ def test_main_thread_after_fork(self):
627
628
import os, threading
628
629
from test import support
629
630
631
+ ident = threading.get_ident()
630
632
pid = os.fork()
631
633
if pid == 0:
634
+ print("current ident", threading.get_ident() == ident)
632
635
main = threading.main_thread()
633
- print(main.name)
634
- print(main.ident == threading.current_thread(). ident)
635
- print(main.ident == threading.get_ident() )
636
+ print("main", main.name)
637
+ print(" main ident", main .ident == ident)
638
+ print("current is main", threading.current_thread() is main )
636
639
else:
637
640
support.wait_process(pid, exitcode=0)
638
641
"""
639
642
_ , out , err = assert_python_ok ("-c" , code )
640
643
data = out .decode ().replace ('\r ' , '' )
641
644
self .assertEqual (err , b"" )
642
- self .assertEqual (data , "MainThread\n True\n True\n " )
645
+ self .assertEqual (data ,
646
+ "current ident True\n "
647
+ "main MainThread\n "
648
+ "main ident True\n "
649
+ "current is main True\n " )
643
650
644
651
@skip_unless_reliable_fork
645
652
@unittest .skipUnless (hasattr (os , 'waitpid' ), "test needs os.waitpid()" )
@@ -649,15 +656,17 @@ def test_main_thread_after_fork_from_nonmain_thread(self):
649
656
from test import support
650
657
651
658
def func():
659
+ ident = threading.get_ident()
652
660
with warnings.catch_warnings(record=True) as ws:
653
661
warnings.filterwarnings(
654
662
"always", category=DeprecationWarning)
655
663
pid = os.fork()
656
664
if pid == 0:
665
+ print("current ident", threading.get_ident() == ident)
657
666
main = threading.main_thread()
658
- print(main.name)
659
- print(main.ident == threading.current_thread(). ident)
660
- print(main.ident == threading.get_ident() )
667
+ print(" main", main .name, type(main).__name__ )
668
+ print(" main ident", main .ident == ident)
669
+ print("current is main", threading.current_thread() is main )
661
670
# stdout is fully buffered because not a tty,
662
671
# we have to flush before exit.
663
672
sys.stdout.flush()
@@ -673,7 +682,80 @@ def func():
673
682
_ , out , err = assert_python_ok ("-c" , code )
674
683
data = out .decode ().replace ('\r ' , '' )
675
684
self .assertEqual (err .decode ('utf-8' ), "" )
676
- self .assertEqual (data , "Thread-1 (func)\n True\n True\n " )
685
+ self .assertEqual (data ,
686
+ "current ident True\n "
687
+ "main Thread-1 (func) Thread\n "
688
+ "main ident True\n "
689
+ "current is main True\n "
690
+ )
691
+
692
+ @unittest .skipIf (sys .platform in platforms_to_skip , "due to known OS bug" )
693
+ @support .requires_fork ()
694
+ @unittest .skipUnless (hasattr (os , 'waitpid' ), "test needs os.waitpid()" )
695
+ def test_main_thread_after_fork_from_foreign_thread (self , create_dummy = False ):
696
+ code = """if 1:
697
+ import os, threading, sys, traceback, _thread
698
+ from test import support
699
+
700
+ def func(lock):
701
+ ident = threading.get_ident()
702
+ if %s:
703
+ # call current_thread() before fork to allocate DummyThread
704
+ current = threading.current_thread()
705
+ print("current", current.name, type(current).__name__)
706
+ print("ident in _active", ident in threading._active)
707
+ # flush before fork, so child won't flush it again
708
+ sys.stdout.flush()
709
+ pid = os.fork()
710
+ if pid == 0:
711
+ print("current ident", threading.get_ident() == ident)
712
+ main = threading.main_thread()
713
+ print("main", main.name, type(main).__name__)
714
+ print("main ident", main.ident == ident)
715
+ print("current is main", threading.current_thread() is main)
716
+ print("_dangling", [t.name for t in list(threading._dangling)])
717
+ # stdout is fully buffered because not a tty,
718
+ # we have to flush before exit.
719
+ sys.stdout.flush()
720
+ try:
721
+ threading._shutdown()
722
+ os._exit(0)
723
+ except:
724
+ traceback.print_exc()
725
+ sys.stderr.flush()
726
+ os._exit(1)
727
+ else:
728
+ try:
729
+ support.wait_process(pid, exitcode=0)
730
+ except Exception:
731
+ # avoid 'could not acquire lock for
732
+ # <_io.BufferedWriter name='<stderr>'> at interpreter shutdown,'
733
+ traceback.print_exc()
734
+ sys.stderr.flush()
735
+ finally:
736
+ lock.release()
737
+
738
+ join_lock = _thread.allocate_lock()
739
+ join_lock.acquire()
740
+ th = _thread.start_new_thread(func, (join_lock,))
741
+ join_lock.acquire()
742
+ """ % create_dummy
743
+ # "DeprecationWarning: This process is multi-threaded, use of fork()
744
+ # may lead to deadlocks in the child"
745
+ _ , out , err = assert_python_ok ("-W" , "ignore::DeprecationWarning" , "-c" , code )
746
+ data = out .decode ().replace ('\r ' , '' )
747
+ self .assertEqual (err .decode (), "" )
748
+ self .assertEqual (data ,
749
+ ("current Dummy-1 _DummyThread\n " if create_dummy else "" ) +
750
+ f"ident in _active { create_dummy !s} \n " +
751
+ "current ident True\n "
752
+ "main MainThread _MainThread\n "
753
+ "main ident True\n "
754
+ "current is main True\n "
755
+ "_dangling ['MainThread']\n " )
756
+
757
+ def test_main_thread_after_fork_from_dummy_thread (self , create_dummy = False ):
758
+ self .test_main_thread_after_fork_from_foreign_thread (create_dummy = True )
677
759
678
760
def test_main_thread_during_shutdown (self ):
679
761
# bpo-31516: current_thread() should still point to the main thread
0 commit comments