Skip to content

Commit 57ebfde

Browse files
authored
Merge pull request RustPython#1892 from palaviv/threading-type
Make more objects ThreadSafe
2 parents 46945c3 + bfd14b4 commit 57ebfde

22 files changed

+165
-117
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,

examples/mini_repl.rs

Lines changed: 11 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,7 @@
66
use rustpython_compiler as compiler;
77
use rustpython_vm as vm;
88
// these are needed for special memory shenanigans to let us share a variable with Python and Rust
9-
use std::cell::Cell;
10-
use std::rc::Rc;
9+
use std::sync::atomic::{AtomicBool, Ordering};
1110
// this needs to be in scope in order to insert things into scope.globals
1211
use vm::pyobject::ItemProtocol;
1312

@@ -53,27 +52,23 @@ macro_rules! add_python_function {
5352
}};
5453
}
5554

56-
fn main() -> vm::pyobject::PyResult<()> {
57-
// you can also use a raw pointer instead of Rc<Cell<_>>, but that requires usage of unsafe.
58-
// both methods are ways of circumnavigating the fact that Python doesn't respect Rust's borrow
59-
// checking rules.
60-
let on: Rc<Cell<bool>> = Rc::new(Cell::new(true));
55+
static ON: AtomicBool = AtomicBool::new(false);
56+
57+
fn on(b: bool) {
58+
ON.store(b, Ordering::Relaxed);
59+
}
6160

61+
fn main() -> vm::pyobject::PyResult<()> {
6262
let mut input = String::with_capacity(50);
6363
let stdin = std::io::stdin();
6464

6565
let vm = vm::VirtualMachine::new(vm::PySettings::default());
6666
let scope: vm::scope::Scope = vm.new_scope_with_builtins();
6767

6868
// typing `quit()` is too long, let's make `on(False)` work instead.
69-
scope.globals.set_item(
70-
"on",
71-
vm.context().new_function({
72-
let on = Rc::clone(&on);
73-
move |b: bool| on.set(b)
74-
}),
75-
&vm,
76-
)?;
69+
scope
70+
.globals
71+
.set_item("on", vm.context().new_function(on), &vm)?;
7772

7873
// let's include a fibonacci function, but let's be lazy and write it in Python
7974
add_python_function!(
@@ -84,7 +79,7 @@ fn main() -> vm::pyobject::PyResult<()> {
8479
r#"def fib(n): return n if n <= 1 else fib(n - 1) + fib(n - 2)"#
8580
)?;
8681

87-
while on.get() {
82+
while ON.load(Ordering::Relaxed) {
8883
input.clear();
8984
stdin
9085
.read_line(&mut input)

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/function.rs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -458,8 +458,8 @@ tuple_from_py_func_args!(A, B, C, D, E, F);
458458
pub type FunctionBox<T> = SmallBox<T, S1>;
459459

460460
/// A built-in Python function.
461-
pub type PyNativeFunc = FunctionBox<dyn Fn(&VirtualMachine, PyFuncArgs) -> PyResult + 'static>;
462-
// TODO: + Send + Sync
461+
pub type PyNativeFunc =
462+
FunctionBox<dyn Fn(&VirtualMachine, PyFuncArgs) -> PyResult + 'static + Send + Sync>;
463463

464464
/// Implemented by types that are or can generate built-in functions.
465465
///
@@ -481,7 +481,7 @@ pub trait IntoPyNativeFunc<T, R, VM> {
481481

482482
impl<F> IntoPyNativeFunc<PyFuncArgs, PyResult, VirtualMachine> for F
483483
where
484-
F: Fn(&VirtualMachine, PyFuncArgs) -> PyResult + 'static,
484+
F: Fn(&VirtualMachine, PyFuncArgs) -> PyResult + 'static + Send + Sync,
485485
{
486486
fn into_func(self) -> PyNativeFunc {
487487
smallbox!(self)
@@ -499,7 +499,7 @@ macro_rules! into_py_native_func_tuple {
499499
($(($n:tt, $T:ident)),*) => {
500500
impl<F, $($T,)* R> IntoPyNativeFunc<($(OwnedParam<$T>,)*), R, VirtualMachine> for F
501501
where
502-
F: Fn($($T,)* &VirtualMachine) -> R + 'static,
502+
F: Fn($($T,)* &VirtualMachine) -> R + 'static + Send + Sync,
503503
$($T: FromArgs,)*
504504
R: IntoPyObject,
505505
{
@@ -514,7 +514,7 @@ macro_rules! into_py_native_func_tuple {
514514

515515
impl<F, S, $($T,)* R> IntoPyNativeFunc<(RefParam<S>, $(OwnedParam<$T>,)*), R, VirtualMachine> for F
516516
where
517-
F: Fn(&S, $($T,)* &VirtualMachine) -> R + 'static,
517+
F: Fn(&S, $($T,)* &VirtualMachine) -> R + 'static + Send + Sync,
518518
S: PyValue,
519519
$($T: FromArgs,)*
520520
R: IntoPyObject,
@@ -530,7 +530,7 @@ macro_rules! into_py_native_func_tuple {
530530

531531
impl<F, $($T,)* R> IntoPyNativeFunc<($(OwnedParam<$T>,)*), R, ()> for F
532532
where
533-
F: Fn($($T,)*) -> R + 'static,
533+
F: Fn($($T,)*) -> R + 'static + Send + Sync,
534534
$($T: FromArgs,)*
535535
R: IntoPyObject,
536536
{
@@ -541,7 +541,7 @@ macro_rules! into_py_native_func_tuple {
541541

542542
impl<F, S, $($T,)* R> IntoPyNativeFunc<(RefParam<S>, $(OwnedParam<$T>,)*), R, ()> for F
543543
where
544-
F: Fn(&S, $($T,)*) -> R + 'static,
544+
F: Fn(&S, $($T,)*) -> R + 'static + Send + Sync,
545545
S: PyValue,
546546
$($T: FromArgs,)*
547547
R: IntoPyObject,

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/objbuiltinfunc.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use std::fmt;
33
use crate::function::{OptionalArg, PyFuncArgs, PyNativeFunc};
44
use crate::obj::objtype::PyClassRef;
55
use crate::pyobject::{
6-
IdProtocol, PyClassImpl, PyContext, PyObjectRef, PyResult, PyValue, TypeProtocol,
6+
IdProtocol, PyClassImpl, PyContext, PyObjectRef, PyResult, PyValue, ThreadSafe, TypeProtocol,
77
};
88
use crate::slots::{SlotCall, SlotDescriptor};
99
use crate::vm::VirtualMachine;
@@ -12,6 +12,7 @@ use crate::vm::VirtualMachine;
1212
pub struct PyBuiltinFunction {
1313
value: PyNativeFunc,
1414
}
15+
impl ThreadSafe for PyBuiltinFunction {}
1516

1617
impl PyValue for PyBuiltinFunction {
1718
fn class(vm: &VirtualMachine) -> PyClassRef {
@@ -48,6 +49,7 @@ impl PyBuiltinFunction {}
4849
pub struct PyBuiltinMethod {
4950
function: PyBuiltinFunction,
5051
}
52+
impl ThreadSafe for PyBuiltinMethod {}
5153

5254
impl PyValue for PyBuiltinMethod {
5355
fn class(vm: &VirtualMachine) -> PyClassRef {

vm/src/obj/objfunction.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ use crate::obj::objcoroutine::PyCoroutine;
1111
use crate::obj::objgenerator::PyGenerator;
1212
use crate::pyobject::{
1313
IdProtocol, ItemProtocol, PyClassImpl, PyContext, PyObjectRef, PyRef, PyResult, PyValue,
14-
TypeProtocol,
14+
ThreadSafe, TypeProtocol,
1515
};
1616
use crate::scope::Scope;
1717
use crate::slots::{SlotCall, SlotDescriptor};
@@ -28,6 +28,7 @@ pub struct PyFunction {
2828
defaults: Option<PyTupleRef>,
2929
kw_only_defaults: Option<PyDictRef>,
3030
}
31+
impl ThreadSafe for PyFunction {}
3132

3233
impl SlotDescriptor for PyFunction {
3334
fn descr_get(
@@ -293,6 +294,8 @@ pub struct PyBoundMethod {
293294
pub function: PyObjectRef,
294295
}
295296

297+
impl ThreadSafe for PyBoundMethod {}
298+
296299
impl SlotCall for PyBoundMethod {
297300
fn call(&self, args: PyFuncArgs, vm: &VirtualMachine) -> PyResult {
298301
let args = args.insert(self.object.clone());

vm/src/obj/objgetset.rs

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,23 +4,23 @@
44
use super::objtype::PyClassRef;
55
use crate::function::{FunctionBox, OptionalArg, OwnedParam, RefParam};
66
use crate::pyobject::{
7-
IntoPyObject, PyClassImpl, PyContext, PyObjectRef, PyRef, PyResult, PyValue, TryFromObject,
8-
TypeProtocol,
7+
IntoPyObject, PyClassImpl, PyContext, PyObjectRef, PyRef, PyResult, PyValue, ThreadSafe,
8+
TryFromObject, TypeProtocol,
99
};
1010
use crate::slots::SlotDescriptor;
1111
use crate::vm::VirtualMachine;
1212

13-
pub type PyGetterFunc = FunctionBox<dyn Fn(&VirtualMachine, PyObjectRef) -> PyResult>;
13+
pub type PyGetterFunc = FunctionBox<dyn Fn(&VirtualMachine, PyObjectRef) -> PyResult + Send + Sync>;
1414
pub type PySetterFunc =
15-
FunctionBox<dyn Fn(&VirtualMachine, PyObjectRef, PyObjectRef) -> PyResult<()>>;
15+
FunctionBox<dyn Fn(&VirtualMachine, PyObjectRef, PyObjectRef) -> PyResult<()> + Send + Sync>;
1616

1717
pub trait IntoPyGetterFunc<T> {
1818
fn into_getter(self) -> PyGetterFunc;
1919
}
2020

2121
impl<F, T, R> IntoPyGetterFunc<(OwnedParam<T>, R, VirtualMachine)> for F
2222
where
23-
F: Fn(T, &VirtualMachine) -> R + 'static,
23+
F: Fn(T, &VirtualMachine) -> R + 'static + Send + Sync,
2424
T: TryFromObject,
2525
R: IntoPyObject,
2626
{
@@ -34,7 +34,7 @@ where
3434

3535
impl<F, S, R> IntoPyGetterFunc<(RefParam<S>, R, VirtualMachine)> for F
3636
where
37-
F: Fn(&S, &VirtualMachine) -> R + 'static,
37+
F: Fn(&S, &VirtualMachine) -> R + 'static + Send + Sync,
3838
S: PyValue,
3939
R: IntoPyObject,
4040
{
@@ -48,7 +48,7 @@ where
4848

4949
impl<F, T, R> IntoPyGetterFunc<(OwnedParam<T>, R)> for F
5050
where
51-
F: Fn(T) -> R + 'static,
51+
F: Fn(T) -> R + 'static + Send + Sync,
5252
T: TryFromObject,
5353
R: IntoPyObject,
5454
{
@@ -59,7 +59,7 @@ where
5959

6060
impl<F, S, R> IntoPyGetterFunc<(RefParam<S>, R)> for F
6161
where
62-
F: Fn(&S) -> R + 'static,
62+
F: Fn(&S) -> R + 'static + Send + Sync,
6363
S: PyValue,
6464
R: IntoPyObject,
6565
{
@@ -90,7 +90,7 @@ pub trait IntoPySetterFunc<T> {
9090

9191
impl<F, T, V, R> IntoPySetterFunc<(OwnedParam<T>, V, R, VirtualMachine)> for F
9292
where
93-
F: Fn(T, V, &VirtualMachine) -> R + 'static,
93+
F: Fn(T, V, &VirtualMachine) -> R + 'static + Send + Sync,
9494
T: TryFromObject,
9595
V: TryFromObject,
9696
R: IntoPyNoResult,
@@ -106,7 +106,7 @@ where
106106

107107
impl<F, S, V, R> IntoPySetterFunc<(RefParam<S>, V, R, VirtualMachine)> for F
108108
where
109-
F: Fn(&S, V, &VirtualMachine) -> R + 'static,
109+
F: Fn(&S, V, &VirtualMachine) -> R + 'static + Send + Sync,
110110
S: PyValue,
111111
V: TryFromObject,
112112
R: IntoPyNoResult,
@@ -122,7 +122,7 @@ where
122122

123123
impl<F, T, V, R> IntoPySetterFunc<(OwnedParam<T>, V, R)> for F
124124
where
125-
F: Fn(T, V) -> R + 'static,
125+
F: Fn(T, V) -> R + 'static + Send + Sync,
126126
T: TryFromObject,
127127
V: TryFromObject,
128128
R: IntoPyNoResult,
@@ -134,7 +134,7 @@ where
134134

135135
impl<F, S, V, R> IntoPySetterFunc<(RefParam<S>, V, R)> for F
136136
where
137-
F: Fn(&S, V) -> R + 'static,
137+
F: Fn(&S, V) -> R + 'static + Send + Sync,
138138
S: PyValue,
139139
V: TryFromObject,
140140
R: IntoPyNoResult,
@@ -152,6 +152,8 @@ pub struct PyGetSet {
152152
// doc: Option<String>,
153153
}
154154

155+
impl ThreadSafe for PyGetSet {}
156+
155157
impl std::fmt::Debug for PyGetSet {
156158
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
157159
write!(

vm/src/obj/objmappingproxy.rs

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@ use super::objstr::PyStringRef;
44
use super::objtype::PyClassRef;
55
use crate::function::OptionalArg;
66
use crate::pyobject::{
7-
ItemProtocol, PyClassImpl, PyContext, PyObjectRef, PyRef, PyResult, PyValue, TryFromObject,
7+
ItemProtocol, PyClassImpl, PyContext, PyObjectRef, PyRef, PyResult, PyValue, ThreadSafe,
8+
TryFromObject,
89
};
910
use crate::vm::VirtualMachine;
1011

@@ -13,6 +14,7 @@ use crate::vm::VirtualMachine;
1314
pub struct PyMappingProxy {
1415
mapping: MappingProxyInner,
1516
}
17+
impl ThreadSafe for PyMappingProxy {}
1618

1719
#[derive(Debug)]
1820
enum MappingProxyInner {
@@ -87,7 +89,7 @@ impl PyMappingProxy {
8789
MappingProxyInner::Dict(d) => d.clone(),
8890
MappingProxyInner::Class(c) => {
8991
// TODO: something that's much more efficient than this
90-
PyDictRef::from_attributes(c.attributes.borrow().clone(), vm)?.into_object()
92+
PyDictRef::from_attributes(c.attributes.read().unwrap().clone(), vm)?.into_object()
9193
}
9294
};
9395
objiter::get_iter(vm, &obj)
@@ -97,7 +99,7 @@ impl PyMappingProxy {
9799
let obj = match &self.mapping {
98100
MappingProxyInner::Dict(d) => d.clone(),
99101
MappingProxyInner::Class(c) => {
100-
PyDictRef::from_attributes(c.attributes.borrow().clone(), vm)?.into_object()
102+
PyDictRef::from_attributes(c.attributes.read().unwrap().clone(), vm)?.into_object()
101103
}
102104
};
103105
vm.call_method(&obj, "items", vec![])
@@ -107,7 +109,7 @@ impl PyMappingProxy {
107109
let obj = match &self.mapping {
108110
MappingProxyInner::Dict(d) => d.clone(),
109111
MappingProxyInner::Class(c) => {
110-
PyDictRef::from_attributes(c.attributes.borrow().clone(), vm)?.into_object()
112+
PyDictRef::from_attributes(c.attributes.read().unwrap().clone(), vm)?.into_object()
111113
}
112114
};
113115
vm.call_method(&obj, "keys", vec![])
@@ -117,7 +119,7 @@ impl PyMappingProxy {
117119
let obj = match &self.mapping {
118120
MappingProxyInner::Dict(d) => d.clone(),
119121
MappingProxyInner::Class(c) => {
120-
PyDictRef::from_attributes(c.attributes.borrow().clone(), vm)?.into_object()
122+
PyDictRef::from_attributes(c.attributes.read().unwrap().clone(), vm)?.into_object()
121123
}
122124
};
123125
vm.call_method(&obj, "values", vec![])

vm/src/obj/objsuper.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@ use super::objstr::PyStringRef;
1010
use super::objtype::{self, PyClass, PyClassRef};
1111
use crate::function::OptionalArg;
1212
use crate::pyobject::{
13-
IdProtocol, PyClassImpl, PyContext, PyObjectRef, PyRef, PyResult, PyValue, TryFromObject,
14-
TypeProtocol,
13+
IdProtocol, PyClassImpl, PyContext, PyObjectRef, PyRef, PyResult, PyValue, ThreadSafe,
14+
TryFromObject, TypeProtocol,
1515
};
1616
use crate::scope::NameProtocol;
1717
use crate::slots::SlotDescriptor;
@@ -27,6 +27,7 @@ pub struct PySuper {
2727
typ: PyClassRef,
2828
obj: Option<(PyObjectRef, PyClassRef)>,
2929
}
30+
impl ThreadSafe for PySuper {}
3031

3132
impl PyValue for PySuper {
3233
fn class(vm: &VirtualMachine) -> PyClassRef {

vm/src/obj/objtraceback.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use crate::frame::FrameRef;
22
use crate::obj::objtype::PyClassRef;
3-
use crate::pyobject::{PyClassImpl, PyContext, PyRef, PyValue};
3+
use crate::pyobject::{PyClassImpl, PyContext, PyRef, PyValue, ThreadSafe};
44
use crate::vm::VirtualMachine;
55

66
#[pyclass]
@@ -11,6 +11,7 @@ pub struct PyTraceback {
1111
pub lasti: usize,
1212
pub lineno: usize,
1313
}
14+
impl ThreadSafe for PyTraceback {}
1415

1516
pub type PyTracebackRef = PyRef<PyTraceback>;
1617

0 commit comments

Comments
 (0)