Move GIL counting from GILPool to GILGuard (#4188)

This commit is contained in:
Alex Gaynor 2024-05-17 00:25:41 -04:00 committed by GitHub
parent 88f2f6f4d5
commit 1c64a03ea0
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 39 additions and 23 deletions

View File

@ -167,6 +167,7 @@ impl GILGuard {
/// `GILGuard::Ensured` will be returned.
pub(crate) fn acquire() -> Self {
if gil_is_acquired() {
increment_gil_count();
return GILGuard::Assumed;
}
@ -215,6 +216,7 @@ impl GILGuard {
/// as part of multi-phase interpreter initialization.
pub(crate) fn acquire_unchecked() -> Self {
if gil_is_acquired() {
increment_gil_count();
return GILGuard::Assumed;
}
@ -222,8 +224,21 @@ impl GILGuard {
#[allow(deprecated)]
let pool = unsafe { mem::ManuallyDrop::new(GILPool::new()) };
increment_gil_count();
GILGuard::Ensured { gstate, pool }
}
/// Acquires the `GILGuard` while assuming that the GIL is already held.
pub(crate) unsafe fn assume() -> Self {
increment_gil_count();
GILGuard::Assumed
}
/// Gets the Python token associated with this [`GILGuard`].
#[inline]
pub fn python(&self) -> Python<'_> {
unsafe { Python::assume_gil_acquired() }
}
}
/// The Drop implementation for `GILGuard` will release the GIL.
@ -238,6 +253,7 @@ impl Drop for GILGuard {
ffi::PyGILState_Release(*gstate);
},
}
decrement_gil_count();
}
}
@ -378,7 +394,6 @@ impl GILPool {
/// As well as requiring the GIL, see the safety notes on `Python::new_pool`.
#[inline]
pub unsafe fn new() -> GILPool {
increment_gil_count();
// Update counts of PyObjects / Py that have been cloned or dropped since last acquisition
#[cfg(not(pyo3_disable_reference_pool))]
POOL.update_counts(Python::assume_gil_acquired());
@ -427,7 +442,6 @@ impl Drop for GILPool {
}
}
}
decrement_gil_count();
}
}
@ -687,19 +701,19 @@ mod tests {
assert_eq!(get_gil_count(), 1);
let pool = unsafe { GILPool::new() };
assert_eq!(get_gil_count(), 2);
assert_eq!(get_gil_count(), 1);
let pool2 = unsafe { GILPool::new() };
assert_eq!(get_gil_count(), 3);
assert_eq!(get_gil_count(), 1);
drop(pool);
assert_eq!(get_gil_count(), 2);
assert_eq!(get_gil_count(), 1);
Python::with_gil(|_| {
// nested with_gil doesn't update gil count
assert_eq!(get_gil_count(), 2);
});
assert_eq!(get_gil_count(), 2);
assert_eq!(get_gil_count(), 1);
drop(pool2);
assert_eq!(get_gil_count(), 1);

View File

@ -9,8 +9,7 @@ use std::{
panic::{self, UnwindSafe},
};
#[allow(deprecated)]
use crate::gil::GILPool;
use crate::gil::GILGuard;
use crate::{
callback::PyCallbackOutput, ffi, ffi_ptr_ext::FfiPtrExt, impl_::panic::PanicTrap,
methods::IPowModulo, panic::PanicException, types::PyModule, Py, PyResult, Python,
@ -171,17 +170,19 @@ trampoline!(
///
/// Panics during execution are trapped so that they don't propagate through any
/// outer FFI boundary.
///
/// The GIL must already be held when this is called.
#[inline]
pub(crate) fn trampoline<F, R>(body: F) -> R
pub(crate) unsafe fn trampoline<F, R>(body: F) -> R
where
F: for<'py> FnOnce(Python<'py>) -> PyResult<R> + UnwindSafe,
R: PyCallbackOutput,
{
let trap = PanicTrap::new("uncaught panic at ffi boundary");
// Necessary to construct a pool until PyO3 0.22 when the GIL Refs API is fully disabled
#[allow(deprecated)]
let pool = unsafe { GILPool::new() };
let py = pool.python();
// SAFETY: This function requires the GIL to already be held.
let guard = GILGuard::assume();
let py = guard.python();
let out = panic_result_into_callback_output(
py,
panic::catch_unwind(move || -> PyResult<_> { body(py) }),
@ -218,17 +219,19 @@ where
///
/// # Safety
///
/// ctx must be either a valid ffi::PyObject or NULL
/// - ctx must be either a valid ffi::PyObject or NULL
/// - The GIL must already be held when this is called.
#[inline]
unsafe fn trampoline_unraisable<F>(body: F, ctx: *mut ffi::PyObject)
where
F: for<'py> FnOnce(Python<'py>) -> PyResult<()> + UnwindSafe,
{
let trap = PanicTrap::new("uncaught panic at ffi boundary");
// Necessary to construct a pool until PyO3 0.22 when the GIL Refs API is fully disabled
#[allow(deprecated)]
let pool = GILPool::new();
let py = pool.python();
// SAFETY: The GIL is already held.
let guard = GILGuard::assume();
let py = guard.python();
if let Err(py_err) = panic::catch_unwind(move || body(py))
.unwrap_or_else(|payload| Err(PanicException::from_panic_payload(payload)))
{

View File

@ -411,10 +411,10 @@ impl Python<'_> {
where
F: for<'py> FnOnce(Python<'py>) -> R,
{
let _guard = GILGuard::acquire();
let guard = GILGuard::acquire();
// SAFETY: Either the GIL was already acquired or we just created a new `GILGuard`.
f(unsafe { Python::assume_gil_acquired() })
f(guard.python())
}
/// Like [`Python::with_gil`] except Python interpreter state checking is skipped.
@ -445,10 +445,9 @@ impl Python<'_> {
where
F: for<'py> FnOnce(Python<'py>) -> R,
{
let _guard = GILGuard::acquire_unchecked();
let guard = GILGuard::acquire_unchecked();
// SAFETY: Either the GIL was already acquired or we just created a new `GILGuard`.
f(Python::assume_gil_acquired())
f(guard.python())
}
}