Skip to content

Commit

Permalink
add pyo3::types::mutex for PyMutex wrappers
Browse files Browse the repository at this point in the history
  • Loading branch information
ngoldbaum committed Sep 3, 2024
1 parent ff90dae commit 632ff75
Show file tree
Hide file tree
Showing 2 changed files with 89 additions and 0 deletions.
3 changes: 3 additions & 0 deletions src/types/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ pub use self::list::{PyList, PyListMethods};
pub use self::mapping::{PyMapping, PyMappingMethods};
pub use self::memoryview::PyMemoryView;
pub use self::module::{PyModule, PyModuleMethods};
pub use self::mutex::{PyMutex, PyMutexGuard};
pub use self::none::PyNone;
pub use self::notimplemented::PyNotImplemented;
#[allow(deprecated)]
Expand Down Expand Up @@ -243,6 +244,8 @@ pub(crate) mod list;
pub(crate) mod mapping;
mod memoryview;
pub(crate) mod module;
#[cfg(Py_3_13)]
mod mutex;
mod none;
mod notimplemented;
mod num;
Expand Down
86 changes: 86 additions & 0 deletions src/types/mutex.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
use std::ops::Deref;

/// Wrapper for [`PyMutex`](https://docs.python.org/3/c-api/init.html#c.PyMutex) exposing an RAII interface.
#[derive(Debug)]
pub struct PyMutex<T> {
_mutex: crate::ffi::PyMutex,
data: T,
}

/// RAII guard to handle releasing a PyMutex lock.
#[derive(Debug)]
pub struct PyMutexGuard<'a, T> {
_mutex: &'a mut crate::ffi::PyMutex,
data: &'a T,
}

impl<T> PyMutex<T> {
/// Acquire the mutex, blocking the current thread until it is able to do so.
pub fn lock(&mut self) -> PyMutexGuard<'_, T> {
unsafe { crate::ffi::PyMutex_Lock(&mut self._mutex) };
PyMutexGuard {
_mutex: &mut self._mutex,
data: &self.data,
}
}

/// Create a new mutex in an unlocked state ready for use.
pub fn new(value: T) -> Self {
Self {
_mutex: crate::ffi::PyMutex::new(),
data: value,
}
}
}

impl<'a, T> Drop for PyMutexGuard<'a, T> {
fn drop(&mut self) {
unsafe { crate::ffi::PyMutex_Unlock(self._mutex) };
}
}

impl<'a, T> Deref for PyMutexGuard<'a, T> {
type Target = T;

fn deref(&self) -> &T {
self.data
}
}

#[cfg(test)]
mod tests {
use super::*;
use crate::types::{PyAnyMethods, PyDict, PyDictMethods, PyList, PyNone};
use crate::Python;

#[test]
fn test_pymutex() {
Python::with_gil(|py| {
let d = PyDict::new(py);
let mut mutex = PyMutex::new(&d);

let list = Python::with_gil(|py| PyList::new(py, vec!["foo", "bar"]).unbind());
let dict_guard = mutex.lock();

py.allow_threads(|| {
std::thread::spawn(move || {
drop(list);
})
.join()
.unwrap();
});

dict_guard
.set_item(PyNone::get(py), PyNone::get(py))
.unwrap();
drop(dict_guard);

assert!(d
.get_item(PyNone::get(py))
.unwrap()
.unwrap()
.eq(PyNone::get(py))
.unwrap());
});
}
}

0 comments on commit 632ff75

Please sign in to comment.