Skip to content

Commit 16887d3

Browse files
committed
Make PyClass ThreadSafe
1 parent 2ee1c39 commit 16887d3

File tree

10 files changed

+69
-55
lines changed

10 files changed

+69
-55
lines changed

derive/src/pyclass.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -275,7 +275,7 @@ fn extract_impl_items(mut items: Vec<ItemIdent>) -> Result<TokenStream2, Diagnos
275275
#transform(Self::#item_ident)
276276
};
277277
Some(quote! {
278-
(*class.slots.borrow_mut()).#slot_ident = Some(#into_func);
278+
(*class.slots.write().unwrap()).#slot_ident = Some(#into_func);
279279
})
280280
}
281281
_ => None,

vm/src/exceptions.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -427,7 +427,7 @@ impl ExceptionZoo {
427427
pub fn new(type_type: &PyClassRef, object_type: &PyClassRef) -> Self {
428428
let create_exception_type = |name: &str, base: &PyClassRef| {
429429
let typ = create_type(name, type_type, base);
430-
typ.slots.borrow_mut().flags |= PyTpFlags::BASETYPE;
430+
typ.slots.write().unwrap().flags |= PyTpFlags::BASETYPE;
431431
typ
432432
};
433433
// Sorted By Hierarchy then alphabetized.

vm/src/frame.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -256,7 +256,7 @@ impl ExecutingFrame<'_> {
256256
let new_traceback =
257257
PyTraceback::new(next, self.object.clone(), self.lasti(), loc.row());
258258
exception.set_traceback(Some(new_traceback.into_ref(vm)));
259-
vm_trace!("Adding to traceback: {:?} {:?}", new_traceback, lineno);
259+
vm_trace!("Adding to traceback: {:?} {:?}", new_traceback, loc.row);
260260

261261
match self.unwind_blocks(vm, UnwindReason::Raising { exception }) {
262262
Ok(None) => {}

vm/src/macros.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,7 @@ macro_rules! py_class {
140140
{
141141
let py_class = $ctx.new_class($class_name, $class_base);
142142
// FIXME: setting flag here probably wrong
143-
py_class.slots.borrow_mut().flags |= $crate::slots::PyTpFlags::BASETYPE;
143+
py_class.slots.write().unwrap().flags |= $crate::slots::PyTpFlags::BASETYPE;
144144
$crate::extend_class!($ctx, &py_class, { $($name => $value),* });
145145
py_class
146146
}
@@ -157,7 +157,7 @@ macro_rules! extend_class {
157157
};
158158

159159
(@set_attr($ctx:expr, $class:expr, (slot $slot_name:ident), $value:expr)) => {
160-
$class.slots.borrow_mut().$slot_name = Some(
160+
$class.slots.write().unwrap().$slot_name = Some(
161161
$crate::function::IntoPyNativeFunc::into_func($value)
162162
);
163163
};

vm/src/obj/objmappingproxy.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ impl PyMappingProxy {
8787
MappingProxyInner::Dict(d) => d.clone(),
8888
MappingProxyInner::Class(c) => {
8989
// TODO: something that's much more efficient than this
90-
PyDictRef::from_attributes(c.attributes.borrow().clone(), vm)?.into_object()
90+
PyDictRef::from_attributes(c.attributes.read().unwrap().clone(), vm)?.into_object()
9191
}
9292
};
9393
objiter::get_iter(vm, &obj)
@@ -97,7 +97,7 @@ impl PyMappingProxy {
9797
let obj = match &self.mapping {
9898
MappingProxyInner::Dict(d) => d.clone(),
9999
MappingProxyInner::Class(c) => {
100-
PyDictRef::from_attributes(c.attributes.borrow().clone(), vm)?.into_object()
100+
PyDictRef::from_attributes(c.attributes.read().unwrap().clone(), vm)?.into_object()
101101
}
102102
};
103103
vm.call_method(&obj, "items", vec![])
@@ -107,7 +107,7 @@ impl PyMappingProxy {
107107
let obj = match &self.mapping {
108108
MappingProxyInner::Dict(d) => d.clone(),
109109
MappingProxyInner::Class(c) => {
110-
PyDictRef::from_attributes(c.attributes.borrow().clone(), vm)?.into_object()
110+
PyDictRef::from_attributes(c.attributes.read().unwrap().clone(), vm)?.into_object()
111111
}
112112
};
113113
vm.call_method(&obj, "keys", vec![])
@@ -117,7 +117,7 @@ impl PyMappingProxy {
117117
let obj = match &self.mapping {
118118
MappingProxyInner::Dict(d) => d.clone(),
119119
MappingProxyInner::Class(c) => {
120-
PyDictRef::from_attributes(c.attributes.borrow().clone(), vm)?.into_object()
120+
PyDictRef::from_attributes(c.attributes.read().unwrap().clone(), vm)?.into_object()
121121
}
122122
};
123123
vm.call_method(&obj, "values", vec![])

vm/src/obj/objtype.rs

Lines changed: 42 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
use std::cell::RefCell;
21
use std::collections::{HashMap, HashSet};
32
use std::fmt;
3+
use std::sync::RwLock;
44

55
use super::objdict::PyDictRef;
66
use super::objlist::PyList;
@@ -12,7 +12,7 @@ use super::objweakref::PyWeak;
1212
use crate::function::{OptionalArg, PyFuncArgs};
1313
use crate::pyobject::{
1414
IdProtocol, PyAttributes, PyClassImpl, PyContext, PyIterable, PyObject, PyObjectRef, PyRef,
15-
PyResult, PyValue, TypeProtocol,
15+
PyResult, PyValue, ThreadSafe, TypeProtocol,
1616
};
1717
use crate::slots::{PyClassSlots, PyTpFlags};
1818
use crate::vm::VirtualMachine;
@@ -27,11 +27,13 @@ pub struct PyClass {
2727
pub name: String,
2828
pub bases: Vec<PyClassRef>,
2929
pub mro: Vec<PyClassRef>,
30-
pub subclasses: RefCell<Vec<PyWeak>>,
31-
pub attributes: RefCell<PyAttributes>,
32-
pub slots: RefCell<PyClassSlots>,
30+
pub subclasses: RwLock<Vec<PyWeak>>,
31+
pub attributes: RwLock<PyAttributes>,
32+
pub slots: RwLock<PyClassSlots>,
3333
}
3434

35+
impl ThreadSafe for PyClass {}
36+
3537
impl fmt::Display for PyClass {
3638
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3739
fmt::Display::fmt(&self.name, f)
@@ -97,7 +99,8 @@ impl PyClassRef {
9799
#[pyproperty(magic)]
98100
fn qualname(self, vm: &VirtualMachine) -> PyObjectRef {
99101
self.attributes
100-
.borrow()
102+
.read()
103+
.unwrap()
101104
.get("__qualname__")
102105
.cloned()
103106
.unwrap_or_else(|| vm.ctx.new_str(self.name.clone()))
@@ -107,7 +110,8 @@ impl PyClassRef {
107110
fn module(self, vm: &VirtualMachine) -> PyObjectRef {
108111
// TODO: Implement getting the actual module a builtin type is from
109112
self.attributes
110-
.borrow()
113+
.read()
114+
.unwrap()
111115
.get("__module__")
112116
.cloned()
113117
.unwrap_or_else(|| vm.ctx.new_str("builtins".to_owned()))
@@ -116,7 +120,8 @@ impl PyClassRef {
116120
#[pyproperty(magic, setter)]
117121
fn set_module(self, value: PyObjectRef) {
118122
self.attributes
119-
.borrow_mut()
123+
.write()
124+
.unwrap()
120125
.insert("__module__".to_owned(), value);
121126
}
122127

@@ -145,7 +150,7 @@ impl PyClassRef {
145150

146151
if let Some(attr) = self.get_attr(&name) {
147152
let attr_class = attr.class();
148-
let slots = attr_class.slots.borrow();
153+
let slots = attr_class.slots.read().unwrap();
149154
if let Some(ref descr_get) = slots.descr_get {
150155
return descr_get(vm, attr, None, OptionalArg::Present(self.into_object()));
151156
} else if let Some(ref descriptor) = attr_class.get_attr("__get__") {
@@ -180,7 +185,8 @@ impl PyClassRef {
180185
}
181186

182187
self.attributes
183-
.borrow_mut()
188+
.write()
189+
.unwrap()
184190
.insert(attr_name.to_string(), value);
185191
Ok(())
186192
}
@@ -196,7 +202,7 @@ impl PyClassRef {
196202
}
197203

198204
if self.get_attr(attr_name.as_str()).is_some() {
199-
self.attributes.borrow_mut().remove(attr_name.as_str());
205+
self.attributes.write().unwrap().remove(attr_name.as_str());
200206
Ok(())
201207
} else {
202208
Err(vm.new_attribute_error(attr_name.as_str().to_owned()))
@@ -206,13 +212,14 @@ impl PyClassRef {
206212
// This is used for class initialisation where the vm is not yet available.
207213
pub fn set_str_attr<V: Into<PyObjectRef>>(&self, attr_name: &str, value: V) {
208214
self.attributes
209-
.borrow_mut()
215+
.write()
216+
.unwrap()
210217
.insert(attr_name.to_owned(), value.into());
211218
}
212219

213220
#[pymethod(magic)]
214221
fn subclasses(self) -> PyList {
215-
let mut subclasses = self.subclasses.borrow_mut();
222+
let mut subclasses = self.subclasses.write().unwrap();
216223
subclasses.retain(|x| x.upgrade().is_some());
217224
PyList::from(
218225
subclasses
@@ -269,7 +276,7 @@ impl PyClassRef {
269276
// Search the bases for the proper metatype to deal with this:
270277
let winner = calculate_meta_class(metatype.clone(), &bases, vm)?;
271278
let metatype = if !winner.is(&metatype) {
272-
if let Some(ref tp_new) = winner.clone().slots.borrow().new {
279+
if let Some(ref tp_new) = winner.clone().slots.read().unwrap().new {
273280
// Pass it to the winner
274281

275282
return tp_new(vm, args.insert(winner.into_object()));
@@ -294,10 +301,10 @@ impl PyClassRef {
294301
let typ = new(metatype, name.as_str(), base.clone(), bases, attributes)
295302
.map_err(|e| vm.new_type_error(e))?;
296303

297-
typ.slots.borrow_mut().flags = base.slots.borrow().flags;
304+
typ.slots.write().unwrap().flags = base.slots.read().unwrap().flags;
298305
vm.ctx.add_tp_new_wrapper(&typ);
299306

300-
for (name, obj) in typ.attributes.borrow().iter() {
307+
for (name, obj) in typ.attributes.read().unwrap().clone().iter() {
301308
if let Some(meth) = vm.get_method(obj.clone(), "__set_name__") {
302309
let set_name = meth?;
303310
vm.invoke(
@@ -393,9 +400,9 @@ fn call_tp_new(
393400
let class_with_new_slot = typ
394401
.iter_mro()
395402
.cloned()
396-
.find(|cls| cls.slots.borrow().new.is_some())
403+
.find(|cls| cls.slots.read().unwrap().new.is_some())
397404
.expect("Should be able to find a new slot somewhere in the mro");
398-
let slots = class_with_new_slot.slots.borrow();
405+
let slots = class_with_new_slot.slots.read().unwrap();
399406
let new_slot = slots.new.as_ref().unwrap();
400407
new_slot(vm, args.insert(subtype.into_object()))
401408
}
@@ -422,7 +429,8 @@ impl PyClassRef {
422429
flame_guard!(format!("class_get_attr({:?})", attr_name));
423430

424431
self.attributes
425-
.borrow()
432+
.read()
433+
.unwrap()
426434
.get(attr_name)
427435
.cloned()
428436
.or_else(|| self.get_super_attr(attr_name))
@@ -431,21 +439,21 @@ impl PyClassRef {
431439
pub fn get_super_attr(&self, attr_name: &str) -> Option<PyObjectRef> {
432440
self.mro
433441
.iter()
434-
.find_map(|class| class.attributes.borrow().get(attr_name).cloned())
442+
.find_map(|class| class.attributes.read().unwrap().get(attr_name).cloned())
435443
}
436444

437445
// This is the internal has_attr implementation for fast lookup on a class.
438446
pub fn has_attr(&self, attr_name: &str) -> bool {
439447
self.iter_mro()
440-
.any(|c| c.attributes.borrow().contains_key(attr_name))
448+
.any(|c| c.attributes.read().unwrap().contains_key(attr_name))
441449
}
442450

443451
pub fn get_attributes(self) -> PyAttributes {
444452
// Gather all members here:
445453
let mut attributes = PyAttributes::new();
446454

447455
for bc in self.iter_mro().rev() {
448-
for (name, value) in bc.attributes.borrow().iter() {
456+
for (name, value) in bc.attributes.read().unwrap().clone().iter() {
449457
attributes.insert(name.to_owned(), value.clone());
450458
}
451459
}
@@ -540,9 +548,9 @@ pub fn new(
540548
name: String::from(name),
541549
bases,
542550
mro,
543-
subclasses: RefCell::default(),
544-
attributes: RefCell::new(dict),
545-
slots: RefCell::default(),
551+
subclasses: RwLock::default(),
552+
attributes: RwLock::new(dict),
553+
slots: RwLock::default(),
546554
},
547555
dict: None,
548556
typ: typ.into_typed_pyobj(),
@@ -553,7 +561,8 @@ pub fn new(
553561

554562
for base in &new_type.bases {
555563
base.subclasses
556-
.borrow_mut()
564+
.write()
565+
.unwrap()
557566
.push(PyWeak::downgrade(new_type.as_object()));
558567
}
559568

@@ -603,7 +612,13 @@ fn best_base<'a>(bases: &'a [PyClassRef], vm: &VirtualMachine) -> PyResult<PyCla
603612
// return NULL;
604613
// }
605614

606-
if !base_i.slots.borrow().flags.has_feature(PyTpFlags::BASETYPE) {
615+
if !base_i
616+
.slots
617+
.read()
618+
.unwrap()
619+
.flags
620+
.has_feature(PyTpFlags::BASETYPE)
621+
{
607622
return Err(vm.new_type_error(format!(
608623
"type '{}' is not an acceptable base type",
609624
base_i.name

vm/src/pyobject.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -604,7 +604,7 @@ impl PyContext {
604604
}
605605

606606
pub fn add_tp_new_wrapper(&self, ty: &PyClassRef) {
607-
if !ty.attributes.borrow().contains_key("__new__") {
607+
if !ty.attributes.read().unwrap().contains_key("__new__") {
608608
let new_wrapper =
609609
self.new_bound_method(self.tp_new_wrapper.clone(), ty.clone().into_object());
610610
ty.set_str_attr("__new__", new_wrapper);
@@ -1309,7 +1309,7 @@ pub trait PyClassImpl: PyClassDef {
13091309

13101310
fn extend_class(ctx: &PyContext, class: &PyClassRef) {
13111311
Self::impl_extend_class(ctx, class);
1312-
class.slots.borrow_mut().flags = Self::TP_FLAGS;
1312+
class.slots.write().unwrap().flags = Self::TP_FLAGS;
13131313
ctx.add_tp_new_wrapper(&class);
13141314
if let Some(doc) = Self::DOC {
13151315
class.set_str_attr("__doc__", ctx.new_str(doc));

vm/src/slots.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,9 @@ pub trait SlotCall: PyValue {
4545
}
4646

4747
pub type PyDescrGetFunc = FunctionBox<
48-
dyn Fn(&VirtualMachine, PyObjectRef, Option<PyObjectRef>, OptionalArg<PyObjectRef>) -> PyResult,
48+
dyn Fn(&VirtualMachine, PyObjectRef, Option<PyObjectRef>, OptionalArg<PyObjectRef>) -> PyResult
49+
+ Send
50+
+ Sync,
4951
>;
5052

5153
#[pyimpl]

vm/src/types.rs

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -40,10 +40,9 @@ use crate::obj::objweakproxy;
4040
use crate::obj::objweakref;
4141
use crate::obj::objzip;
4242
use crate::pyobject::{PyAttributes, PyContext, PyObject};
43-
use std::cell::RefCell;
4443
use std::mem::MaybeUninit;
4544
use std::ptr;
46-
use std::sync::Arc;
45+
use std::sync::{Arc, RwLock};
4746

4847
/// Holder of references to builtin types.
4948
#[derive(Debug)]
@@ -303,9 +302,9 @@ fn init_type_hierarchy() -> (PyClassRef, PyClassRef) {
303302
name: String::from("type"),
304303
bases: vec![],
305304
mro: vec![],
306-
subclasses: RefCell::default(),
307-
attributes: RefCell::new(PyAttributes::new()),
308-
slots: RefCell::default(),
305+
subclasses: RwLock::default(),
306+
attributes: RwLock::new(PyAttributes::new()),
307+
slots: RwLock::default(),
309308
},
310309
},
311310
Uninit { typ }
@@ -317,9 +316,9 @@ fn init_type_hierarchy() -> (PyClassRef, PyClassRef) {
317316
name: String::from("object"),
318317
bases: vec![],
319318
mro: vec![],
320-
subclasses: RefCell::default(),
321-
attributes: RefCell::new(PyAttributes::new()),
322-
slots: RefCell::default(),
319+
subclasses: RwLock::default(),
320+
attributes: RwLock::new(PyAttributes::new()),
321+
slots: RwLock::default(),
323322
},
324323
},
325324
Uninit { typ },
@@ -350,7 +349,8 @@ fn init_type_hierarchy() -> (PyClassRef, PyClassRef) {
350349

351350
object_type
352351
.subclasses
353-
.borrow_mut()
352+
.write()
353+
.unwrap()
354354
.push(objweakref::PyWeak::downgrade(&type_type.as_object()));
355355

356356
(type_type, object_type)

0 commit comments

Comments
 (0)