summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEric Snow <ericsnowcurrently@gmail.com>2023-11-28 02:01:05 (GMT)
committerGitHub <noreply@github.com>2023-11-28 02:01:05 (GMT)
commit0122b4d7c92855e97912cf827dd81d836725c9a4 (patch)
tree4a1e3355d8bf5e9d2b9f36745518f56f590df021
parent82ae5a609d9a2c0ff2384527a18ff1caf7410052 (diff)
downloadcpython-0122b4d7c92855e97912cf827dd81d836725c9a4.zip
cpython-0122b4d7c92855e97912cf827dd81d836725c9a4.tar.gz
cpython-0122b4d7c92855e97912cf827dd81d836725c9a4.tar.bz2
[3.12] gh-105716: Support Background Threads in Subinterpreters Consistently (gh-109921) (gh-110707)
The existence of background threads running on a subinterpreter was preventing interpreters from getting properly destroyed, as well as impacting the ability to run the interpreter again. It also affected how we wait for non-daemon threads to finish. We add PyInterpreterState.threads.main, with some internal C-API functions. (cherry-picked from commit 1dd9dee45d2591b4e701039d1673282380696849)
-rw-r--r--Doc/data/python3.12.abi228
-rw-r--r--Include/internal/pycore_interp.h2
-rw-r--r--Include/internal/pycore_pystate.h5
-rw-r--r--Lib/test/test_interpreters.py97
-rw-r--r--Lib/test/test_threading.py49
-rw-r--r--Lib/threading.py4
-rw-r--r--Misc/NEWS.d/next/Core and Builtins/2023-09-26-14-00-25.gh-issue-105716.SUJkW1.rst3
-rw-r--r--Modules/_threadmodule.c16
-rw-r--r--Modules/_xxsubinterpretersmodule.c90
-rw-r--r--Modules/main.c4
-rw-r--r--Python/pystate.c37
11 files changed, 385 insertions, 150 deletions
diff --git a/Doc/data/python3.12.abi b/Doc/data/python3.12.abi
index 6abf43c..b3a07fd 100644
--- a/Doc/data/python3.12.abi
+++ b/Doc/data/python3.12.abi
@@ -1124,11 +1124,14 @@
<elf-symbol name='_PyInterpreterState_IDDecref' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='_PyInterpreterState_IDIncref' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='_PyInterpreterState_IDInitref' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
+ <elf-symbol name='_PyInterpreterState_IsRunningMain' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='_PyInterpreterState_LookUpID' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='_PyInterpreterState_RequireIDRef' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='_PyInterpreterState_RequiresIDRef' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='_PyInterpreterState_SetConfig' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='_PyInterpreterState_SetEvalFrameFunc' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
+ <elf-symbol name='_PyInterpreterState_SetNotRunningMain' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
+ <elf-symbol name='_PyInterpreterState_SetRunningMain' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='_PyList_DebugMallocStats' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='_PyList_Extend' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='_PyLong_AsByteArray' type='func-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
@@ -1707,7 +1710,7 @@
<elf-symbol name='_PyNotImplemented_Type' size='416' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='_PyOS_ReadlineTState' size='8' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='_PyParser_TokenNames' size='552' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
- <elf-symbol name='_PyRuntime' size='459920' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
+ <elf-symbol name='_PyRuntime' size='459928' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='_PySet_Dummy' size='8' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='_PyWeakref_CallableProxyType' size='416' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
<elf-symbol name='_PyWeakref_ProxyType' size='416' type='object-type' binding='global-binding' visibility='default-visibility' is-defined='yes'/>
@@ -2534,11 +2537,11 @@
<parameter type-id='type-id-20'/>
<return type-id='type-id-54'/>
</function-decl>
- <function-decl name='_PyInterpreterState_DeleteExceptMain' filepath='./Include/internal/pycore_pystate.h' line='151' column='1' visibility='default' binding='global' size-in-bits='64'>
+ <function-decl name='_PyInterpreterState_DeleteExceptMain' filepath='./Include/internal/pycore_pystate.h' line='156' column='1' visibility='default' binding='global' size-in-bits='64'>
<parameter type-id='type-id-178'/>
<return type-id='type-id-54'/>
</function-decl>
- <function-decl name='_PySignal_AfterFork' filepath='./Include/internal/pycore_pystate.h' line='152' column='1' visibility='default' binding='global' size-in-bits='64'>
+ <function-decl name='_PySignal_AfterFork' filepath='./Include/internal/pycore_pystate.h' line='157' column='1' visibility='default' binding='global' size-in-bits='64'>
<return type-id='type-id-46'/>
</function-decl>
<function-decl name='_PyRuntimeState_ReInitThreads' filepath='./Include/internal/pycore_runtime.h' line='201' column='1' visibility='default' binding='global' size-in-bits='64'>
@@ -3926,17 +3929,17 @@
<parameter type-id='type-id-8'/>
<return type-id='type-id-8'/>
</function-decl>
- <function-decl name='Py_RunMain' mangled-name='Py_RunMain' filepath='Modules/main.c' line='701' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='Py_RunMain'>
+ <function-decl name='Py_RunMain' mangled-name='Py_RunMain' filepath='Modules/main.c' line='705' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='Py_RunMain'>
<return type-id='type-id-8'/>
</function-decl>
- <function-decl name='Py_Main' mangled-name='Py_Main' filepath='Modules/main.c' line='740' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='Py_Main'>
- <parameter type-id='type-id-8' name='argc' filepath='Modules/main.c' line='740' column='1'/>
- <parameter type-id='type-id-235' name='argv' filepath='Modules/main.c' line='740' column='1'/>
+ <function-decl name='Py_Main' mangled-name='Py_Main' filepath='Modules/main.c' line='744' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='Py_Main'>
+ <parameter type-id='type-id-8' name='argc' filepath='Modules/main.c' line='744' column='1'/>
+ <parameter type-id='type-id-235' name='argv' filepath='Modules/main.c' line='744' column='1'/>
<return type-id='type-id-8'/>
</function-decl>
- <function-decl name='Py_BytesMain' mangled-name='Py_BytesMain' filepath='Modules/main.c' line='752' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='Py_BytesMain'>
- <parameter type-id='type-id-8' name='argc' filepath='Modules/main.c' line='752' column='1'/>
- <parameter type-id='type-id-239' name='argv' filepath='Modules/main.c' line='752' column='1'/>
+ <function-decl name='Py_BytesMain' mangled-name='Py_BytesMain' filepath='Modules/main.c' line='756' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='Py_BytesMain'>
+ <parameter type-id='type-id-8' name='argc' filepath='Modules/main.c' line='756' column='1'/>
+ <parameter type-id='type-id-239' name='argv' filepath='Modules/main.c' line='756' column='1'/>
<return type-id='type-id-8'/>
</function-decl>
</abi-instr>
@@ -7563,19 +7566,19 @@
</abi-instr>
<abi-instr address-size='64' path='Objects/interpreteridobject.c' comp-dir-path='/home/runner/work/cpython/cpython' language='LANG_C11'>
<var-decl name='_PyInterpreterID_Type' type-id='type-id-256' mangled-name='_PyInterpreterID_Type' visibility='default' filepath='./Include/cpython/interpreteridobject.h' line='7' column='1' elf-symbol-id='_PyInterpreterID_Type'/>
- <function-decl name='_PyInterpreterState_LookUpID' mangled-name='_PyInterpreterState_LookUpID' filepath='./Include/internal/pycore_interp.h' line='251' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyInterpreterState_LookUpID'>
+ <function-decl name='_PyInterpreterState_LookUpID' mangled-name='_PyInterpreterState_LookUpID' filepath='./Include/internal/pycore_interp.h' line='253' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyInterpreterState_LookUpID'>
<parameter type-id='type-id-377'/>
<return type-id='type-id-20'/>
</function-decl>
- <function-decl name='_PyInterpreterState_IDInitref' mangled-name='_PyInterpreterState_IDInitref' filepath='./Include/internal/pycore_interp.h' line='253' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyInterpreterState_IDInitref'>
+ <function-decl name='_PyInterpreterState_IDInitref' mangled-name='_PyInterpreterState_IDInitref' filepath='./Include/internal/pycore_interp.h' line='255' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyInterpreterState_IDInitref'>
<parameter type-id='type-id-20'/>
<return type-id='type-id-8'/>
</function-decl>
- <function-decl name='_PyInterpreterState_IDIncref' mangled-name='_PyInterpreterState_IDIncref' filepath='./Include/internal/pycore_interp.h' line='254' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyInterpreterState_IDIncref'>
+ <function-decl name='_PyInterpreterState_IDIncref' mangled-name='_PyInterpreterState_IDIncref' filepath='./Include/internal/pycore_interp.h' line='256' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyInterpreterState_IDIncref'>
<parameter type-id='type-id-20'/>
<return type-id='type-id-8'/>
</function-decl>
- <function-decl name='_PyInterpreterState_IDDecref' mangled-name='_PyInterpreterState_IDDecref' filepath='./Include/internal/pycore_interp.h' line='255' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyInterpreterState_IDDecref'>
+ <function-decl name='_PyInterpreterState_IDDecref' mangled-name='_PyInterpreterState_IDDecref' filepath='./Include/internal/pycore_interp.h' line='257' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyInterpreterState_IDDecref'>
<parameter type-id='type-id-20'/>
<return type-id='type-id-46'/>
</function-decl>
@@ -16067,7 +16070,7 @@
<var-decl name='max_str_digits' type-id='type-id-8' visibility='default' filepath='./Include/internal/pycore_interp.h' line='39' column='1'/>
</data-member>
</class-decl>
- <class-decl name='_is' size-in-bits='3068224' is-struct='yes' visibility='default' filepath='./Include/internal/pycore_interp.h' line='49' column='1' id='type-id-935'>
+ <class-decl name='_is' size-in-bits='3068288' is-struct='yes' visibility='default' filepath='./Include/internal/pycore_interp.h' line='49' column='1' id='type-id-935'>
<data-member access='public' layout-offset-in-bits='0'>
<var-decl name='next' type-id='type-id-20' visibility='default' filepath='./Include/internal/pycore_interp.h' line='51' column='1'/>
</data-member>
@@ -16276,10 +16279,13 @@
<var-decl name='static_objects' type-id='type-id-875' visibility='default' filepath='./Include/internal/pycore_interp.h' line='195' column='1'/>
</data-member>
<data-member access='public' layout-offset-in-bits='3065856'>
- <var-decl name='_finalizing_id' type-id='type-id-819' visibility='default' filepath='./Include/internal/pycore_interp.h' line='199' column='1'/>
+ <var-decl name='threads_main' type-id='type-id-177' visibility='default' filepath='./Include/internal/pycore_interp.h' line='198' column='1'/>
</data-member>
<data-member access='public' layout-offset-in-bits='3065920'>
- <var-decl name='_initial_thread' type-id='type-id-945' visibility='default' filepath='./Include/internal/pycore_interp.h' line='202' column='1'/>
+ <var-decl name='_finalizing_id' type-id='type-id-819' visibility='default' filepath='./Include/internal/pycore_interp.h' line='201' column='1'/>
+ </data-member>
+ <data-member access='public' layout-offset-in-bits='3065984'>
+ <var-decl name='_initial_thread' type-id='type-id-945' visibility='default' filepath='./Include/internal/pycore_interp.h' line='204' column='1'/>
</data-member>
</class-decl>
<class-decl name='pythreads' size-in-bits='256' is-struct='yes' visibility='default' filepath='./Include/internal/pycore_interp.h' line='67' column='1' id='type-id-936'>
@@ -16296,18 +16302,18 @@
<var-decl name='stacksize' type-id='type-id-19' visibility='default' filepath='./Include/internal/pycore_interp.h' line='77' column='1'/>
</data-member>
</class-decl>
- <class-decl name='_xidregitem' size-in-bits='256' is-struct='yes' visibility='default' filepath='./Include/internal/pycore_interp.h' line='244' column='1' id='type-id-946'>
+ <class-decl name='_xidregitem' size-in-bits='256' is-struct='yes' visibility='default' filepath='./Include/internal/pycore_interp.h' line='246' column='1' id='type-id-946'>
<data-member access='public' layout-offset-in-bits='0'>
- <var-decl name='prev' type-id='type-id-947' visibility='default' filepath='./Include/internal/pycore_interp.h' line='245' column='1'/>
+ <var-decl name='prev' type-id='type-id-947' visibility='default' filepath='./Include/internal/pycore_interp.h' line='247' column='1'/>
</data-member>
<data-member access='public' layout-offset-in-bits='64'>
- <var-decl name='next' type-id='type-id-947' visibility='default' filepath='./Include/internal/pycore_interp.h' line='246' column='1'/>
+ <var-decl name='next' type-id='type-id-947' visibility='default' filepath='./Include/internal/pycore_interp.h' line='248' column='1'/>
</data-member>
<data-member access='public' layout-offset-in-bits='128'>
- <var-decl name='cls' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_interp.h' line='247' column='1'/>
+ <var-decl name='cls' type-id='type-id-2' visibility='default' filepath='./Include/internal/pycore_interp.h' line='249' column='1'/>
</data-member>
<data-member access='public' layout-offset-in-bits='192'>
- <var-decl name='getdata' type-id='type-id-796' visibility='default' filepath='./Include/internal/pycore_interp.h' line='248' column='1'/>
+ <var-decl name='getdata' type-id='type-id-796' visibility='default' filepath='./Include/internal/pycore_interp.h' line='250' column='1'/>
</data-member>
</class-decl>
<class-decl name='_Py_list_state' size-in-bits='5184' is-struct='yes' visibility='default' filepath='./Include/internal/pycore_list.h' line='31' column='1' id='type-id-943'>
@@ -16590,7 +16596,7 @@
</data-member>
</class-decl>
<typedef-decl name='_Py_AuditHookEntry' type-id='type-id-983' filepath='./Include/internal/pycore_runtime.h' line='54' column='1' id='type-id-985'/>
- <class-decl name='pyruntimestate' size-in-bits='3679360' is-struct='yes' visibility='default' filepath='./Include/internal/pycore_runtime.h' line='61' column='1' id='type-id-986'>
+ <class-decl name='pyruntimestate' size-in-bits='3679424' is-struct='yes' visibility='default' filepath='./Include/internal/pycore_runtime.h' line='61' column='1' id='type-id-986'>
<data-member access='public' layout-offset-in-bits='0'>
<var-decl name='_initialized' type-id='type-id-8' visibility='default' filepath='./Include/internal/pycore_runtime.h' line='66' column='1'/>
</data-member>
@@ -17469,7 +17475,7 @@
</function-decl>
<var-decl name='_PyOS_ReadlineTState' type-id='type-id-177' mangled-name='_PyOS_ReadlineTState' visibility='default' filepath='./Include/cpython/pythonrun.h' line='120' column='1' elf-symbol-id='_PyOS_ReadlineTState'/>
<var-decl name='PyOS_ReadlineFunctionPointer' type-id='type-id-1068' mangled-name='PyOS_ReadlineFunctionPointer' visibility='default' filepath='./Include/cpython/pythonrun.h' line='121' column='1' elf-symbol-id='PyOS_ReadlineFunctionPointer'/>
- <function-decl name='_PyOS_InterruptOccurred' mangled-name='_PyOS_InterruptOccurred' filepath='./Include/internal/pycore_pystate.h' line='164' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyOS_InterruptOccurred'>
+ <function-decl name='_PyOS_InterruptOccurred' mangled-name='_PyOS_InterruptOccurred' filepath='./Include/internal/pycore_pystate.h' line='169' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyOS_InterruptOccurred'>
<parameter type-id='type-id-177'/>
<return type-id='type-id-8'/>
</function-decl>
@@ -22073,11 +22079,11 @@
<parameter type-id='type-id-177'/>
<return type-id='type-id-46'/>
</function-decl>
- <function-decl name='_PyThreadState_MustExit' filepath='./Include/internal/pycore_pystate.h' line='79' column='1' visibility='default' binding='global' size-in-bits='64'>
+ <function-decl name='_PyThreadState_MustExit' filepath='./Include/internal/pycore_pystate.h' line='84' column='1' visibility='default' binding='global' size-in-bits='64'>
<parameter type-id='type-id-177'/>
<return type-id='type-id-8'/>
</function-decl>
- <function-decl name='_PyThreadState_DeleteExcept' mangled-name='_PyThreadState_DeleteExcept' filepath='./Include/internal/pycore_pystate.h' line='139' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyThreadState_DeleteExcept'>
+ <function-decl name='_PyThreadState_DeleteExcept' mangled-name='_PyThreadState_DeleteExcept' filepath='./Include/internal/pycore_pystate.h' line='144' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyThreadState_DeleteExcept'>
<parameter type-id='type-id-177'/>
<return type-id='type-id-46'/>
</function-decl>
@@ -24951,7 +24957,7 @@
<parameter type-id='type-id-937'/>
<return type-id='type-id-54'/>
</function-decl>
- <function-decl name='_PyInterpreterState_Clear' filepath='./Include/internal/pycore_interp.h' line='208' column='1' visibility='default' binding='global' size-in-bits='64'>
+ <function-decl name='_PyInterpreterState_Clear' filepath='./Include/internal/pycore_interp.h' line='210' column='1' visibility='default' binding='global' size-in-bits='64'>
<parameter type-id='type-id-177'/>
<return type-id='type-id-46'/>
</function-decl>
@@ -25140,15 +25146,15 @@
<parameter type-id='type-id-19'/>
<return type-id='type-id-46'/>
</function-decl>
- <function-decl name='_PyThreadState_New' mangled-name='_PyThreadState_New' filepath='./Include/internal/pycore_pystate.h' line='134' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyThreadState_New'>
+ <function-decl name='_PyThreadState_New' mangled-name='_PyThreadState_New' filepath='./Include/internal/pycore_pystate.h' line='139' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyThreadState_New'>
<parameter type-id='type-id-20'/>
<return type-id='type-id-177'/>
</function-decl>
- <function-decl name='_PyThreadState_Bind' mangled-name='_PyThreadState_Bind' filepath='./Include/internal/pycore_pystate.h' line='135' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyThreadState_Bind'>
+ <function-decl name='_PyThreadState_Bind' mangled-name='_PyThreadState_Bind' filepath='./Include/internal/pycore_pystate.h' line='140' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyThreadState_Bind'>
<parameter type-id='type-id-177'/>
<return type-id='type-id-46'/>
</function-decl>
- <function-decl name='_PyInterpreterState_Enable' mangled-name='_PyInterpreterState_Enable' filepath='./Include/internal/pycore_pystate.h' line='148' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyInterpreterState_Enable'>
+ <function-decl name='_PyInterpreterState_Enable' mangled-name='_PyInterpreterState_Enable' filepath='./Include/internal/pycore_pystate.h' line='153' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyInterpreterState_Enable'>
<parameter type-id='type-id-178'/>
<return type-id='type-id-54'/>
</function-decl>
@@ -25495,7 +25501,7 @@
<parameter type-id='type-id-20'/>
<return type-id='type-id-46'/>
</function-decl>
- <var-decl name='_Py_tss_tstate' type-id='type-id-177' visibility='default' filepath='./Include/internal/pycore_pystate.h' line='71' column='1'/>
+ <var-decl name='_Py_tss_tstate' type-id='type-id-177' visibility='default' filepath='./Include/internal/pycore_pystate.h' line='76' column='1'/>
<function-decl name='PyThread_get_thread_native_id' mangled-name='PyThread_get_thread_native_id' filepath='./Include/pythread.h' line='27' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyThread_get_thread_native_id'>
<return type-id='type-id-28'/>
</function-decl>
@@ -25514,142 +25520,154 @@
<parameter type-id='type-id-20' name='interp' filepath='Python/pystate.c' line='925' column='1'/>
<return type-id='type-id-46'/>
</function-decl>
- <function-decl name='_PyInterpreterState_RequiresIDRef' mangled-name='_PyInterpreterState_RequiresIDRef' filepath='Python/pystate.c' line='1121' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyInterpreterState_RequiresIDRef'>
- <parameter type-id='type-id-20' name='interp' filepath='Python/pystate.c' line='1121' column='1'/>
+ <function-decl name='_PyInterpreterState_SetRunningMain' mangled-name='_PyInterpreterState_SetRunningMain' filepath='Python/pystate.c' line='1053' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyInterpreterState_SetRunningMain'>
+ <parameter type-id='type-id-20' name='interp' filepath='Python/pystate.c' line='1053' column='1'/>
+ <return type-id='type-id-8'/>
+ </function-decl>
+ <function-decl name='_PyInterpreterState_SetNotRunningMain' mangled-name='_PyInterpreterState_SetNotRunningMain' filepath='Python/pystate.c' line='1072' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyInterpreterState_SetNotRunningMain'>
+ <parameter type-id='type-id-20' name='interp' filepath='Python/pystate.c' line='1072' column='1'/>
+ <return type-id='type-id-46'/>
+ </function-decl>
+ <function-decl name='_PyInterpreterState_IsRunningMain' mangled-name='_PyInterpreterState_IsRunningMain' filepath='Python/pystate.c' line='1079' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyInterpreterState_IsRunningMain'>
+ <parameter type-id='type-id-20' name='interp' filepath='Python/pystate.c' line='1079' column='1'/>
+ <return type-id='type-id-8'/>
+ </function-decl>
+ <function-decl name='_PyInterpreterState_RequiresIDRef' mangled-name='_PyInterpreterState_RequiresIDRef' filepath='Python/pystate.c' line='1154' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyInterpreterState_RequiresIDRef'>
+ <parameter type-id='type-id-20' name='interp' filepath='Python/pystate.c' line='1154' column='1'/>
<return type-id='type-id-8'/>
</function-decl>
- <function-decl name='_PyInterpreterState_RequireIDRef' mangled-name='_PyInterpreterState_RequireIDRef' filepath='Python/pystate.c' line='1127' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyInterpreterState_RequireIDRef'>
- <parameter type-id='type-id-20' name='interp' filepath='Python/pystate.c' line='1127' column='1'/>
- <parameter type-id='type-id-8' name='required' filepath='Python/pystate.c' line='1127' column='1'/>
+ <function-decl name='_PyInterpreterState_RequireIDRef' mangled-name='_PyInterpreterState_RequireIDRef' filepath='Python/pystate.c' line='1160' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyInterpreterState_RequireIDRef'>
+ <parameter type-id='type-id-20' name='interp' filepath='Python/pystate.c' line='1160' column='1'/>
+ <parameter type-id='type-id-8' name='required' filepath='Python/pystate.c' line='1160' column='1'/>
<return type-id='type-id-46'/>
</function-decl>
- <function-decl name='_PyInterpreterState_GetMainModule' mangled-name='_PyInterpreterState_GetMainModule' filepath='Python/pystate.c' line='1133' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyInterpreterState_GetMainModule'>
- <parameter type-id='type-id-20' name='interp' filepath='Python/pystate.c' line='1133' column='1'/>
+ <function-decl name='_PyInterpreterState_GetMainModule' mangled-name='_PyInterpreterState_GetMainModule' filepath='Python/pystate.c' line='1166' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyInterpreterState_GetMainModule'>
+ <parameter type-id='type-id-20' name='interp' filepath='Python/pystate.c' line='1166' column='1'/>
<return type-id='type-id-2'/>
</function-decl>
- <function-decl name='PyInterpreterState_GetDict' mangled-name='PyInterpreterState_GetDict' filepath='Python/pystate.c' line='1144' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyInterpreterState_GetDict'>
- <parameter type-id='type-id-20' name='interp' filepath='Python/pystate.c' line='1144' column='1'/>
+ <function-decl name='PyInterpreterState_GetDict' mangled-name='PyInterpreterState_GetDict' filepath='Python/pystate.c' line='1177' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyInterpreterState_GetDict'>
+ <parameter type-id='type-id-20' name='interp' filepath='Python/pystate.c' line='1177' column='1'/>
<return type-id='type-id-2'/>
</function-decl>
- <function-decl name='PyThreadState_New' mangled-name='PyThreadState_New' filepath='Python/pystate.c' line='1386' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyThreadState_New'>
- <parameter type-id='type-id-20' name='interp' filepath='Python/pystate.c' line='1386' column='1'/>
+ <function-decl name='PyThreadState_New' mangled-name='PyThreadState_New' filepath='Python/pystate.c' line='1419' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyThreadState_New'>
+ <parameter type-id='type-id-20' name='interp' filepath='Python/pystate.c' line='1419' column='1'/>
<return type-id='type-id-177'/>
</function-decl>
- <function-decl name='_PyThreadState_Prealloc' mangled-name='_PyThreadState_Prealloc' filepath='Python/pystate.c' line='1409' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyThreadState_Prealloc'>
- <parameter type-id='type-id-20' name='interp' filepath='Python/pystate.c' line='1409' column='1'/>
+ <function-decl name='_PyThreadState_Prealloc' mangled-name='_PyThreadState_Prealloc' filepath='Python/pystate.c' line='1442' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyThreadState_Prealloc'>
+ <parameter type-id='type-id-20' name='interp' filepath='Python/pystate.c' line='1442' column='1'/>
<return type-id='type-id-177'/>
</function-decl>
- <function-decl name='_PyThreadState_Init' mangled-name='_PyThreadState_Init' filepath='Python/pystate.c' line='1417' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyThreadState_Init'>
- <parameter type-id='type-id-177' name='tstate' filepath='Python/pystate.c' line='1417' column='1'/>
+ <function-decl name='_PyThreadState_Init' mangled-name='_PyThreadState_Init' filepath='Python/pystate.c' line='1450' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyThreadState_Init'>
+ <parameter type-id='type-id-177' name='tstate' filepath='Python/pystate.c' line='1450' column='1'/>
<return type-id='type-id-46'/>
</function-decl>
- <function-decl name='_PyThreadState_DeleteCurrent' mangled-name='_PyThreadState_DeleteCurrent' filepath='Python/pystate.c' line='1579' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyThreadState_DeleteCurrent'>
- <parameter type-id='type-id-177' name='tstate' filepath='Python/pystate.c' line='1579' column='1'/>
+ <function-decl name='_PyThreadState_DeleteCurrent' mangled-name='_PyThreadState_DeleteCurrent' filepath='Python/pystate.c' line='1612' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyThreadState_DeleteCurrent'>
+ <parameter type-id='type-id-177' name='tstate' filepath='Python/pystate.c' line='1612' column='1'/>
<return type-id='type-id-46'/>
</function-decl>
- <function-decl name='PyThreadState_DeleteCurrent' mangled-name='PyThreadState_DeleteCurrent' filepath='Python/pystate.c' line='1589' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyThreadState_DeleteCurrent'>
+ <function-decl name='PyThreadState_DeleteCurrent' mangled-name='PyThreadState_DeleteCurrent' filepath='Python/pystate.c' line='1622' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyThreadState_DeleteCurrent'>
<return type-id='type-id-46'/>
</function-decl>
- <function-decl name='_PyThreadState_GetDict' mangled-name='_PyThreadState_GetDict' filepath='Python/pystate.c' line='1651' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyThreadState_GetDict'>
- <parameter type-id='type-id-177' name='tstate' filepath='Python/pystate.c' line='1651' column='1'/>
+ <function-decl name='_PyThreadState_GetDict' mangled-name='_PyThreadState_GetDict' filepath='Python/pystate.c' line='1684' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyThreadState_GetDict'>
+ <parameter type-id='type-id-177' name='tstate' filepath='Python/pystate.c' line='1684' column='1'/>
<return type-id='type-id-2'/>
</function-decl>
- <function-decl name='PyThreadState_GetInterpreter' mangled-name='PyThreadState_GetInterpreter' filepath='Python/pystate.c' line='1676' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyThreadState_GetInterpreter'>
- <parameter type-id='type-id-177' name='tstate' filepath='Python/pystate.c' line='1676' column='1'/>
+ <function-decl name='PyThreadState_GetInterpreter' mangled-name='PyThreadState_GetInterpreter' filepath='Python/pystate.c' line='1709' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyThreadState_GetInterpreter'>
+ <parameter type-id='type-id-177' name='tstate' filepath='Python/pystate.c' line='1709' column='1'/>
<return type-id='type-id-20'/>
</function-decl>
- <function-decl name='PyThreadState_GetID' mangled-name='PyThreadState_GetID' filepath='Python/pystate.c' line='1700' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyThreadState_GetID'>
- <parameter type-id='type-id-177' name='tstate' filepath='Python/pystate.c' line='1700' column='1'/>
+ <function-decl name='PyThreadState_GetID' mangled-name='PyThreadState_GetID' filepath='Python/pystate.c' line='1733' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyThreadState_GetID'>
+ <parameter type-id='type-id-177' name='tstate' filepath='Python/pystate.c' line='1733' column='1'/>
<return type-id='type-id-117'/>
</function-decl>
- <function-decl name='PyThreadState_SetAsyncExc' mangled-name='PyThreadState_SetAsyncExc' filepath='Python/pystate.c' line='1754' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyThreadState_SetAsyncExc'>
- <parameter type-id='type-id-28' name='id' filepath='Python/pystate.c' line='1754' column='1'/>
- <parameter type-id='type-id-2' name='exc' filepath='Python/pystate.c' line='1754' column='1'/>
+ <function-decl name='PyThreadState_SetAsyncExc' mangled-name='PyThreadState_SetAsyncExc' filepath='Python/pystate.c' line='1787' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyThreadState_SetAsyncExc'>
+ <parameter type-id='type-id-28' name='id' filepath='Python/pystate.c' line='1787' column='1'/>
+ <parameter type-id='type-id-2' name='exc' filepath='Python/pystate.c' line='1787' column='1'/>
<return type-id='type-id-8'/>
</function-decl>
- <function-decl name='_PyThreadState_Swap' mangled-name='_PyThreadState_Swap' filepath='Python/pystate.c' line='1851' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyThreadState_Swap'>
- <parameter type-id='type-id-178' name='runtime' filepath='Python/pystate.c' line='1851' column='1'/>
- <parameter type-id='type-id-177' name='newts' filepath='Python/pystate.c' line='1851' column='1'/>
+ <function-decl name='_PyThreadState_Swap' mangled-name='_PyThreadState_Swap' filepath='Python/pystate.c' line='1884' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyThreadState_Swap'>
+ <parameter type-id='type-id-178' name='runtime' filepath='Python/pystate.c' line='1884' column='1'/>
+ <parameter type-id='type-id-177' name='newts' filepath='Python/pystate.c' line='1884' column='1'/>
<return type-id='type-id-177'/>
</function-decl>
- <function-decl name='PyInterpreterState_Main' mangled-name='PyInterpreterState_Main' filepath='Python/pystate.c' line='1901' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyInterpreterState_Main'>
+ <function-decl name='PyInterpreterState_Main' mangled-name='PyInterpreterState_Main' filepath='Python/pystate.c' line='1934' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='PyInterpreterState_Main'>
<return type-id='type-id-20'/>
</function-decl>
- <function-decl name='_PyThread_CurrentFrames' mangled-name='_PyThread_CurrentFrames' filepath='Python/pystate.c' line='1932' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyThread_CurrentFrames'>
+ <function-decl name='_PyThread_CurrentFrames' mangled-name='_PyThread_CurrentFrames' filepath='Python/pystate.c' line='1965' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyThread_CurrentFrames'>
<return type-id='type-id-2'/>
</function-decl>
- <function-decl name='_PyThread_CurrentExceptions' mangled-name='_PyThread_CurrentExceptions' filepath='Python/pystate.c' line='1993' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyThread_CurrentExceptions'>
+ <function-decl name='_PyThread_CurrentExceptions' mangled-name='_PyThread_CurrentExceptions' filepath='Python/pystate.c' line='2026' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyThread_CurrentExceptions'>
<return type-id='type-id-2'/>
</function-decl>
- <function-decl name='_PyGILState_GetInterpreterStateUnsafe' mangled-name='_PyGILState_GetInterpreterStateUnsafe' filepath='Python/pystate.c' line='2111' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyGILState_GetInterpreterStateUnsafe'>
+ <function-decl name='_PyGILState_GetInterpreterStateUnsafe' mangled-name='_PyGILState_GetInterpreterStateUnsafe' filepath='Python/pystate.c' line='2144' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyGILState_GetInterpreterStateUnsafe'>
<return type-id='type-id-20'/>
</function-decl>
- <function-decl name='_PyCrossInterpreterData_Init' mangled-name='_PyCrossInterpreterData_Init' filepath='Python/pystate.c' line='2280' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyCrossInterpreterData_Init'>
- <parameter type-id='type-id-1063' name='data' filepath='Python/pystate.c' line='2280' column='1'/>
- <parameter type-id='type-id-20' name='interp' filepath='Python/pystate.c' line='2281' column='1'/>
- <parameter type-id='type-id-22' name='shared' filepath='Python/pystate.c' line='2282' column='1'/>
- <parameter type-id='type-id-2' name='obj' filepath='Python/pystate.c' line='2282' column='1'/>
- <parameter type-id='type-id-793' name='new_object' filepath='Python/pystate.c' line='2283' column='1'/>
+ <function-decl name='_PyCrossInterpreterData_Init' mangled-name='_PyCrossInterpreterData_Init' filepath='Python/pystate.c' line='2313' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyCrossInterpreterData_Init'>
+ <parameter type-id='type-id-1063' name='data' filepath='Python/pystate.c' line='2313' column='1'/>
+ <parameter type-id='type-id-20' name='interp' filepath='Python/pystate.c' line='2314' column='1'/>
+ <parameter type-id='type-id-22' name='shared' filepath='Python/pystate.c' line='2315' column='1'/>
+ <parameter type-id='type-id-2' name='obj' filepath='Python/pystate.c' line='2315' column='1'/>
+ <parameter type-id='type-id-793' name='new_object' filepath='Python/pystate.c' line='2316' column='1'/>
<return type-id='type-id-46'/>
</function-decl>
- <function-decl name='_PyCrossInterpreterData_InitWithSize' mangled-name='_PyCrossInterpreterData_InitWithSize' filepath='Python/pystate.c' line='2302' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyCrossInterpreterData_InitWithSize'>
- <parameter type-id='type-id-1063' name='data' filepath='Python/pystate.c' line='2302' column='1'/>
- <parameter type-id='type-id-20' name='interp' filepath='Python/pystate.c' line='2303' column='1'/>
- <parameter type-id='type-id-1503' name='size' filepath='Python/pystate.c' line='2304' column='1'/>
- <parameter type-id='type-id-2' name='obj' filepath='Python/pystate.c' line='2304' column='1'/>
- <parameter type-id='type-id-793' name='new_object' filepath='Python/pystate.c' line='2305' column='1'/>
+ <function-decl name='_PyCrossInterpreterData_InitWithSize' mangled-name='_PyCrossInterpreterData_InitWithSize' filepath='Python/pystate.c' line='2335' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyCrossInterpreterData_InitWithSize'>
+ <parameter type-id='type-id-1063' name='data' filepath='Python/pystate.c' line='2335' column='1'/>
+ <parameter type-id='type-id-20' name='interp' filepath='Python/pystate.c' line='2336' column='1'/>
+ <parameter type-id='type-id-1503' name='size' filepath='Python/pystate.c' line='2337' column='1'/>
+ <parameter type-id='type-id-2' name='obj' filepath='Python/pystate.c' line='2337' column='1'/>
+ <parameter type-id='type-id-793' name='new_object' filepath='Python/pystate.c' line='2338' column='1'/>
<return type-id='type-id-8'/>
</function-decl>
- <function-decl name='_PyCrossInterpreterData_Clear' mangled-name='_PyCrossInterpreterData_Clear' filepath='Python/pystate.c' line='2321' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyCrossInterpreterData_Clear'>
- <parameter type-id='type-id-20' name='interp' filepath='Python/pystate.c' line='2321' column='1'/>
- <parameter type-id='type-id-1063' name='data' filepath='Python/pystate.c' line='2322' column='1'/>
+ <function-decl name='_PyCrossInterpreterData_Clear' mangled-name='_PyCrossInterpreterData_Clear' filepath='Python/pystate.c' line='2354' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyCrossInterpreterData_Clear'>
+ <parameter type-id='type-id-20' name='interp' filepath='Python/pystate.c' line='2354' column='1'/>
+ <parameter type-id='type-id-1063' name='data' filepath='Python/pystate.c' line='2355' column='1'/>
<return type-id='type-id-46'/>
</function-decl>
- <function-decl name='_PyObject_CheckCrossInterpreterData' mangled-name='_PyObject_CheckCrossInterpreterData' filepath='Python/pystate.c' line='2367' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyObject_CheckCrossInterpreterData'>
- <parameter type-id='type-id-2' name='obj' filepath='Python/pystate.c' line='2367' column='1'/>
+ <function-decl name='_PyObject_CheckCrossInterpreterData' mangled-name='_PyObject_CheckCrossInterpreterData' filepath='Python/pystate.c' line='2400' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyObject_CheckCrossInterpreterData'>
+ <parameter type-id='type-id-2' name='obj' filepath='Python/pystate.c' line='2400' column='1'/>
<return type-id='type-id-8'/>
</function-decl>
- <function-decl name='_PyObject_GetCrossInterpreterData' mangled-name='_PyObject_GetCrossInterpreterData' filepath='Python/pystate.c' line='2377' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyObject_GetCrossInterpreterData'>
- <parameter type-id='type-id-2' name='obj' filepath='Python/pystate.c' line='2377' column='1'/>
- <parameter type-id='type-id-1063' name='data' filepath='Python/pystate.c' line='2377' column='1'/>
+ <function-decl name='_PyObject_GetCrossInterpreterData' mangled-name='_PyObject_GetCrossInterpreterData' filepath='Python/pystate.c' line='2410' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyObject_GetCrossInterpreterData'>
+ <parameter type-id='type-id-2' name='obj' filepath='Python/pystate.c' line='2410' column='1'/>
+ <parameter type-id='type-id-1063' name='data' filepath='Python/pystate.c' line='2410' column='1'/>
<return type-id='type-id-8'/>
</function-decl>
- <function-decl name='_PyCrossInterpreterData_NewObject' mangled-name='_PyCrossInterpreterData_NewObject' filepath='Python/pystate.c' line='2415' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyCrossInterpreterData_NewObject'>
- <parameter type-id='type-id-1063' name='data' filepath='Python/pystate.c' line='2415' column='1'/>
+ <function-decl name='_PyCrossInterpreterData_NewObject' mangled-name='_PyCrossInterpreterData_NewObject' filepath='Python/pystate.c' line='2448' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyCrossInterpreterData_NewObject'>
+ <parameter type-id='type-id-1063' name='data' filepath='Python/pystate.c' line='2448' column='1'/>
<return type-id='type-id-2'/>
</function-decl>
- <function-decl name='_PyCrossInterpreterData_Release' mangled-name='_PyCrossInterpreterData_Release' filepath='Python/pystate.c' line='2481' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyCrossInterpreterData_Release'>
- <parameter type-id='type-id-1063' name='data' filepath='Python/pystate.c' line='2481' column='1'/>
+ <function-decl name='_PyCrossInterpreterData_Release' mangled-name='_PyCrossInterpreterData_Release' filepath='Python/pystate.c' line='2514' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyCrossInterpreterData_Release'>
+ <parameter type-id='type-id-1063' name='data' filepath='Python/pystate.c' line='2514' column='1'/>
<return type-id='type-id-8'/>
</function-decl>
- <function-decl name='_PyCrossInterpreterData_ReleaseAndRawFree' mangled-name='_PyCrossInterpreterData_ReleaseAndRawFree' filepath='Python/pystate.c' line='2487' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyCrossInterpreterData_ReleaseAndRawFree'>
- <parameter type-id='type-id-1063' name='data' filepath='Python/pystate.c' line='2487' column='1'/>
+ <function-decl name='_PyCrossInterpreterData_ReleaseAndRawFree' mangled-name='_PyCrossInterpreterData_ReleaseAndRawFree' filepath='Python/pystate.c' line='2520' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyCrossInterpreterData_ReleaseAndRawFree'>
+ <parameter type-id='type-id-1063' name='data' filepath='Python/pystate.c' line='2520' column='1'/>
<return type-id='type-id-8'/>
</function-decl>
- <function-decl name='_PyCrossInterpreterData_RegisterClass' mangled-name='_PyCrossInterpreterData_RegisterClass' filepath='Python/pystate.c' line='2569' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyCrossInterpreterData_RegisterClass'>
- <parameter type-id='type-id-1' name='cls' filepath='Python/pystate.c' line='2569' column='1'/>
- <parameter type-id='type-id-796' name='getdata' filepath='Python/pystate.c' line='2570' column='1'/>
+ <function-decl name='_PyCrossInterpreterData_RegisterClass' mangled-name='_PyCrossInterpreterData_RegisterClass' filepath='Python/pystate.c' line='2602' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyCrossInterpreterData_RegisterClass'>
+ <parameter type-id='type-id-1' name='cls' filepath='Python/pystate.c' line='2602' column='1'/>
+ <parameter type-id='type-id-796' name='getdata' filepath='Python/pystate.c' line='2603' column='1'/>
<return type-id='type-id-8'/>
</function-decl>
- <function-decl name='_PyCrossInterpreterData_UnregisterClass' mangled-name='_PyCrossInterpreterData_UnregisterClass' filepath='Python/pystate.c' line='2592' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyCrossInterpreterData_UnregisterClass'>
- <parameter type-id='type-id-1' name='cls' filepath='Python/pystate.c' line='2592' column='1'/>
+ <function-decl name='_PyCrossInterpreterData_UnregisterClass' mangled-name='_PyCrossInterpreterData_UnregisterClass' filepath='Python/pystate.c' line='2625' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyCrossInterpreterData_UnregisterClass'>
+ <parameter type-id='type-id-1' name='cls' filepath='Python/pystate.c' line='2625' column='1'/>
<return type-id='type-id-8'/>
</function-decl>
- <function-decl name='_PyCrossInterpreterData_Lookup' mangled-name='_PyCrossInterpreterData_Lookup' filepath='Python/pystate.c' line='2612' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyCrossInterpreterData_Lookup'>
- <parameter type-id='type-id-2' name='obj' filepath='Python/pystate.c' line='2612' column='1'/>
+ <function-decl name='_PyCrossInterpreterData_Lookup' mangled-name='_PyCrossInterpreterData_Lookup' filepath='Python/pystate.c' line='2645' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyCrossInterpreterData_Lookup'>
+ <parameter type-id='type-id-2' name='obj' filepath='Python/pystate.c' line='2645' column='1'/>
<return type-id='type-id-796'/>
</function-decl>
- <function-decl name='_PyInterpreterState_GetEvalFrameFunc' mangled-name='_PyInterpreterState_GetEvalFrameFunc' filepath='Python/pystate.c' line='2761' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyInterpreterState_GetEvalFrameFunc'>
- <parameter type-id='type-id-20' name='interp' filepath='Python/pystate.c' line='2761' column='1'/>
+ <function-decl name='_PyInterpreterState_GetEvalFrameFunc' mangled-name='_PyInterpreterState_GetEvalFrameFunc' filepath='Python/pystate.c' line='2798' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyInterpreterState_GetEvalFrameFunc'>
+ <parameter type-id='type-id-20' name='interp' filepath='Python/pystate.c' line='2798' column='1'/>
<return type-id='type-id-789'/>
</function-decl>
- <function-decl name='_PyInterpreterState_SetEvalFrameFunc' mangled-name='_PyInterpreterState_SetEvalFrameFunc' filepath='Python/pystate.c' line='2771' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyInterpreterState_SetEvalFrameFunc'>
- <parameter type-id='type-id-20' name='interp' filepath='Python/pystate.c' line='2771' column='1'/>
- <parameter type-id='type-id-789' name='eval_frame' filepath='Python/pystate.c' line='2772' column='1'/>
+ <function-decl name='_PyInterpreterState_SetEvalFrameFunc' mangled-name='_PyInterpreterState_SetEvalFrameFunc' filepath='Python/pystate.c' line='2808' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyInterpreterState_SetEvalFrameFunc'>
+ <parameter type-id='type-id-20' name='interp' filepath='Python/pystate.c' line='2808' column='1'/>
+ <parameter type-id='type-id-789' name='eval_frame' filepath='Python/pystate.c' line='2809' column='1'/>
<return type-id='type-id-46'/>
</function-decl>
- <function-decl name='_PyInterpreterState_GetConfigCopy' mangled-name='_PyInterpreterState_GetConfigCopy' filepath='Python/pystate.c' line='2791' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyInterpreterState_GetConfigCopy'>
- <parameter type-id='type-id-53' name='config' filepath='Python/pystate.c' line='2791' column='1'/>
+ <function-decl name='_PyInterpreterState_GetConfigCopy' mangled-name='_PyInterpreterState_GetConfigCopy' filepath='Python/pystate.c' line='2828' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_PyInterpreterState_GetConfigCopy'>
+ <parameter type-id='type-id-53' name='config' filepath='Python/pystate.c' line='2828' column='1'/>
<return type-id='type-id-8'/>
</function-decl>
</abi-instr>
diff --git a/Include/internal/pycore_interp.h b/Include/internal/pycore_interp.h
index 2fbb9f1..b5d947c 100644
--- a/Include/internal/pycore_interp.h
+++ b/Include/internal/pycore_interp.h
@@ -194,6 +194,8 @@ struct _is {
struct _Py_interp_cached_objects cached_objects;
struct _Py_interp_static_objects static_objects;
+ /* The thread currently executing in the __main__ module, if any. */
+ PyThreadState *threads_main;
/* The ID of the OS thread in which we are finalizing.
We use _Py_atomic_address instead of adding a new _Py_atomic_ulong. */
_Py_atomic_address _finalizing_id;
diff --git a/Include/internal/pycore_pystate.h b/Include/internal/pycore_pystate.h
index e4186b3..fba08ae 100644
--- a/Include/internal/pycore_pystate.h
+++ b/Include/internal/pycore_pystate.h
@@ -44,6 +44,11 @@ _Py_IsMainInterpreterFinalizing(PyInterpreterState *interp)
interp == &_PyRuntime._main_interpreter);
}
+// Export for _xxsubinterpreters module.
+PyAPI_FUNC(int) _PyInterpreterState_SetRunningMain(PyInterpreterState *);
+PyAPI_FUNC(void) _PyInterpreterState_SetNotRunningMain(PyInterpreterState *);
+PyAPI_FUNC(int) _PyInterpreterState_IsRunningMain(PyInterpreterState *);
+
static inline const PyConfig *
_Py_GetMainConfig(void)
diff --git a/Lib/test/test_interpreters.py b/Lib/test/test_interpreters.py
index 38cf4b6..cc4f400 100644
--- a/Lib/test/test_interpreters.py
+++ b/Lib/test/test_interpreters.py
@@ -261,6 +261,16 @@ class TestInterpreterIsRunning(TestBase):
self.assertTrue(interp.is_running())
self.assertFalse(interp.is_running())
+ def test_finished(self):
+ r, w = os.pipe()
+ interp = interpreters.create()
+ interp.run(f"""if True:
+ import os
+ os.write({w}, b'x')
+ """)
+ self.assertFalse(interp.is_running())
+ self.assertEqual(os.read(r, 1), b'x')
+
def test_from_subinterpreter(self):
interp = interpreters.create()
out = _run_output(interp, dedent(f"""
@@ -288,6 +298,31 @@ class TestInterpreterIsRunning(TestBase):
with self.assertRaises(ValueError):
interp.is_running()
+ def test_with_only_background_threads(self):
+ r_interp, w_interp = os.pipe()
+ r_thread, w_thread = os.pipe()
+
+ DONE = b'D'
+ FINISHED = b'F'
+
+ interp = interpreters.create()
+ interp.run(f"""if True:
+ import os
+ import threading
+
+ def task():
+ v = os.read({r_thread}, 1)
+ assert v == {DONE!r}
+ os.write({w_interp}, {FINISHED!r})
+ t = threading.Thread(target=task)
+ t.start()
+ """)
+ self.assertFalse(interp.is_running())
+
+ os.write(w_thread, DONE)
+ interp.run('t.join()')
+ self.assertEqual(os.read(r_interp, 1), FINISHED)
+
class TestInterpreterClose(TestBase):
@@ -389,6 +424,37 @@ class TestInterpreterClose(TestBase):
interp.close()
self.assertTrue(interp.is_running())
+ def test_subthreads_still_running(self):
+ r_interp, w_interp = os.pipe()
+ r_thread, w_thread = os.pipe()
+
+ FINISHED = b'F'
+
+ interp = interpreters.create()
+ interp.run(f"""if True:
+ import os
+ import threading
+ import time
+
+ done = False
+
+ def notify_fini():
+ global done
+ done = True
+ t.join()
+ threading._register_atexit(notify_fini)
+
+ def task():
+ while not done:
+ time.sleep(0.1)
+ os.write({w_interp}, {FINISHED!r})
+ t = threading.Thread(target=task)
+ t.start()
+ """)
+ interp.close()
+
+ self.assertEqual(os.read(r_interp, 1), FINISHED)
+
class TestInterpreterRun(TestBase):
@@ -465,6 +531,37 @@ class TestInterpreterRun(TestBase):
with self.assertRaises(TypeError):
interp.run(b'print("spam")')
+ def test_with_background_threads_still_running(self):
+ r_interp, w_interp = os.pipe()
+ r_thread, w_thread = os.pipe()
+
+ RAN = b'R'
+ DONE = b'D'
+ FINISHED = b'F'
+
+ interp = interpreters.create()
+ interp.run(f"""if True:
+ import os
+ import threading
+
+ def task():
+ v = os.read({r_thread}, 1)
+ assert v == {DONE!r}
+ os.write({w_interp}, {FINISHED!r})
+ t = threading.Thread(target=task)
+ t.start()
+ os.write({w_interp}, {RAN!r})
+ """)
+ interp.run(f"""if True:
+ os.write({w_interp}, {RAN!r})
+ """)
+
+ os.write(w_thread, DONE)
+ interp.run('t.join()')
+ self.assertEqual(os.read(r_interp, 1), RAN)
+ self.assertEqual(os.read(r_interp, 1), RAN)
+ self.assertEqual(os.read(r_interp, 1), FINISHED)
+
# test_xxsubinterpreters covers the remaining Interpreter.run() behavior.
diff --git a/Lib/test/test_threading.py b/Lib/test/test_threading.py
index f63e5c6..ce477d2 100644
--- a/Lib/test/test_threading.py
+++ b/Lib/test/test_threading.py
@@ -26,6 +26,11 @@ from unittest import mock
from test import lock_tests
from test import support
+try:
+ from test.support import interpreters
+except ModuleNotFoundError:
+ interpreters = None
+
threading_helper.requires_working_threading(module=True)
# Between fork() and exec(), only async-safe functions are allowed (issues
@@ -45,6 +50,12 @@ def skip_unless_reliable_fork(test):
return test
+def requires_subinterpreters(meth):
+ """Decorator to skip a test if subinterpreters are not supported."""
+ return unittest.skipIf(interpreters is None,
+ 'subinterpreters required')(meth)
+
+
def restore_default_excepthook(testcase):
testcase.addCleanup(setattr, threading, 'excepthook', threading.excepthook)
threading.excepthook = threading.__excepthook__
@@ -1296,6 +1307,44 @@ class SubinterpThreadingTests(BaseTestCase):
# The thread was joined properly.
self.assertEqual(os.read(r, 1), b"x")
+ @requires_subinterpreters
+ def test_threads_join_with_no_main(self):
+ r_interp, w_interp = self.pipe()
+
+ INTERP = b'I'
+ FINI = b'F'
+ DONE = b'D'
+
+ interp = interpreters.create()
+ interp.run(f"""if True:
+ import os
+ import threading
+ import time
+
+ done = False
+
+ def notify_fini():
+ global done
+ done = True
+ os.write({w_interp}, {FINI!r})
+ t.join()
+ threading._register_atexit(notify_fini)
+
+ def task():
+ while not done:
+ time.sleep(0.1)
+ os.write({w_interp}, {DONE!r})
+ t = threading.Thread(target=task)
+ t.start()
+
+ os.write({w_interp}, {INTERP!r})
+ """)
+ interp.close()
+
+ self.assertEqual(os.read(r_interp, 1), INTERP)
+ self.assertEqual(os.read(r_interp, 1), FINI)
+ self.assertEqual(os.read(r_interp, 1), DONE)
+
@cpython_only
def test_daemon_threads_fatal_error(self):
subinterp_code = f"""if 1:
diff --git a/Lib/threading.py b/Lib/threading.py
index a746dee..624e7ed 100644
--- a/Lib/threading.py
+++ b/Lib/threading.py
@@ -37,6 +37,7 @@ _daemon_threads_allowed = _thread.daemon_threads_allowed
_allocate_lock = _thread.allocate_lock
_set_sentinel = _thread._set_sentinel
get_ident = _thread.get_ident
+_is_main_interpreter = _thread._is_main_interpreter
try:
get_native_id = _thread.get_native_id
_HAVE_THREAD_NATIVE_ID = True
@@ -1566,7 +1567,7 @@ def _shutdown():
# the main thread's tstate_lock - that won't happen until the interpreter
# is nearly dead. So we release it here. Note that just calling _stop()
# isn't enough: other threads may already be waiting on _tstate_lock.
- if _main_thread._is_stopped:
+ if _main_thread._is_stopped and _is_main_interpreter():
# _shutdown() was already called
return
@@ -1619,6 +1620,7 @@ def main_thread():
In normal conditions, the main thread is the thread from which the
Python interpreter was started.
"""
+ # XXX Figure this out for subinterpreters. (See gh-75698.)
return _main_thread
# get thread-local implementation, either from the thread
diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-09-26-14-00-25.gh-issue-105716.SUJkW1.rst b/Misc/NEWS.d/next/Core and Builtins/2023-09-26-14-00-25.gh-issue-105716.SUJkW1.rst
new file mode 100644
index 0000000..b35550f
--- /dev/null
+++ b/Misc/NEWS.d/next/Core and Builtins/2023-09-26-14-00-25.gh-issue-105716.SUJkW1.rst
@@ -0,0 +1,3 @@
+Subinterpreters now correctly handle the case where they have threads
+running in the background. Before, such threads would interfere with
+cleaning up and destroying them, as well as prevent running another script.
diff --git a/Modules/_threadmodule.c b/Modules/_threadmodule.c
index 5edb6e9..568fe83 100644
--- a/Modules/_threadmodule.c
+++ b/Modules/_threadmodule.c
@@ -1604,6 +1604,18 @@ PyDoc_STRVAR(excepthook_doc,
\n\
Handle uncaught Thread.run() exception.");
+static PyObject *
+thread__is_main_interpreter(PyObject *module, PyObject *Py_UNUSED(ignored))
+{
+ PyInterpreterState *interp = _PyInterpreterState_GET();
+ return PyBool_FromLong(_Py_IsMainInterpreter(interp));
+}
+
+PyDoc_STRVAR(thread__is_main_interpreter_doc,
+"_is_main_interpreter()\n\
+\n\
+Return True if the current interpreter is the main Python interpreter.");
+
static PyMethodDef thread_methods[] = {
{"start_new_thread", (PyCFunction)thread_PyThread_start_new_thread,
METH_VARARGS, start_new_doc},
@@ -1633,8 +1645,10 @@ static PyMethodDef thread_methods[] = {
METH_VARARGS, stack_size_doc},
{"_set_sentinel", thread__set_sentinel,
METH_NOARGS, _set_sentinel_doc},
- {"_excepthook", thread_excepthook,
+ {"_excepthook", thread_excepthook,
METH_O, excepthook_doc},
+ {"_is_main_interpreter", thread__is_main_interpreter,
+ METH_NOARGS, thread__is_main_interpreter_doc},
{NULL, NULL} /* sentinel */
};
diff --git a/Modules/_xxsubinterpretersmodule.c b/Modules/_xxsubinterpretersmodule.c
index 5d4f1b9..c0958c6 100644
--- a/Modules/_xxsubinterpretersmodule.c
+++ b/Modules/_xxsubinterpretersmodule.c
@@ -2,7 +2,14 @@
/* interpreters module */
/* low-level access to interpreter primitives */
+#ifndef Py_BUILD_CORE_BUILTIN
+# define Py_BUILD_CORE_MODULE 1
+#endif
+
#include "Python.h"
+#include "pycore_initconfig.h" // _PyErr_SetFromPyStatus()
+#include "pycore_pyerrors.h" // _PyErr_ChainExceptions1()
+#include "pycore_pystate.h" // _PyInterpreterState_SetRunningMain()
#include "interpreteridobject.h"
@@ -353,41 +360,14 @@ exceptions_init(PyObject *mod)
}
static int
-_is_running(PyInterpreterState *interp)
-{
- PyThreadState *tstate = PyInterpreterState_ThreadHead(interp);
- if (PyThreadState_Next(tstate) != NULL) {
- PyErr_SetString(PyExc_RuntimeError,
- "interpreter has more than one thread");
- return -1;
- }
-
- assert(!PyErr_Occurred());
- struct _PyInterpreterFrame *frame = tstate->cframe->current_frame;
- if (frame == NULL) {
- return 0;
- }
- return 1;
-}
-
-static int
-_ensure_not_running(PyInterpreterState *interp)
+_run_script(PyInterpreterState *interp, const char *codestr,
+ _sharedns *shared, _sharedexception *sharedexc)
{
- int is_running = _is_running(interp);
- if (is_running < 0) {
+ if (_PyInterpreterState_SetRunningMain(interp) < 0) {
+ // We skip going through the shared exception.
return -1;
}
- if (is_running) {
- PyErr_Format(PyExc_RuntimeError, "interpreter already running");
- return -1;
- }
- return 0;
-}
-static int
-_run_script(PyInterpreterState *interp, const char *codestr,
- _sharedns *shared, _sharedexception *sharedexc)
-{
PyObject *excval = NULL;
PyObject *main_mod = _PyInterpreterState_GetMainModule(interp);
if (main_mod == NULL) {
@@ -417,6 +397,7 @@ _run_script(PyInterpreterState *interp, const char *codestr,
else {
Py_DECREF(result); // We throw away the result.
}
+ _PyInterpreterState_SetNotRunningMain(interp);
*sharedexc = no_exception;
return 0;
@@ -432,6 +413,7 @@ error:
}
Py_XDECREF(excval);
assert(!PyErr_Occurred());
+ _PyInterpreterState_SetNotRunningMain(interp);
return -1;
}
@@ -439,9 +421,6 @@ static int
_run_script_in_interpreter(PyObject *mod, PyInterpreterState *interp,
const char *codestr, PyObject *shareables)
{
- if (_ensure_not_running(interp) < 0) {
- return -1;
- }
module_state *state = get_module_state(mod);
_sharedns *shared = _get_shared_ns(shareables);
@@ -452,8 +431,26 @@ _run_script_in_interpreter(PyObject *mod, PyInterpreterState *interp,
// Switch to interpreter.
PyThreadState *save_tstate = NULL;
if (interp != PyInterpreterState_Get()) {
- // XXX Using the "head" thread isn't strictly correct.
+ // XXX gh-109860: Using the "head" thread isn't strictly correct.
PyThreadState *tstate = PyInterpreterState_ThreadHead(interp);
+ assert(tstate != NULL);
+ // Hack (until gh-109860): The interpreter's initial thread state
+ // is least likely to break.
+ while(tstate->next != NULL) {
+ tstate = tstate->next;
+ }
+ // We must do this check before switching interpreters, so any
+ // exception gets raised in the right one.
+ // XXX gh-109860: Drop this redundant check once we stop
+ // re-using tstates that might already be in use.
+ if (_PyInterpreterState_IsRunningMain(interp)) {
+ PyErr_SetString(PyExc_RuntimeError,
+ "interpreter already running");
+ if (shared != NULL) {
+ _sharedns_free(shared);
+ }
+ return -1;
+ }
// XXX Possible GILState issues?
save_tstate = PyThreadState_Swap(tstate);
}
@@ -473,8 +470,10 @@ _run_script_in_interpreter(PyObject *mod, PyInterpreterState *interp,
_sharedexception_apply(&exc, state->RunFailedError);
}
else if (result != 0) {
- // We were unable to allocate a shared exception.
- PyErr_NoMemory();
+ if (!PyErr_Occurred()) {
+ // We were unable to allocate a shared exception.
+ PyErr_NoMemory();
+ }
}
if (shared != NULL) {
@@ -569,12 +568,20 @@ interp_destroy(PyObject *self, PyObject *args, PyObject *kwds)
// Ensure the interpreter isn't running.
/* XXX We *could* support destroying a running interpreter but
aren't going to worry about it for now. */
- if (_ensure_not_running(interp) < 0) {
+ if (_PyInterpreterState_IsRunningMain(interp)) {
+ PyErr_Format(PyExc_RuntimeError, "interpreter running");
return NULL;
}
// Destroy the interpreter.
+ // XXX gh-109860: Using the "head" thread isn't strictly correct.
PyThreadState *tstate = PyInterpreterState_ThreadHead(interp);
+ assert(tstate != NULL);
+ // Hack (until gh-109860): The interpreter's initial thread state
+ // is least likely to break.
+ while(tstate->next != NULL) {
+ tstate = tstate->next;
+ }
// XXX Possible GILState issues?
PyThreadState *save_tstate = PyThreadState_Swap(tstate);
Py_EndInterpreter(tstate);
@@ -743,11 +750,7 @@ interp_is_running(PyObject *self, PyObject *args, PyObject *kwds)
if (interp == NULL) {
return NULL;
}
- int is_running = _is_running(interp);
- if (is_running < 0) {
- return NULL;
- }
- if (is_running) {
+ if (_PyInterpreterState_IsRunningMain(interp)) {
Py_RETURN_TRUE;
}
Py_RETURN_FALSE;
@@ -758,6 +761,7 @@ PyDoc_STRVAR(is_running_doc,
\n\
Return whether or not the identified interpreter is running.");
+
static PyMethodDef module_functions[] = {
{"create", _PyCFunction_CAST(interp_create),
METH_VARARGS | METH_KEYWORDS, create_doc},
diff --git a/Modules/main.c b/Modules/main.c
index b9de2ec..1b189b4 100644
--- a/Modules/main.c
+++ b/Modules/main.c
@@ -613,6 +613,9 @@ pymain_run_python(int *exitcode)
pymain_header(config);
+ _PyInterpreterState_SetRunningMain(interp);
+ assert(!PyErr_Occurred());
+
if (config->run_command) {
*exitcode = pymain_run_command(config->run_command);
}
@@ -636,6 +639,7 @@ error:
*exitcode = pymain_exit_err_print();
done:
+ _PyInterpreterState_SetNotRunningMain(interp);
Py_XDECREF(main_importer_path);
}
diff --git a/Python/pystate.c b/Python/pystate.c
index 0430454..534e77f 100644
--- a/Python/pystate.c
+++ b/Python/pystate.c
@@ -1049,6 +1049,39 @@ _PyInterpreterState_DeleteExceptMain(_PyRuntimeState *runtime)
#endif
+int
+_PyInterpreterState_SetRunningMain(PyInterpreterState *interp)
+{
+ if (interp->threads_main != NULL) {
+ PyErr_SetString(PyExc_RuntimeError,
+ "interpreter already running");
+ return -1;
+ }
+ PyThreadState *tstate = current_fast_get(&_PyRuntime);
+ _Py_EnsureTstateNotNULL(tstate);
+ if (tstate->interp != interp) {
+ PyErr_SetString(PyExc_RuntimeError,
+ "current tstate has wrong interpreter");
+ return -1;
+ }
+ interp->threads_main = tstate;
+ return 0;
+}
+
+void
+_PyInterpreterState_SetNotRunningMain(PyInterpreterState *interp)
+{
+ assert(interp->threads_main == current_fast_get(&_PyRuntime));
+ interp->threads_main = NULL;
+}
+
+int
+_PyInterpreterState_IsRunningMain(PyInterpreterState *interp)
+{
+ return (interp->threads_main != NULL);
+}
+
+
//----------
// accessors
//----------
@@ -2757,6 +2790,10 @@ _register_builtins_for_crossinterpreter_data(struct _xidregistry *xidregistry)
}
+/*************/
+/* Other API */
+/*************/
+
_PyFrameEvalFunction
_PyInterpreterState_GetEvalFrameFunc(PyInterpreterState *interp)
{