Mercurial > hg-stable
changeset 43176:aaec70a5f9a8
rust-cpython: store leaked reference to PySharedState in $leaked struct
I want to move it out of the macro, and allow multiple sharable objects
per PyObject.
author | Yuya Nishihara <yuya@tcha.org> |
---|---|
date | Sun, 15 Sep 2019 16:04:45 +0900 |
parents | a1908eb08342 |
children | 5cb8867c9e2b |
files | rust/hg-cpython/src/ref_sharing.rs |
diffstat | 1 files changed, 26 insertions(+), 11 deletions(-) [+] |
line wrap: on
line diff
--- a/rust/hg-cpython/src/ref_sharing.rs Tue Sep 17 07:59:25 2019 +0900 +++ b/rust/hg-cpython/src/ref_sharing.rs Sun Sep 15 16:04:45 2019 +0900 @@ -74,8 +74,8 @@ } } - /// Return a reference to the wrapped data with an artificial static - /// lifetime. + /// Return a reference to the wrapped data and its state with an + /// artificial static lifetime. /// We need to be protected by the GIL for thread-safety. /// /// # Safety @@ -86,7 +86,7 @@ &self, py: Python, data: &PySharedRefCell<T>, - ) -> PyResult<&'static T> { + ) -> PyResult<(&'static T, &'static PySharedState)> { if self.mutably_borrowed.get() { return Err(AlreadyBorrowed::new( py, @@ -94,9 +94,12 @@ mutable reference in Python objects", )); } + // TODO: it's weird that self is data.py_shared_state. Maybe we + // can move stuff to PySharedRefCell? let ptr = data.as_ptr(); + let state_ptr: *const PySharedState = &data.py_shared_state; self.leak_count.replace(self.leak_count.get() + 1); - Ok(&*ptr) + Ok((&*ptr, &*state_ptr)) } /// # Safety @@ -267,9 +270,9 @@ // assert $data_member type use crate::ref_sharing::PySharedRefCell; let data: &PySharedRefCell<_> = self.$data_member(py); - let static_ref = + let (static_ref, static_state_ref) = data.py_shared_state.leak_immutable(py, data)?; - let leak_handle = $leaked::new(py, self); + let leak_handle = $leaked::new(py, self, static_state_ref); Ok((leak_handle, static_ref)) } } @@ -280,26 +283,38 @@ /// In truth, this does not represent leaked references themselves; /// it is instead useful alongside them to manage them. pub struct $leaked { - inner: $name, + _inner: $name, + py_shared_state: &'static crate::ref_sharing::PySharedState, } impl $leaked { + /// # Safety + /// + /// The `py_shared_state` must be owned by the `inner` Python + /// object. // Marked as unsafe so client code wouldn't construct $leaked // struct by mistake. Its drop() is unsafe. - unsafe fn new(py: Python, inner: &$name) -> Self { + unsafe fn new( + py: Python, + inner: &$name, + py_shared_state: &'static crate::ref_sharing::PySharedState, + ) -> Self { Self { - inner: inner.clone_ref(py), + _inner: inner.clone_ref(py), + py_shared_state, } } } impl Drop for $leaked { fn drop(&mut self) { + // py_shared_state should be alive since we do have + // a Python reference to the owner object. Taking GIL makes + // sure that the state is only accessed by this thread. let gil = Python::acquire_gil(); let py = gil.python(); - let state = &self.inner.$data_member(py).py_shared_state; unsafe { - state.decrease_leak_count(py, false); + self.py_shared_state.decrease_leak_count(py, false); } } }