Mercurial > public > mercurial-scm > hg-stable
comparison rust/hg-cpython/src/ref_sharing.rs @ 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 |
comparison
equal
deleted
inserted
replaced
43175:a1908eb08342 | 43176:aaec70a5f9a8 |
---|---|
72 immutable references in Python objects", | 72 immutable references in Python objects", |
73 )), | 73 )), |
74 } | 74 } |
75 } | 75 } |
76 | 76 |
77 /// Return a reference to the wrapped data with an artificial static | 77 /// Return a reference to the wrapped data and its state with an |
78 /// lifetime. | 78 /// artificial static lifetime. |
79 /// We need to be protected by the GIL for thread-safety. | 79 /// We need to be protected by the GIL for thread-safety. |
80 /// | 80 /// |
81 /// # Safety | 81 /// # Safety |
82 /// | 82 /// |
83 /// This is highly unsafe since the lifetime of the given data can be | 83 /// This is highly unsafe since the lifetime of the given data can be |
84 /// extended. Do not call this function directly. | 84 /// extended. Do not call this function directly. |
85 pub unsafe fn leak_immutable<T>( | 85 pub unsafe fn leak_immutable<T>( |
86 &self, | 86 &self, |
87 py: Python, | 87 py: Python, |
88 data: &PySharedRefCell<T>, | 88 data: &PySharedRefCell<T>, |
89 ) -> PyResult<&'static T> { | 89 ) -> PyResult<(&'static T, &'static PySharedState)> { |
90 if self.mutably_borrowed.get() { | 90 if self.mutably_borrowed.get() { |
91 return Err(AlreadyBorrowed::new( | 91 return Err(AlreadyBorrowed::new( |
92 py, | 92 py, |
93 "Cannot borrow immutably while there is a \ | 93 "Cannot borrow immutably while there is a \ |
94 mutable reference in Python objects", | 94 mutable reference in Python objects", |
95 )); | 95 )); |
96 } | 96 } |
97 // TODO: it's weird that self is data.py_shared_state. Maybe we | |
98 // can move stuff to PySharedRefCell? | |
97 let ptr = data.as_ptr(); | 99 let ptr = data.as_ptr(); |
100 let state_ptr: *const PySharedState = &data.py_shared_state; | |
98 self.leak_count.replace(self.leak_count.get() + 1); | 101 self.leak_count.replace(self.leak_count.get() + 1); |
99 Ok(&*ptr) | 102 Ok((&*ptr, &*state_ptr)) |
100 } | 103 } |
101 | 104 |
102 /// # Safety | 105 /// # Safety |
103 /// | 106 /// |
104 /// It's unsafe to update the reference count without knowing the | 107 /// It's unsafe to update the reference count without knowing the |
265 py: Python<'a>, | 268 py: Python<'a>, |
266 ) -> PyResult<($leaked, &'static $inner_struct)> { | 269 ) -> PyResult<($leaked, &'static $inner_struct)> { |
267 // assert $data_member type | 270 // assert $data_member type |
268 use crate::ref_sharing::PySharedRefCell; | 271 use crate::ref_sharing::PySharedRefCell; |
269 let data: &PySharedRefCell<_> = self.$data_member(py); | 272 let data: &PySharedRefCell<_> = self.$data_member(py); |
270 let static_ref = | 273 let (static_ref, static_state_ref) = |
271 data.py_shared_state.leak_immutable(py, data)?; | 274 data.py_shared_state.leak_immutable(py, data)?; |
272 let leak_handle = $leaked::new(py, self); | 275 let leak_handle = $leaked::new(py, self, static_state_ref); |
273 Ok((leak_handle, static_ref)) | 276 Ok((leak_handle, static_ref)) |
274 } | 277 } |
275 } | 278 } |
276 | 279 |
277 /// Manage immutable references to `$name` leaked into Python | 280 /// Manage immutable references to `$name` leaked into Python |
278 /// iterators. | 281 /// iterators. |
279 /// | 282 /// |
280 /// In truth, this does not represent leaked references themselves; | 283 /// In truth, this does not represent leaked references themselves; |
281 /// it is instead useful alongside them to manage them. | 284 /// it is instead useful alongside them to manage them. |
282 pub struct $leaked { | 285 pub struct $leaked { |
283 inner: $name, | 286 _inner: $name, |
287 py_shared_state: &'static crate::ref_sharing::PySharedState, | |
284 } | 288 } |
285 | 289 |
286 impl $leaked { | 290 impl $leaked { |
291 /// # Safety | |
292 /// | |
293 /// The `py_shared_state` must be owned by the `inner` Python | |
294 /// object. | |
287 // Marked as unsafe so client code wouldn't construct $leaked | 295 // Marked as unsafe so client code wouldn't construct $leaked |
288 // struct by mistake. Its drop() is unsafe. | 296 // struct by mistake. Its drop() is unsafe. |
289 unsafe fn new(py: Python, inner: &$name) -> Self { | 297 unsafe fn new( |
298 py: Python, | |
299 inner: &$name, | |
300 py_shared_state: &'static crate::ref_sharing::PySharedState, | |
301 ) -> Self { | |
290 Self { | 302 Self { |
291 inner: inner.clone_ref(py), | 303 _inner: inner.clone_ref(py), |
304 py_shared_state, | |
292 } | 305 } |
293 } | 306 } |
294 } | 307 } |
295 | 308 |
296 impl Drop for $leaked { | 309 impl Drop for $leaked { |
297 fn drop(&mut self) { | 310 fn drop(&mut self) { |
311 // py_shared_state should be alive since we do have | |
312 // a Python reference to the owner object. Taking GIL makes | |
313 // sure that the state is only accessed by this thread. | |
298 let gil = Python::acquire_gil(); | 314 let gil = Python::acquire_gil(); |
299 let py = gil.python(); | 315 let py = gil.python(); |
300 let state = &self.inner.$data_member(py).py_shared_state; | |
301 unsafe { | 316 unsafe { |
302 state.decrease_leak_count(py, false); | 317 self.py_shared_state.decrease_leak_count(py, false); |
303 } | 318 } |
304 } | 319 } |
305 } | 320 } |
306 }; | 321 }; |
307 } | 322 } |