File tree Expand file tree Collapse file tree
Expand file tree Collapse file tree Original file line number Diff line number Diff line change @@ -42,6 +42,7 @@ generate-import-lib = ["pyo3-build-config/python3-dll-a"]
4242paste = " 1"
4343
4444[build-dependencies ]
45+ cc = " 1.2"
4546pyo3-build-config = { path = " ../pyo3-build-config" , version = " =0.23.3" , features = [" resolve-config" ] }
4647
4748[lints ]
Original file line number Diff line number Diff line change @@ -182,6 +182,22 @@ fn emit_link_config(interpreter_config: &InterpreterConfig) -> Result<()> {
182182 Ok ( ( ) )
183183}
184184
185+ fn do_cc ( interpreter_config : & InterpreterConfig ) -> Result < ( ) > {
186+ let implementation_def = match interpreter_config. implementation {
187+ PythonImplementation :: CPython => "PYTHON_IS_CPYTHON" ,
188+ PythonImplementation :: PyPy => "PYTHON_IS_PYPY" ,
189+ PythonImplementation :: GraalPy => "PYTHON_IS_GRAALPY" ,
190+ } ;
191+ println ! ( "cargo:rerun-if-changed=src/acquire_gil.cpp" ) ;
192+ cc:: Build :: new ( )
193+ . cpp ( true )
194+ . file ( "src/acquire_gil.cpp" )
195+ . define ( implementation_def, None )
196+ . cpp_link_stdlib ( "stdc++" )
197+ . compile ( "acquire_gil" ) ;
198+ Ok ( ( ) )
199+ }
200+
185201/// Prepares the PyO3 crate for compilation.
186202///
187203/// This loads the config from pyo3-build-config and then makes some additional checks to improve UX
@@ -218,6 +234,8 @@ fn configure_pyo3() -> Result<()> {
218234 // Emit cfgs like `invalid_from_utf8_lint`
219235 print_feature_cfgs ( ) ;
220236
237+ do_cc ( & interpreter_config) ?;
238+
221239 Ok ( ( ) )
222240}
223241
Original file line number Diff line number Diff line change 1+ #if defined(_WIN32)
2+ #include < windows.h>
3+ #include < synchapi.h>
4+ #else
5+ #include < unistd.h>
6+ #endif
7+
8+ #if defined(PYTHON_IS_PYPY)
9+ #define gil_func_name PyPyGILState_Ensure
10+ #define wrapped_func_name PyPyGILState_Ensure_Safe
11+ #else
12+ #define gil_func_name PyGILState_Ensure
13+ #define wrapped_func_name PyGILState_Ensure_Safe
14+ #endif
15+
16+ extern " C" {
17+ int wrapped_func_name (void );
18+ int gil_func_name (void );
19+ };
20+
21+ #if !defined(_WIN32)
22+ // mark the wrapped function as visibility("hidden") to avoid causing namespace pollution
23+ __attribute__ ((visibility(" hidden" )))
24+ #endif
25+ int wrapped_func_name (void ) {
26+ // Do the equivalent of https://github.com/python/cpython/issues/87135 (included
27+ // in Python 3.14) to avoid pthread_exit unwinding the current thread, which tends
28+ // to cause undefined behavior in Rust.
29+ //
30+ // Unfortunately, I don't know of a way to do a catch(...) from Rust.
31+ try {
32+ return gil_func_name ();
33+ } catch (...) {
34+ while (1 ) {
35+ #if defined(_WIN32)
36+ SleepEx (INFINITE, TRUE );
37+ #elif defined(__wasi__)
38+ sleep (9999999 ); // WASI doesn't have pause() ?!
39+ #else
40+ pause ();
41+ #endif
42+ }
43+ }
44+ }
45+
Original file line number Diff line number Diff line change @@ -74,7 +74,13 @@ pub enum PyGILState_STATE {
7474}
7575
7676extern "C" {
77- #[ cfg_attr( PyPy , link_name = "PyPyGILState_Ensure" ) ]
77+ // The PyGILState_Ensure function will call pthread_exit during interpreter shutdown,
78+ // which causes undefined behavior. Redirect to the "safe" version that hangs instead,
79+ // as Python 3.14 does.
80+ //
81+ // See https://github.com/rust-lang/rust/issues/135929
82+ #[ cfg_attr( PyPy , link_name = "PyPyGILState_Ensure_Safe" ) ]
83+ #[ cfg_attr( not( PyPy ) , link_name = "PyGILState_Ensure_Safe" ) ]
7884 pub fn PyGILState_Ensure ( ) -> PyGILState_STATE ;
7985 #[ cfg_attr( PyPy , link_name = "PyPyGILState_Release" ) ]
8086 pub fn PyGILState_Release ( arg1 : PyGILState_STATE ) ;
You can’t perform that action at this time.
0 commit comments