From 13f2377600ce80e9bebca3ed79bb878ea634ffaa Mon Sep 17 00:00:00 2001 From: Aviv Palivoda Date: Fri, 15 May 2020 16:29:20 +0300 Subject: [PATCH] Make Popen ThreadSafe --- vm/src/stdlib/subprocess.rs | 45 +++++++++++++++++++++---------------- 1 file changed, 26 insertions(+), 19 deletions(-) diff --git a/vm/src/stdlib/subprocess.rs b/vm/src/stdlib/subprocess.rs index 9694edb82a..2848893b94 100644 --- a/vm/src/stdlib/subprocess.rs +++ b/vm/src/stdlib/subprocess.rs @@ -1,7 +1,7 @@ -use std::cell::RefCell; use std::ffi::OsString; use std::fs::File; use std::io::ErrorKind; +use std::sync::{RwLock, RwLockReadGuard, RwLockWriteGuard}; use std::time::Duration; use crate::function::OptionalArg; @@ -9,17 +9,19 @@ use crate::obj::objbytes::PyBytesRef; use crate::obj::objlist::PyListRef; use crate::obj::objstr::{self, PyStringRef}; use crate::obj::objtype::PyClassRef; -use crate::pyobject::{Either, IntoPyObject, PyObjectRef, PyRef, PyResult, PyValue}; +use crate::pyobject::{Either, IntoPyObject, PyObjectRef, PyRef, PyResult, PyValue, ThreadSafe}; use crate::stdlib::io::io_open; use crate::stdlib::os::{convert_io_error, raw_file_number, rust_file}; use crate::vm::VirtualMachine; #[derive(Debug)] struct Popen { - process: RefCell, + process: RwLock, args: PyObjectRef, } +impl ThreadSafe for Popen {} + impl PyValue for Popen { fn class(vm: &VirtualMachine) -> PyClassRef { vm.class("_subprocess", "Popen") @@ -103,6 +105,14 @@ fn convert_to_file_io(file: &Option, mode: &str, vm: &VirtualMachine) -> P } impl PopenRef { + fn borrow_process(&self) -> RwLockReadGuard<'_, subprocess::Popen> { + self.process.read().unwrap() + } + + fn borrow_process_mut(&self) -> RwLockWriteGuard<'_, subprocess::Popen> { + self.process.write().unwrap() + } + fn new(cls: PyClassRef, args: PopenArgs, vm: &VirtualMachine) -> PyResult { let stdin = convert_redirection(args.stdin, vm)?; let stdout = convert_redirection(args.stdout, vm)?; @@ -130,27 +140,26 @@ impl PopenRef { .map_err(|s| vm.new_os_error(format!("Could not start program: {}", s)))?; Popen { - process: RefCell::new(process), + process: RwLock::new(process), args: args.args.into_object(), } .into_ref_with_type(vm, cls) } fn poll(self) -> Option { - self.process.borrow_mut().poll() + self.borrow_process_mut().poll() } fn return_code(self) -> Option { - self.process.borrow().exit_status() + self.borrow_process().exit_status() } fn wait(self, args: PopenWaitArgs, vm: &VirtualMachine) -> PyResult { let timeout = match args.timeout { Some(timeout) => self - .process - .borrow_mut() + .borrow_process_mut() .wait_timeout(Duration::new(timeout, 0)), - None => self.process.borrow_mut().wait().map(Some), + None => self.borrow_process_mut().wait().map(Some), } .map_err(|s| vm.new_os_error(format!("Could not start program: {}", s)))?; if let Some(exit) = timeout { @@ -167,27 +176,25 @@ impl PopenRef { } fn stdin(self, vm: &VirtualMachine) -> PyResult { - convert_to_file_io(&self.process.borrow().stdin, "wb", vm) + convert_to_file_io(&self.borrow_process().stdin, "wb", vm) } fn stdout(self, vm: &VirtualMachine) -> PyResult { - convert_to_file_io(&self.process.borrow().stdout, "rb", vm) + convert_to_file_io(&self.borrow_process().stdout, "rb", vm) } fn stderr(self, vm: &VirtualMachine) -> PyResult { - convert_to_file_io(&self.process.borrow().stderr, "rb", vm) + convert_to_file_io(&self.borrow_process().stderr, "rb", vm) } fn terminate(self, vm: &VirtualMachine) -> PyResult<()> { - self.process - .borrow_mut() + self.borrow_process_mut() .terminate() .map_err(|err| convert_io_error(vm, err)) } fn kill(self, vm: &VirtualMachine) -> PyResult<()> { - self.process - .borrow_mut() + self.borrow_process_mut() .kill() .map_err(|err| convert_io_error(vm, err)) } @@ -202,7 +209,7 @@ impl PopenRef { OptionalArg::Present(ref bytes) => Some(bytes.get_value().to_vec()), OptionalArg::Missing => None, }; - let mut communicator = self.process.borrow_mut().communicate_start(bytes); + let mut communicator = self.borrow_process_mut().communicate_start(bytes); if let OptionalArg::Present(timeout) = args.timeout { communicator = communicator.limit_time(Duration::new(timeout, 0)); } @@ -217,7 +224,7 @@ impl PopenRef { } fn pid(self) -> Option { - self.process.borrow().pid() + self.borrow_process().pid() } fn enter(self) -> Self { @@ -230,7 +237,7 @@ impl PopenRef { _exception_value: PyObjectRef, _traceback: PyObjectRef, ) { - let mut process = self.process.borrow_mut(); + let mut process = self.borrow_process_mut(); process.stdout.take(); process.stdin.take(); process.stderr.take();