Skip to content

Commit

Permalink
Add Py::get_frozen for GIL-independent access to frozen classes.
Browse files Browse the repository at this point in the history
  • Loading branch information
adamreichold committed May 16, 2023
1 parent edb9522 commit 63acd0c
Show file tree
Hide file tree
Showing 3 changed files with 38 additions and 2 deletions.
1 change: 1 addition & 0 deletions newsfragments/3158.added.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Add `Py::get_frozen` for GIL-indepedent access to internally synchronized frozen classes.
37 changes: 36 additions & 1 deletion src/instance.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
use crate::pyclass::boolean_struct::False;
// Copyright (c) 2017-present PyO3 Project and Contributors
use crate::conversion::PyTryFrom;
use crate::err::{self, PyDowncastError, PyErr, PyResult};
use crate::gil;
use crate::pycell::{PyBorrowError, PyBorrowMutError, PyCell};
use crate::pyclass::boolean_struct::{False, True};
use crate::types::{PyDict, PyString, PyTuple};
use crate::{
ffi, AsPyPointer, FromPyObject, IntoPy, IntoPyPointer, PyAny, PyClass, PyClassInitializer,
Expand Down Expand Up @@ -467,6 +467,41 @@ where
{
self.as_ref(py).try_borrow_mut()
}

/// Provide an immutable borrow of the value `T` without acquiring the GIL.
///
/// This is sound if the class is frozen and `Sync`.
///
/// # Examples
///
/// ```
/// use std::sync::atomic::{AtomicUsize, Ordering};
/// # use pyo3::prelude::*;
///
/// #[pyclass(frozen)]
/// struct FrozenCounter {
/// value: AtomicUsize,
/// }
///
/// let cell = Python::with_gil(|py| {
/// let counter = FrozenCounter { value: AtomicUsize::new(0) };
///
/// Py::new(py, counter).unwrap()
/// });
///
/// cell.get_frozen().value.fetch_add(1, Ordering::Relaxed);
/// ```
pub fn get_frozen(&self) -> &T
where
T: PyClass<Frozen = True> + Sync,
{
let any = self.as_ptr() as *const PyAny;
// SAFETY: The class itself is frozen and `Sync` and we do not access anything but `cell.contents.value`.
unsafe {
let cell: &PyCell<T> = PyNativeType::unchecked_downcast(&*any);
&*cell.get_ptr()
}
}
}

impl<T> Py<T> {
Expand Down
2 changes: 1 addition & 1 deletion src/pycell.rs
Original file line number Diff line number Diff line change
Expand Up @@ -450,7 +450,7 @@ impl<T: PyClass> PyCell<T> {
std::mem::swap(&mut *self.borrow_mut(), &mut *other.borrow_mut())
}

fn get_ptr(&self) -> *mut T {
pub(crate) fn get_ptr(&self) -> *mut T {
self.contents.value.get()
}

Expand Down

0 comments on commit 63acd0c

Please sign in to comment.