diff options
author | Eric Snow <ericsnowcurrently@gmail.com> | 2023-11-28 02:01:05 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-11-28 02:01:05 (GMT) |
commit | 0122b4d7c92855e97912cf827dd81d836725c9a4 (patch) | |
tree | 4a1e3355d8bf5e9d2b9f36745518f56f590df021 | |
parent | 82ae5a609d9a2c0ff2384527a18ff1caf7410052 (diff) | |
download | cpython-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.abi | 228 | ||||
-rw-r--r-- | Include/internal/pycore_interp.h | 2 | ||||
-rw-r--r-- | Include/internal/pycore_pystate.h | 5 | ||||
-rw-r--r-- | Lib/test/test_interpreters.py | 97 | ||||
-rw-r--r-- | Lib/test/test_threading.py | 49 | ||||
-rw-r--r-- | Lib/threading.py | 4 | ||||
-rw-r--r-- | Misc/NEWS.d/next/Core and Builtins/2023-09-26-14-00-25.gh-issue-105716.SUJkW1.rst | 3 | ||||
-rw-r--r-- | Modules/_threadmodule.c | 16 | ||||
-rw-r--r-- | Modules/_xxsubinterpretersmodule.c | 90 | ||||
-rw-r--r-- | Modules/main.c | 4 | ||||
-rw-r--r-- | Python/pystate.c | 37 |
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) { |