File tree 4 files changed +71
-1
lines changed
4 files changed +71
-1
lines changed Original file line number Diff line number Diff line change @@ -42,6 +42,7 @@ generate-import-lib = ["pyo3-build-config/python3-dll-a"]
42
42
paste = " 1"
43
43
44
44
[build-dependencies ]
45
+ cc = " 1.2"
45
46
pyo3-build-config = { path = " ../pyo3-build-config" , version = " =0.23.3" , features = [" resolve-config" ] }
46
47
47
48
[lints ]
Original file line number Diff line number Diff line change @@ -182,6 +182,22 @@ fn emit_link_config(interpreter_config: &InterpreterConfig) -> Result<()> {
182
182
Ok ( ( ) )
183
183
}
184
184
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
+
185
201
/// Prepares the PyO3 crate for compilation.
186
202
///
187
203
/// 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<()> {
218
234
// Emit cfgs like `invalid_from_utf8_lint`
219
235
print_feature_cfgs ( ) ;
220
236
237
+ do_cc ( & interpreter_config) ?;
238
+
221
239
Ok ( ( ) )
222
240
}
223
241
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 {
74
74
}
75
75
76
76
extern "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" ) ]
78
84
pub fn PyGILState_Ensure ( ) -> PyGILState_STATE ;
79
85
#[ cfg_attr( PyPy , link_name = "PyPyGILState_Release" ) ]
80
86
pub fn PyGILState_Release ( arg1 : PyGILState_STATE ) ;
You can’t perform that action at this time.
0 commit comments