diff --git a/vm/src/vm/mod.rs b/vm/src/vm/mod.rs index bf1764b62..8edcfd336 100644 --- a/vm/src/vm/mod.rs +++ b/vm/src/vm/mod.rs @@ -41,7 +41,7 @@ mod vm_ops; pub use interpreter::Interpreter; pub use setting::PySettings; -pub use thread::PyThread; +pub use thread::ThreadedVirtualMachine; // Objects are live when they are on stack, or referenced by a name (for now) @@ -276,71 +276,6 @@ impl VirtualMachine { self.signal_rx = Some(signal_rx); } - /// Start a new thread with access to the same interpreter. - /// - /// # Note - /// - /// If you return a `PyObjectRef` (or a type that contains one) from `F`, and don't `join()` - /// on the thread, there is a possibility that that thread will panic as `PyObjectRef`'s `Drop` - /// implementation tries to run the `__del__` destructor of a python object but finds that it's - /// not in the context of any vm. - #[cfg(feature = "threading")] - pub fn start_thread(&self, f: F) -> std::thread::JoinHandle - where - F: FnOnce(&VirtualMachine) -> R, - F: Send + 'static, - R: Send + 'static, - { - let thread = self.new_thread(); - std::thread::spawn(|| thread.run(f)) - } - - /// Create a new VM thread that can be passed to a function like [`std::thread::spawn`] - /// to use the same interpreter on a different thread. Note that if you just want to - /// use this with `thread::spawn`, you can use - /// [`vm.start_thread()`](`VirtualMachine::start_thread`) as a convenience. - /// - /// # Usage - /// - /// ``` - /// # rustpython_vm::Interpreter::default().enter(|vm| { - /// use std::thread::Builder; - /// let handle = Builder::new() - /// .name("my thread :)".into()) - /// .spawn(vm.new_thread().make_spawn_func(|vm| vm.ctx.none())) - /// .expect("couldn't spawn thread"); - /// let returned_obj = handle.join().expect("thread panicked"); - /// assert!(vm.is_none(&returned_obj)); - /// # }) - /// ``` - /// - /// Note: this function is safe, but running the returned PyThread in the same - /// thread context (i.e. with the same thread-local storage) doesn't have any - /// specific guaranteed behavior. - #[cfg(feature = "threading")] - pub fn new_thread(&self) -> PyThread { - let thread_vm = VirtualMachine { - builtins: self.builtins.clone(), - sys_module: self.sys_module.clone(), - ctx: self.ctx.clone(), - frames: RefCell::new(vec![]), - wasm_id: self.wasm_id.clone(), - exceptions: RefCell::default(), - import_func: self.import_func.clone(), - profile_func: RefCell::new(self.ctx.none()), - trace_func: RefCell::new(self.ctx.none()), - use_tracing: Cell::new(false), - recursion_limit: self.recursion_limit.clone(), - signal_handlers: None, - signal_rx: None, - repr_guards: RefCell::default(), - state: self.state.clone(), - initialized: self.initialized, - recursion_depth: Cell::new(0), - }; - PyThread { thread_vm } - } - pub fn run_code_obj(&self, code: PyRef, scope: Scope) -> PyResult { let frame = Frame::new(code, scope, self.builtins.dict(), &[], self).into_ref(self); self.run_frame_full(frame) diff --git a/vm/src/vm/thread.rs b/vm/src/vm/thread.rs index 8d5083277..1e6987c40 100644 --- a/vm/src/vm/thread.rs +++ b/vm/src/vm/thread.rs @@ -39,14 +39,14 @@ where }) } -#[must_use = "PyThread does nothing unless you move it to another thread and call .run()"] +#[must_use = "ThreadedVirtualMachine does nothing unless you move it to another thread and call .run()"] #[cfg(feature = "threading")] -pub struct PyThread { - pub(super) thread_vm: VirtualMachine, +pub struct ThreadedVirtualMachine { + pub(super) vm: VirtualMachine, } #[cfg(feature = "threading")] -impl PyThread { +impl ThreadedVirtualMachine { /// Create a `FnOnce()` that can easily be passed to a function like [`std::thread::Builder::spawn`] /// /// # Note @@ -74,7 +74,75 @@ impl PyThread { where F: FnOnce(&VirtualMachine) -> R, { - let vm = &self.thread_vm; + let vm = &self.vm; enter_vm(vm, || f(vm)) } } + +impl VirtualMachine { + /// Start a new thread with access to the same interpreter. + /// + /// # Note + /// + /// If you return a `PyObjectRef` (or a type that contains one) from `F`, and don't `join()` + /// on the thread, there is a possibility that that thread will panic as `PyObjectRef`'s `Drop` + /// implementation tries to run the `__del__` destructor of a python object but finds that it's + /// not in the context of any vm. + #[cfg(feature = "threading")] + pub fn start_thread(&self, f: F) -> std::thread::JoinHandle + where + F: FnOnce(&VirtualMachine) -> R, + F: Send + 'static, + R: Send + 'static, + { + let thread = self.new_thread(); + std::thread::spawn(|| thread.run(f)) + } + + /// Create a new VM thread that can be passed to a function like [`std::thread::spawn`] + /// to use the same interpreter on a different thread. Note that if you just want to + /// use this with `thread::spawn`, you can use + /// [`vm.start_thread()`](`VirtualMachine::start_thread`) as a convenience. + /// + /// # Usage + /// + /// ``` + /// # rustpython_vm::Interpreter::default().enter(|vm| { + /// use std::thread::Builder; + /// let handle = Builder::new() + /// .name("my thread :)".into()) + /// .spawn(vm.new_thread().make_spawn_func(|vm| vm.ctx.none())) + /// .expect("couldn't spawn thread"); + /// let returned_obj = handle.join().expect("thread panicked"); + /// assert!(vm.is_none(&returned_obj)); + /// # }) + /// ``` + /// + /// Note: this function is safe, but running the returned ThreadedVirtualMachine in the same + /// thread context (i.e. with the same thread-local storage) doesn't have any + /// specific guaranteed behavior. + #[cfg(feature = "threading")] + pub fn new_thread(&self) -> ThreadedVirtualMachine { + use std::cell::Cell; + let vm = VirtualMachine { + builtins: self.builtins.clone(), + sys_module: self.sys_module.clone(), + ctx: self.ctx.clone(), + frames: RefCell::new(vec![]), + wasm_id: self.wasm_id.clone(), + exceptions: RefCell::default(), + import_func: self.import_func.clone(), + profile_func: RefCell::new(self.ctx.none()), + trace_func: RefCell::new(self.ctx.none()), + use_tracing: Cell::new(false), + recursion_limit: self.recursion_limit.clone(), + signal_handlers: None, + signal_rx: None, + repr_guards: RefCell::default(), + state: self.state.clone(), + initialized: self.initialized, + recursion_depth: Cell::new(0), + }; + ThreadedVirtualMachine { vm } + } +}