[PATCH 1 of 6 V3] rust-cpython: put leaked reference in PyLeakedRef
Raphaël Gomès
raphael.gomes at octobus.net
Sat Oct 19 15:41:55 EDT 2019
Great work on this series, thanks.
I'll admit it was a little hard to follow all of the intermediary steps
needed, but it's better that way for debugging I think.
I'll jump on the follow-up.
On 10/17/19 3:06 PM, Yuya Nishihara wrote:
> # HG changeset patch
> # User Yuya Nishihara <yuya at tcha.org>
> # Date 1568552779 -32400
> # Sun Sep 15 22:06:19 2019 +0900
> # Node ID 30ad653deb7fbe2196f3d2d9d97f9f650c8b7952
> # Parent 2c70dd03b74395fbec276a2e2d1d3b8347268a5d
> rust-cpython: put leaked reference in PyLeakedRef
>
> The next patch will make PyLeakedRef manage the lifetime of the underlying
> object. leak_handle.data.take() will be removed soon.
>
> diff --git a/rust/hg-cpython/src/dirstate/copymap.rs b/rust/hg-cpython/src/dirstate/copymap.rs
> --- a/rust/hg-cpython/src/dirstate/copymap.rs
> +++ b/rust/hg-cpython/src/dirstate/copymap.rs
> @@ -13,6 +13,7 @@ use std::cell::RefCell;
>
> use crate::dirstate::dirstate_map::DirstateMap;
> use crate::ref_sharing::PyLeakedRef;
> +use hg::DirstateMap as RustDirstateMap;
> use hg::{utils::hg_path::HgPathBuf, CopyMapIter};
>
> py_class!(pub class CopyMap |py| {
> @@ -104,7 +105,7 @@ impl CopyMap {
>
> py_shared_iterator!(
> CopyMapKeysIterator,
> - PyLeakedRef,
> + PyLeakedRef<&'static RustDirstateMap>,
> CopyMapIter<'static>,
> CopyMap::translate_key,
> Option<PyBytes>
> @@ -112,7 +113,7 @@ py_shared_iterator!(
>
> py_shared_iterator!(
> CopyMapItemsIterator,
> - PyLeakedRef,
> + PyLeakedRef<&'static RustDirstateMap>,
> CopyMapIter<'static>,
> CopyMap::translate_key_value,
> Option<(PyBytes, PyBytes)>
> diff --git a/rust/hg-cpython/src/dirstate/dirs_multiset.rs b/rust/hg-cpython/src/dirstate/dirs_multiset.rs
> --- a/rust/hg-cpython/src/dirstate/dirs_multiset.rs
> +++ b/rust/hg-cpython/src/dirstate/dirs_multiset.rs
> @@ -92,8 +92,9 @@ py_class!(pub class Dirs |py| {
> })
> }
> def __iter__(&self) -> PyResult<DirsMultisetKeysIterator> {
> - let (leak_handle, leaked_ref) =
> + let mut leak_handle =
> unsafe { self.inner_shared(py).leak_immutable()? };
> + let leaked_ref = leak_handle.data.take().unwrap();
> DirsMultisetKeysIterator::from_inner(
> py,
> leak_handle,
> @@ -125,7 +126,7 @@ impl Dirs {
>
> py_shared_iterator!(
> DirsMultisetKeysIterator,
> - PyLeakedRef,
> + PyLeakedRef<&'static DirsMultiset>,
> DirsMultisetIter<'static>,
> Dirs::translate_key,
> Option<PyBytes>
> diff --git a/rust/hg-cpython/src/dirstate/dirstate_map.rs b/rust/hg-cpython/src/dirstate/dirstate_map.rs
> --- a/rust/hg-cpython/src/dirstate/dirstate_map.rs
> +++ b/rust/hg-cpython/src/dirstate/dirstate_map.rs
> @@ -304,8 +304,9 @@ py_class!(pub class DirstateMap |py| {
> }
>
> def keys(&self) -> PyResult<DirstateMapKeysIterator> {
> - let (leak_handle, leaked_ref) =
> + let mut leak_handle =
> unsafe { self.inner_shared(py).leak_immutable()? };
> + let leaked_ref = leak_handle.data.take().unwrap();
> DirstateMapKeysIterator::from_inner(
> py,
> leak_handle,
> @@ -314,8 +315,9 @@ py_class!(pub class DirstateMap |py| {
> }
>
> def items(&self) -> PyResult<DirstateMapItemsIterator> {
> - let (leak_handle, leaked_ref) =
> + let mut leak_handle =
> unsafe { self.inner_shared(py).leak_immutable()? };
> + let leaked_ref = leak_handle.data.take().unwrap();
> DirstateMapItemsIterator::from_inner(
> py,
> leak_handle,
> @@ -324,8 +326,9 @@ py_class!(pub class DirstateMap |py| {
> }
>
> def __iter__(&self) -> PyResult<DirstateMapKeysIterator> {
> - let (leak_handle, leaked_ref) =
> + let mut leak_handle =
> unsafe { self.inner_shared(py).leak_immutable()? };
> + let leaked_ref = leak_handle.data.take().unwrap();
> DirstateMapKeysIterator::from_inner(
> py,
> leak_handle,
> @@ -443,8 +446,9 @@ py_class!(pub class DirstateMap |py| {
> }
>
> def copymapiter(&self) -> PyResult<CopyMapKeysIterator> {
> - let (leak_handle, leaked_ref) =
> + let mut leak_handle =
> unsafe { self.inner_shared(py).leak_immutable()? };
> + let leaked_ref = leak_handle.data.take().unwrap();
> CopyMapKeysIterator::from_inner(
> py,
> leak_handle,
> @@ -453,8 +457,9 @@ py_class!(pub class DirstateMap |py| {
> }
>
> def copymapitemsiter(&self) -> PyResult<CopyMapItemsIterator> {
> - let (leak_handle, leaked_ref) =
> + let mut leak_handle =
> unsafe { self.inner_shared(py).leak_immutable()? };
> + let leaked_ref = leak_handle.data.take().unwrap();
> CopyMapItemsIterator::from_inner(
> py,
> leak_handle,
> @@ -493,7 +498,7 @@ py_shared_ref!(DirstateMap, RustDirstate
>
> py_shared_iterator!(
> DirstateMapKeysIterator,
> - PyLeakedRef,
> + PyLeakedRef<&'static RustDirstateMap>,
> StateMapIter<'static>,
> DirstateMap::translate_key,
> Option<PyBytes>
> @@ -501,7 +506,7 @@ py_shared_iterator!(
>
> py_shared_iterator!(
> DirstateMapItemsIterator,
> - PyLeakedRef,
> + PyLeakedRef<&'static RustDirstateMap>,
> StateMapIter<'static>,
> DirstateMap::translate_key_value,
> Option<(PyBytes, PyObject)>
> diff --git a/rust/hg-cpython/src/ref_sharing.rs b/rust/hg-cpython/src/ref_sharing.rs
> --- a/rust/hg-cpython/src/ref_sharing.rs
> +++ b/rust/hg-cpython/src/ref_sharing.rs
> @@ -187,23 +187,24 @@ impl<'a, T> PySharedRef<'a, T> {
> self.data.borrow_mut(self.py)
> }
>
> - /// Returns a leaked reference and its management object.
> + /// Returns a leaked reference temporarily held by its management object.
> ///
> /// # Safety
> ///
> /// It's up to you to make sure that the management object lives
> /// longer than the leaked reference. Otherwise, you'll get a
> /// dangling reference.
> - pub unsafe fn leak_immutable(
> - &self,
> - ) -> PyResult<(PyLeakedRef, &'static T)> {
> + pub unsafe fn leak_immutable(&self) -> PyResult<PyLeakedRef<&'static T>> {
> let (static_ref, static_state_ref) = self
> .data
> .py_shared_state
> .leak_immutable(self.py, self.data)?;
> - let leak_handle =
> - PyLeakedRef::new(self.py, self.owner, static_state_ref);
> - Ok((leak_handle, static_ref))
> + Ok(PyLeakedRef::new(
> + self.py,
> + self.owner,
> + static_ref,
> + static_state_ref,
> + ))
> }
> }
>
> @@ -318,12 +319,13 @@ macro_rules! py_shared_ref {
> ///
> /// In truth, this does not represent leaked references themselves;
> /// it is instead useful alongside them to manage them.
> -pub struct PyLeakedRef {
> +pub struct PyLeakedRef<T> {
> _inner: PyObject,
> + pub data: Option<T>, // TODO: remove pub
> py_shared_state: &'static PySharedState,
> }
>
> -impl PyLeakedRef {
> +impl<T> PyLeakedRef<T> {
> /// # Safety
> ///
> /// The `py_shared_state` must be owned by the `inner` Python object.
> @@ -332,16 +334,18 @@ impl PyLeakedRef {
> pub unsafe fn new(
> py: Python,
> inner: &PyObject,
> + data: T,
> py_shared_state: &'static PySharedState,
> ) -> Self {
> Self {
> _inner: inner.clone_ref(py),
> + data: Some(data),
> py_shared_state,
> }
> }
> }
>
> -impl Drop for PyLeakedRef {
> +impl<T> Drop for PyLeakedRef<T> {
> fn drop(&mut self) {
> // py_shared_state should be alive since we do have
> // a Python reference to the owner object. Taking GIL makes
> @@ -379,8 +383,9 @@ impl Drop for PyLeakedRef {
> /// data inner: PySharedRefCell<MyStruct>;
> ///
> /// def __iter__(&self) -> PyResult<MyTypeItemsIterator> {
> -/// let (leak_handle, leaked_ref) =
> +/// let mut leak_handle =
> /// unsafe { self.inner_shared(py).leak_immutable()? };
> +/// let leaked_ref = leak_handle.data.take().unwrap();
> /// MyTypeItemsIterator::from_inner(
> /// py,
> /// leak_handle,
> @@ -406,7 +411,7 @@ impl Drop for PyLeakedRef {
> ///
> /// py_shared_iterator!(
> /// MyTypeItemsIterator,
> -/// PyLeakedRef,
> +/// PyLeakedRef<&'static MyStruct>,
> /// HashMap<'static, Vec<u8>, Vec<u8>>,
> /// MyType::translate_key_value,
> /// Option<(PyBytes, PyBytes)>
More information about the Mercurial-devel
mailing list