Skip to content

Commit 5f4c90a

Browse files
committed
move thread state guard into the crate root
1 parent 74bc5dd commit 5f4c90a

File tree

2 files changed

+21
-13
lines changed

2 files changed

+21
-13
lines changed

src/lib.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,23 @@ mod doctest {
149149
#[inline(always)]
150150
fn cold() {}
151151

152+
/// An RAII guard for avoiding deadlocks with the GIL or other global
153+
/// synchronization events in the Python runtime
154+
// FIXME create a proper MutexExt trait that handles poisoning and upstream to PyO3
155+
struct ThreadStateGuard(*mut pyo3::ffi::PyThreadState);
156+
157+
impl ThreadStateGuard {
158+
fn new() -> ThreadStateGuard {
159+
ThreadStateGuard(unsafe { pyo3::ffi::PyEval_SaveThread() })
160+
}
161+
}
162+
163+
impl Drop for ThreadStateGuard {
164+
fn drop(&mut self) {
165+
unsafe { pyo3::ffi::PyEval_RestoreThread(self.0) };
166+
}
167+
}
168+
152169
/// Create a [`PyArray`] with one, two or three dimensions.
153170
///
154171
/// This macro is backed by [`ndarray::array`].

src/strings.rs

Lines changed: 4 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ use rustc_hash::FxHashMap;
1919
use crate::dtype::{clone_methods_impl, Element, PyArrayDescr, PyArrayDescrMethods};
2020
use crate::npyffi::PyDataType_SET_ELSIZE;
2121
use crate::npyffi::NPY_TYPES;
22+
use crate::ThreadStateGuard;
2223

2324
/// A newtype wrapper around [`[u8; N]`][Py_UCS1] to handle [`byte` scalars][numpy-bytes] while satisfying coherence.
2425
///
@@ -178,22 +179,12 @@ impl TypeDescriptors {
178179
byteorder: c_char,
179180
size: usize,
180181
) -> Bound<'py, PyArrayDescr> {
181-
// FIXME create a proper MutexExt trait that handles poisoning and upstream to PyO3
182-
struct Guard(*mut pyo3::ffi::PyThreadState);
183-
184-
impl Drop for Guard {
185-
fn drop(&mut self) {
186-
unsafe { pyo3::ffi::PyEval_RestoreThread(self.0) };
187-
}
188-
}
189-
190-
// we are currently attached to the python runtime and we might block trying to acquire
191-
// the dtype cache mutex, so detach to avoid a possible deadlock.
192-
let ts_guard = Guard(unsafe { pyo3::ffi::PyEval_SaveThread() });
182+
// Detach from the runtime to avoid deadlocking on acquiring the mutex.
183+
let ts_guard = ThreadStateGuard::new();
193184

194185
let mut dtypes = self.dtypes.lock().expect("dtype cache poisoned");
195186

196-
// we've acquire the dtype cache lock so it's safe to re-attach to the runtime
187+
// Now we hold the mutex so it's safe to re-attach to the runtime.
197188
drop(ts_guard);
198189

199190
let dtype = match dtypes.get_or_insert_with(Default::default).entry(size) {

0 commit comments

Comments
 (0)