1 | #[cfg (all(Py_3_10, not(PyPy), not(Py_LIMITED_API)))] |
2 | use crate::frameobject::PyFrameObject; |
3 | use crate::moduleobject::PyModuleDef; |
4 | use crate::object::PyObject; |
5 | use std::os::raw::c_int; |
6 | |
7 | #[cfg (not(PyPy))] |
8 | use std::os::raw::c_long; |
9 | |
10 | pub const MAX_CO_EXTRA_USERS: c_int = 255; |
11 | |
12 | opaque_struct!(PyThreadState); |
13 | opaque_struct!(PyInterpreterState); |
14 | |
15 | unsafeextern "C" { |
16 | #[cfg (not(PyPy))] |
17 | pub unsafefn PyInterpreterState_New() -> *mut PyInterpreterState; |
18 | #[cfg (not(PyPy))] |
19 | pub unsafefn PyInterpreterState_Clear(arg1: *mut PyInterpreterState); |
20 | #[cfg (not(PyPy))] |
21 | pub unsafefn PyInterpreterState_Delete(arg1: *mut PyInterpreterState); |
22 | |
23 | #[cfg (all(Py_3_9, not(PyPy)))] |
24 | pub unsafefn PyInterpreterState_Get() -> *mut PyInterpreterState; |
25 | |
26 | #[cfg (all(Py_3_8, not(PyPy)))] |
27 | pub unsafefn PyInterpreterState_GetDict(arg1: *mut PyInterpreterState) -> *mut PyObject; |
28 | |
29 | #[cfg (not(PyPy))] |
30 | pub unsafefn PyInterpreterState_GetID(arg1: *mut PyInterpreterState) -> i64; |
31 | |
32 | #[cfg_attr (PyPy, link_name = "PyPyState_AddModule" )] |
33 | pub unsafefn PyState_AddModule(arg1: *mut PyObject, arg2: *mut PyModuleDef) -> c_int; |
34 | |
35 | #[cfg_attr (PyPy, link_name = "PyPyState_RemoveModule" )] |
36 | pub unsafefn PyState_RemoveModule(arg1: *mut PyModuleDef) -> c_int; |
37 | |
38 | // only has PyPy prefix since 3.10 |
39 | #[cfg_attr (all(PyPy, Py_3_10), link_name = "PyPyState_FindModule" )] |
40 | pub unsafefn PyState_FindModule(arg1: *mut PyModuleDef) -> *mut PyObject; |
41 | |
42 | #[cfg_attr (PyPy, link_name = "PyPyThreadState_New" )] |
43 | pub unsafefn PyThreadState_New(arg1: *mut PyInterpreterState) -> *mut PyThreadState; |
44 | #[cfg_attr (PyPy, link_name = "PyPyThreadState_Clear" )] |
45 | pub unsafefn PyThreadState_Clear(arg1: *mut PyThreadState); |
46 | #[cfg_attr (PyPy, link_name = "PyPyThreadState_Delete" )] |
47 | pub unsafefn PyThreadState_Delete(arg1: *mut PyThreadState); |
48 | |
49 | #[cfg_attr (PyPy, link_name = "PyPyThreadState_Get" )] |
50 | pub unsafefn PyThreadState_Get() -> *mut PyThreadState; |
51 | } |
52 | |
53 | #[inline ] |
54 | pub unsafe fn PyThreadState_GET() -> *mut PyThreadState { |
55 | PyThreadState_Get() |
56 | } |
57 | |
58 | unsafeextern "C" { |
59 | #[cfg_attr (PyPy, link_name = "PyPyThreadState_Swap" )] |
60 | pub unsafefn PyThreadState_Swap(arg1: *mut PyThreadState) -> *mut PyThreadState; |
61 | #[cfg_attr (PyPy, link_name = "PyPyThreadState_GetDict" )] |
62 | pub unsafefn PyThreadState_GetDict() -> *mut PyObject; |
63 | #[cfg (not(PyPy))] |
64 | pub unsafefn PyThreadState_SetAsyncExc(arg1: c_long, arg2: *mut PyObject) -> c_int; |
65 | } |
66 | |
67 | // skipped non-limited / 3.9 PyThreadState_GetInterpreter |
68 | // skipped non-limited / 3.9 PyThreadState_GetID |
69 | |
70 | unsafeextern "C" { |
71 | // PyThreadState_GetFrame |
72 | #[cfg (all(Py_3_10, not(PyPy), not(Py_LIMITED_API)))] |
73 | pub fn PyThreadState_GetFrame(arg1: *mut PyThreadState) -> *mut PyFrameObject; |
74 | } |
75 | |
76 | #[repr (C)] |
77 | #[derive (Copy, Clone, Debug, PartialEq, Eq)] |
78 | pub enum PyGILState_STATE { |
79 | PyGILState_LOCKED, |
80 | PyGILState_UNLOCKED, |
81 | } |
82 | |
83 | struct HangThread; |
84 | |
85 | impl Drop for HangThread { |
86 | fn drop(&mut self) { |
87 | loop { |
88 | #[cfg (target_family = "unix" )] |
89 | unsafe { |
90 | libc::pause(); |
91 | } |
92 | #[cfg (not(target_family = "unix" ))] |
93 | std::thread::sleep(std::time::Duration::from_secs(9_999_999)); |
94 | } |
95 | } |
96 | } |
97 | |
98 | // The PyGILState_Ensure function will call pthread_exit during interpreter shutdown, |
99 | // which causes undefined behavior. Redirect to the "safe" version that hangs instead, |
100 | // as Python 3.14 does. |
101 | // |
102 | // See https://github.com/rust-lang/rust/issues/135929 |
103 | |
104 | // C-unwind only supported (and necessary) since 1.71. Python 3.14+ does not do |
105 | // pthread_exit from PyGILState_Ensure (https://github.com/python/cpython/issues/87135). |
106 | mod raw { |
107 | #[cfg (all(not(Py_3_14), rustc_has_extern_c_unwind))] |
108 | unsafeextern "C-unwind" { |
109 | #[cfg_attr (PyPy, link_name = "PyPyGILState_Ensure" )] |
110 | pub unsafefn PyGILState_Ensure() -> super::PyGILState_STATE; |
111 | } |
112 | |
113 | #[cfg (not(all(not(Py_3_14), rustc_has_extern_c_unwind)))] |
114 | extern "C" { |
115 | #[cfg_attr (PyPy, link_name = "PyPyGILState_Ensure" )] |
116 | pub fn PyGILState_Ensure() -> super::PyGILState_STATE; |
117 | } |
118 | } |
119 | |
120 | #[cfg (not(Py_3_14))] |
121 | pub unsafe extern "C" fn PyGILState_Ensure() -> PyGILState_STATE { |
122 | let guard: HangThread = HangThread; |
123 | // If `PyGILState_Ensure` calls `pthread_exit`, which it does on Python < 3.14 |
124 | // when the interpreter is shutting down, this will cause a forced unwind. |
125 | // doing a forced unwind through a function with a Rust destructor is unspecified |
126 | // behavior. |
127 | // |
128 | // However, currently it runs the destructor, which will cause the thread to |
129 | // hang as it should. |
130 | // |
131 | // And if we don't catch the unwinding here, then one of our callers probably has a destructor, |
132 | // so it's unspecified behavior anyway, and on many configurations causes the process to abort. |
133 | // |
134 | // The alternative is for pyo3 to contain custom C or C++ code that catches the `pthread_exit`, |
135 | // but that's also annoying from a portability point of view. |
136 | // |
137 | // On Windows, `PyGILState_Ensure` calls `_endthreadex` instead, which AFAICT can't be caught |
138 | // and therefore will cause unsafety if there are pinned objects on the stack. AFAICT there's |
139 | // nothing we can do it other than waiting for Python 3.14 or not using Windows. At least, |
140 | // if there is nothing pinned on the stack, it won't cause the process to crash. |
141 | let ret: PyGILState_STATE = raw::PyGILState_Ensure(); |
142 | std::mem::forget(guard); |
143 | ret |
144 | } |
145 | |
146 | #[cfg (Py_3_14)] |
147 | pub use self::raw::PyGILState_Ensure; |
148 | |
149 | unsafeextern "C" { |
150 | #[cfg_attr (PyPy, link_name = "PyPyGILState_Release" )] |
151 | pub unsafefn PyGILState_Release(arg1: PyGILState_STATE); |
152 | #[cfg (not(PyPy))] |
153 | pub unsafefn PyGILState_GetThisThreadState() -> *mut PyThreadState; |
154 | } |
155 | |