@@ -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 ):
@@ -676,19 +677,25 @@ def test_main_thread_after_fork(self):
676
677
import os, threading
677
678
from test import support
678
679
680
+ ident = threading.get_ident()
679
681
pid = os.fork()
680
682
if pid == 0:
683
+ print("current ident", threading.get_ident() == ident)
681
684
main = threading.main_thread()
682
- print(main.name)
683
- print(main.ident == threading.current_thread(). ident)
684
- print(main.ident == threading.get_ident() )
685
+ print("main", main.name)
686
+ print(" main ident", main .ident == ident)
687
+ print("current is main", threading.current_thread() is main )
685
688
else:
686
689
support.wait_process(pid, exitcode=0)
687
690
"""
688
691
_ , out , err = assert_python_ok ("-c" , code )
689
692
data = out .decode ().replace ('\r ' , '' )
690
693
self .assertEqual (err , b"" )
691
- self .assertEqual (data , "MainThread\n True\n True\n " )
694
+ self .assertEqual (data ,
695
+ "current ident True\n "
696
+ "main MainThread\n "
697
+ "main ident True\n "
698
+ "current is main True\n " )
692
699
693
700
@skip_unless_reliable_fork
694
701
@unittest .skipUnless (hasattr (os , 'waitpid' ), "test needs os.waitpid()" )
@@ -698,15 +705,17 @@ def test_main_thread_after_fork_from_nonmain_thread(self):
698
705
from test import support
699
706
700
707
def func():
708
+ ident = threading.get_ident()
701
709
with warnings.catch_warnings(record=True) as ws:
702
710
warnings.filterwarnings(
703
711
"always", category=DeprecationWarning)
704
712
pid = os.fork()
705
713
if pid == 0:
714
+ print("current ident", threading.get_ident() == ident)
706
715
main = threading.main_thread()
707
- print(main.name)
708
- print(main.ident == threading.current_thread(). ident)
709
- print(main.ident == threading.get_ident() )
716
+ print(" main", main .name, type(main).__name__ )
717
+ print(" main ident", main .ident == ident)
718
+ print("current is main", threading.current_thread() is main )
710
719
# stdout is fully buffered because not a tty,
711
720
# we have to flush before exit.
712
721
sys.stdout.flush()
@@ -722,7 +731,80 @@ def func():
722
731
_ , out , err = assert_python_ok ("-c" , code )
723
732
data = out .decode ().replace ('\r ' , '' )
724
733
self .assertEqual (err .decode ('utf-8' ), "" )
725
- self .assertEqual (data , "Thread-1 (func)\n True\n True\n " )
734
+ self .assertEqual (data ,
735
+ "current ident True\n "
736
+ "main Thread-1 (func) Thread\n "
737
+ "main ident True\n "
738
+ "current is main True\n "
739
+ )
740
+
741
+ @unittest .skipIf (sys .platform in platforms_to_skip , "due to known OS bug" )
742
+ @support .requires_fork ()
743
+ @unittest .skipUnless (hasattr (os , 'waitpid' ), "test needs os.waitpid()" )
744
+ def test_main_thread_after_fork_from_foreign_thread (self , create_dummy = False ):
745
+ code = """if 1:
746
+ import os, threading, sys, traceback, _thread
747
+ from test import support
748
+
749
+ def func(lock):
750
+ ident = threading.get_ident()
751
+ if %s:
752
+ # call current_thread() before fork to allocate DummyThread
753
+ current = threading.current_thread()
754
+ print("current", current.name, type(current).__name__)
755
+ print("ident in _active", ident in threading._active)
756
+ # flush before fork, so child won't flush it again
757
+ sys.stdout.flush()
758
+ pid = os.fork()
759
+ if pid == 0:
760
+ print("current ident", threading.get_ident() == ident)
761
+ main = threading.main_thread()
762
+ print("main", main.name, type(main).__name__)
763
+ print("main ident", main.ident == ident)
764
+ print("current is main", threading.current_thread() is main)
765
+ print("_dangling", [t.name for t in list(threading._dangling)])
766
+ # stdout is fully buffered because not a tty,
767
+ # we have to flush before exit.
768
+ sys.stdout.flush()
769
+ try:
770
+ threading._shutdown()
771
+ os._exit(0)
772
+ except:
773
+ traceback.print_exc()
774
+ sys.stderr.flush()
775
+ os._exit(1)
776
+ else:
777
+ try:
778
+ support.wait_process(pid, exitcode=0)
779
+ except Exception:
780
+ # avoid 'could not acquire lock for
781
+ # <_io.BufferedWriter name='<stderr>'> at interpreter shutdown,'
782
+ traceback.print_exc()
783
+ sys.stderr.flush()
784
+ finally:
785
+ lock.release()
786
+
787
+ join_lock = _thread.allocate_lock()
788
+ join_lock.acquire()
789
+ th = _thread.start_new_thread(func, (join_lock,))
790
+ join_lock.acquire()
791
+ """ % create_dummy
792
+ # "DeprecationWarning: This process is multi-threaded, use of fork()
793
+ # may lead to deadlocks in the child"
794
+ _ , out , err = assert_python_ok ("-W" , "ignore::DeprecationWarning" , "-c" , code )
795
+ data = out .decode ().replace ('\r ' , '' )
796
+ self .assertEqual (err .decode (), "" )
797
+ self .assertEqual (data ,
798
+ ("current Dummy-1 _DummyThread\n " if create_dummy else "" ) +
799
+ f"ident in _active { create_dummy !s} \n " +
800
+ "current ident True\n "
801
+ "main MainThread _MainThread\n "
802
+ "main ident True\n "
803
+ "current is main True\n "
804
+ "_dangling ['MainThread']\n " )
805
+
806
+ def test_main_thread_after_fork_from_dummy_thread (self , create_dummy = False ):
807
+ self .test_main_thread_after_fork_from_foreign_thread (create_dummy = True )
726
808
727
809
def test_main_thread_during_shutdown (self ):
728
810
# bpo-31516: current_thread() should still point to the main thread
0 commit comments