@@ -79,68 +79,19 @@ pub enum PyGILState_STATE {
7979 PyGILState_UNLOCKED ,
8080}
8181
82- #[ cfg( not( any( Py_3_14 , target_arch = "wasm32" ) ) ) ]
83- struct HangThread ;
84-
85- #[ cfg( not( any( Py_3_14 , target_arch = "wasm32" ) ) ) ]
86- impl Drop for HangThread {
87- fn drop ( & mut self ) {
88- loop {
89- core:: thread:: park ( ) ; // Block forever.
90- }
91- }
92- }
93-
94- // The PyGILState_Ensure function will call pthread_exit during interpreter shutdown,
95- // which causes undefined behavior. Redirect to the "safe" version that hangs instead,
96- // as Python 3.14 does.
97- //
98- // See https://github.com/rust-lang/rust/issues/135929
99-
10082// C-unwind only supported (and necessary) since 1.71. Python 3.14+ does not do
10183// pthread_exit from PyGILState_Ensure (https://github.com/python/cpython/issues/87135).
102- mod raw {
103- #[ cfg( not( any( Py_3_14 , target_arch = "wasm32" ) ) ) ]
104- extern_libpython ! { "C-unwind" {
105- #[ cfg_attr( PyPy , link_name = "PyPyGILState_Ensure" ) ]
106- pub fn PyGILState_Ensure ( ) -> super :: PyGILState_STATE ;
107- } }
108-
109- #[ cfg( any( Py_3_14 , target_arch = "wasm32" ) ) ]
110- extern_libpython ! {
111- #[ cfg_attr( PyPy , link_name = "PyPyGILState_Ensure" ) ]
112- pub fn PyGILState_Ensure ( ) -> super :: PyGILState_STATE ;
113- }
114- }
115-
11684#[ cfg( not( any( Py_3_14 , target_arch = "wasm32" ) ) ) ]
117- pub unsafe extern "C" fn PyGILState_Ensure ( ) -> PyGILState_STATE {
118- let guard = HangThread ;
119- // If `PyGILState_Ensure` calls `pthread_exit`, which it does on Python < 3.14
120- // when the interpreter is shutting down, this will cause a forced unwind.
121- // doing a forced unwind through a function with a Rust destructor is unspecified
122- // behavior.
123- //
124- // However, currently it runs the destructor, which will cause the thread to
125- // hang as it should.
126- //
127- // And if we don't catch the unwinding here, then one of our callers probably has a destructor,
128- // so it's unspecified behavior anyway, and on many configurations causes the process to abort.
129- //
130- // The alternative is for pyo3 to contain custom C or C++ code that catches the `pthread_exit`,
131- // but that's also annoying from a portability point of view.
132- //
133- // On Windows, `PyGILState_Ensure` calls `_endthreadex` instead, which AFAICT can't be caught
134- // and therefore will cause unsafety if there are pinned objects on the stack. AFAICT there's
135- // nothing we can do it other than waiting for Python 3.14 or not using Windows. At least,
136- // if there is nothing pinned on the stack, it won't cause the process to crash.
137- let ret: PyGILState_STATE = raw:: PyGILState_Ensure ( ) ;
138- core:: mem:: forget ( guard) ;
139- ret
140- }
85+ extern_libpython ! { "C-unwind" {
86+ #[ cfg_attr( PyPy , link_name = "PyPyGILState_Ensure" ) ]
87+ pub fn PyGILState_Ensure ( ) -> super :: PyGILState_STATE ;
88+ } }
14189
14290#[ cfg( any( Py_3_14 , target_arch = "wasm32" ) ) ]
143- pub use self :: raw:: PyGILState_Ensure ;
91+ extern_libpython ! {
92+ #[ cfg_attr( PyPy , link_name = "PyPyGILState_Ensure" ) ]
93+ pub fn PyGILState_Ensure ( ) -> super :: PyGILState_STATE ;
94+ }
14495
14596extern_libpython ! {
14697 #[ cfg_attr( PyPy , link_name = "PyPyGILState_Release" ) ]
0 commit comments