Skip to content

Commit f54b555

Browse files
authored
Add Supporting for PyAtomicRef<Option<_>> and PyAtomicRef<PyObject> (RustPython#4286)
* introduce PyObjectAtomicRef * impl Debug for PyObjectAtomicRef * add supporting for PyAtomicRef<Option<_>> * add supporting for PyAtomic<PyObject> * impl Send Sync
1 parent 00ba73d commit f54b555

File tree

1 file changed

+105
-7
lines changed

1 file changed

+105
-7
lines changed

vm/src/object/ext.rs

Lines changed: 105 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ use crate::{
1111
convert::{IntoPyException, ToPyObject, ToPyResult, TryFromObject},
1212
VirtualMachine,
1313
};
14-
use std::{borrow::Borrow, fmt, ops::Deref};
14+
use std::{borrow::Borrow, fmt, marker::PhantomData, ops::Deref, ptr::null_mut};
1515

1616
/* Python objects and references.
1717
@@ -214,27 +214,43 @@ impl<T: PyPayload> ToPyObject for PyRefExact<T> {
214214
}
215215
}
216216

217-
pub struct PyAtomicRef<T: PyObjectPayload>(PyAtomic<*mut Py<T>>);
217+
pub struct PyAtomicRef<T> {
218+
inner: PyAtomic<*mut u8>,
219+
_phantom: PhantomData<T>,
220+
}
218221

219222
cfg_if::cfg_if! {
220223
if #[cfg(feature = "threading")] {
221224
unsafe impl<T: Send + PyObjectPayload> Send for PyAtomicRef<T> {}
222225
unsafe impl<T: Sync + PyObjectPayload> Sync for PyAtomicRef<T> {}
226+
unsafe impl<T: Send + PyObjectPayload> Send for PyAtomicRef<Option<T>> {}
227+
unsafe impl<T: Sync + PyObjectPayload> Sync for PyAtomicRef<Option<T>> {}
228+
unsafe impl Send for PyAtomicRef<PyObject> {}
229+
unsafe impl Sync for PyAtomicRef<PyObject> {}
223230
}
224231
}
225232

226233
impl<T: PyObjectPayload> From<PyRef<T>> for PyAtomicRef<T> {
227234
fn from(pyref: PyRef<T>) -> Self {
228235
let py = PyRef::leak(pyref);
229-
Self(Radium::new(py as *const _ as *mut _))
236+
Self {
237+
inner: Radium::new(py as *const _ as *mut _),
238+
_phantom: Default::default(),
239+
}
230240
}
231241
}
232242

233243
impl<T: PyObjectPayload> Deref for PyAtomicRef<T> {
234244
type Target = Py<T>;
235245

236246
fn deref(&self) -> &Self::Target {
237-
unsafe { &*self.0.load(Ordering::Relaxed) }
247+
unsafe {
248+
self.inner
249+
.load(Ordering::Relaxed)
250+
.cast::<Py<T>>()
251+
.as_ref()
252+
.unwrap_unchecked()
253+
}
238254
}
239255
}
240256

@@ -244,9 +260,9 @@ impl<T: PyObjectPayload> PyAtomicRef<T> {
244260
/// until no more reference can be used via PyAtomicRef::deref()
245261
#[must_use]
246262
pub unsafe fn swap(&self, pyref: PyRef<T>) -> PyRef<T> {
247-
let py = PyRef::leak(pyref);
248-
let old = Radium::swap(&self.0, py as *const _ as *mut _, Ordering::AcqRel);
249-
PyRef::from_raw(old)
263+
let py = PyRef::leak(pyref) as *const Py<T> as *mut _;
264+
let old = Radium::swap(&self.inner, py, Ordering::AcqRel);
265+
PyRef::from_raw(old.cast())
250266
}
251267

252268
pub fn swap_to_temporary_refs(&self, pyref: PyRef<T>, vm: &VirtualMachine) {
@@ -257,6 +273,88 @@ impl<T: PyObjectPayload> PyAtomicRef<T> {
257273
}
258274
}
259275

276+
impl<T: PyObjectPayload> From<Option<PyRef<T>>> for PyAtomicRef<Option<T>> {
277+
fn from(opt_ref: Option<PyRef<T>>) -> Self {
278+
let val = opt_ref
279+
.map(|x| PyRef::leak(x) as *const Py<T> as *mut _)
280+
.unwrap_or(null_mut());
281+
Self {
282+
inner: Radium::new(val),
283+
_phantom: Default::default(),
284+
}
285+
}
286+
}
287+
288+
impl<T: PyObjectPayload> PyAtomicRef<Option<T>> {
289+
pub fn deref(&self) -> Option<&Py<T>> {
290+
unsafe { self.inner.load(Ordering::Relaxed).cast::<Py<T>>().as_ref() }
291+
}
292+
293+
/// # Safety
294+
/// The caller is responsible to keep the returned PyRef alive
295+
/// until no more reference can be used via PyAtomicRef::deref()
296+
#[must_use]
297+
pub unsafe fn swap(&self, opt_ref: Option<PyRef<T>>) -> Option<PyRef<T>> {
298+
let val = opt_ref
299+
.map(|x| PyRef::leak(x) as *const Py<T> as *mut _)
300+
.unwrap_or(null_mut());
301+
let old = Radium::swap(&self.inner, val, Ordering::AcqRel);
302+
unsafe { old.cast::<Py<T>>().as_ref().map(|x| PyRef::from_raw(x)) }
303+
}
304+
305+
pub fn swap_to_temporary_refs(&self, opt_ref: Option<PyRef<T>>, vm: &VirtualMachine) {
306+
let Some(old) = (unsafe { self.swap(opt_ref) }) else {
307+
return;
308+
};
309+
if let Some(frame) = vm.current_frame() {
310+
frame.temporary_refs.lock().push(old.into());
311+
}
312+
}
313+
}
314+
315+
impl From<PyObjectRef> for PyAtomicRef<PyObject> {
316+
fn from(obj: PyObjectRef) -> Self {
317+
let obj = obj.into_raw();
318+
Self {
319+
inner: Radium::new(obj as *mut _),
320+
_phantom: Default::default(),
321+
}
322+
}
323+
}
324+
325+
impl Deref for PyAtomicRef<PyObject> {
326+
type Target = PyObject;
327+
328+
fn deref(&self) -> &Self::Target {
329+
unsafe {
330+
self.inner
331+
.load(Ordering::Relaxed)
332+
.cast::<PyObject>()
333+
.as_ref()
334+
.unwrap_unchecked()
335+
}
336+
}
337+
}
338+
339+
impl PyAtomicRef<PyObject> {
340+
/// # Safety
341+
/// The caller is responsible to keep the returned PyRef alive
342+
/// until no more reference can be used via PyAtomicRef::deref()
343+
#[must_use]
344+
pub unsafe fn swap(&self, obj: PyObjectRef) -> PyObjectRef {
345+
let obj = obj.into_raw() as *mut _;
346+
let old = Radium::swap(&self.inner, obj, Ordering::AcqRel);
347+
PyObjectRef::from_raw(old.cast())
348+
}
349+
350+
pub fn swap_to_temporary_refs(&self, obj: PyObjectRef, vm: &VirtualMachine) {
351+
let old = unsafe { self.swap(obj) };
352+
if let Some(frame) = vm.current_frame() {
353+
frame.temporary_refs.lock().push(old);
354+
}
355+
}
356+
}
357+
260358
pub trait AsObject
261359
where
262360
Self: Borrow<PyObject>,

0 commit comments

Comments
 (0)