Skip to content

Commit 13f2377

Browse files
committed
Make Popen ThreadSafe
1 parent 8042ff8 commit 13f2377

File tree

1 file changed

+26
-19
lines changed

1 file changed

+26
-19
lines changed

vm/src/stdlib/subprocess.rs

Lines changed: 26 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,27 @@
1-
use std::cell::RefCell;
21
use std::ffi::OsString;
32
use std::fs::File;
43
use std::io::ErrorKind;
4+
use std::sync::{RwLock, RwLockReadGuard, RwLockWriteGuard};
55
use std::time::Duration;
66

77
use crate::function::OptionalArg;
88
use crate::obj::objbytes::PyBytesRef;
99
use crate::obj::objlist::PyListRef;
1010
use crate::obj::objstr::{self, PyStringRef};
1111
use crate::obj::objtype::PyClassRef;
12-
use crate::pyobject::{Either, IntoPyObject, PyObjectRef, PyRef, PyResult, PyValue};
12+
use crate::pyobject::{Either, IntoPyObject, PyObjectRef, PyRef, PyResult, PyValue, ThreadSafe};
1313
use crate::stdlib::io::io_open;
1414
use crate::stdlib::os::{convert_io_error, raw_file_number, rust_file};
1515
use crate::vm::VirtualMachine;
1616

1717
#[derive(Debug)]
1818
struct Popen {
19-
process: RefCell<subprocess::Popen>,
19+
process: RwLock<subprocess::Popen>,
2020
args: PyObjectRef,
2121
}
2222

23+
impl ThreadSafe for Popen {}
24+
2325
impl PyValue for Popen {
2426
fn class(vm: &VirtualMachine) -> PyClassRef {
2527
vm.class("_subprocess", "Popen")
@@ -103,6 +105,14 @@ fn convert_to_file_io(file: &Option<File>, mode: &str, vm: &VirtualMachine) -> P
103105
}
104106

105107
impl PopenRef {
108+
fn borrow_process(&self) -> RwLockReadGuard<'_, subprocess::Popen> {
109+
self.process.read().unwrap()
110+
}
111+
112+
fn borrow_process_mut(&self) -> RwLockWriteGuard<'_, subprocess::Popen> {
113+
self.process.write().unwrap()
114+
}
115+
106116
fn new(cls: PyClassRef, args: PopenArgs, vm: &VirtualMachine) -> PyResult<PopenRef> {
107117
let stdin = convert_redirection(args.stdin, vm)?;
108118
let stdout = convert_redirection(args.stdout, vm)?;
@@ -130,27 +140,26 @@ impl PopenRef {
130140
.map_err(|s| vm.new_os_error(format!("Could not start program: {}", s)))?;
131141

132142
Popen {
133-
process: RefCell::new(process),
143+
process: RwLock::new(process),
134144
args: args.args.into_object(),
135145
}
136146
.into_ref_with_type(vm, cls)
137147
}
138148

139149
fn poll(self) -> Option<subprocess::ExitStatus> {
140-
self.process.borrow_mut().poll()
150+
self.borrow_process_mut().poll()
141151
}
142152

143153
fn return_code(self) -> Option<subprocess::ExitStatus> {
144-
self.process.borrow().exit_status()
154+
self.borrow_process().exit_status()
145155
}
146156

147157
fn wait(self, args: PopenWaitArgs, vm: &VirtualMachine) -> PyResult<i64> {
148158
let timeout = match args.timeout {
149159
Some(timeout) => self
150-
.process
151-
.borrow_mut()
160+
.borrow_process_mut()
152161
.wait_timeout(Duration::new(timeout, 0)),
153-
None => self.process.borrow_mut().wait().map(Some),
162+
None => self.borrow_process_mut().wait().map(Some),
154163
}
155164
.map_err(|s| vm.new_os_error(format!("Could not start program: {}", s)))?;
156165
if let Some(exit) = timeout {
@@ -167,27 +176,25 @@ impl PopenRef {
167176
}
168177

169178
fn stdin(self, vm: &VirtualMachine) -> PyResult {
170-
convert_to_file_io(&self.process.borrow().stdin, "wb", vm)
179+
convert_to_file_io(&self.borrow_process().stdin, "wb", vm)
171180
}
172181

173182
fn stdout(self, vm: &VirtualMachine) -> PyResult {
174-
convert_to_file_io(&self.process.borrow().stdout, "rb", vm)
183+
convert_to_file_io(&self.borrow_process().stdout, "rb", vm)
175184
}
176185

177186
fn stderr(self, vm: &VirtualMachine) -> PyResult {
178-
convert_to_file_io(&self.process.borrow().stderr, "rb", vm)
187+
convert_to_file_io(&self.borrow_process().stderr, "rb", vm)
179188
}
180189

181190
fn terminate(self, vm: &VirtualMachine) -> PyResult<()> {
182-
self.process
183-
.borrow_mut()
191+
self.borrow_process_mut()
184192
.terminate()
185193
.map_err(|err| convert_io_error(vm, err))
186194
}
187195

188196
fn kill(self, vm: &VirtualMachine) -> PyResult<()> {
189-
self.process
190-
.borrow_mut()
197+
self.borrow_process_mut()
191198
.kill()
192199
.map_err(|err| convert_io_error(vm, err))
193200
}
@@ -202,7 +209,7 @@ impl PopenRef {
202209
OptionalArg::Present(ref bytes) => Some(bytes.get_value().to_vec()),
203210
OptionalArg::Missing => None,
204211
};
205-
let mut communicator = self.process.borrow_mut().communicate_start(bytes);
212+
let mut communicator = self.borrow_process_mut().communicate_start(bytes);
206213
if let OptionalArg::Present(timeout) = args.timeout {
207214
communicator = communicator.limit_time(Duration::new(timeout, 0));
208215
}
@@ -217,7 +224,7 @@ impl PopenRef {
217224
}
218225

219226
fn pid(self) -> Option<u32> {
220-
self.process.borrow().pid()
227+
self.borrow_process().pid()
221228
}
222229

223230
fn enter(self) -> Self {
@@ -230,7 +237,7 @@ impl PopenRef {
230237
_exception_value: PyObjectRef,
231238
_traceback: PyObjectRef,
232239
) {
233-
let mut process = self.process.borrow_mut();
240+
let mut process = self.borrow_process_mut();
234241
process.stdout.take();
235242
process.stdin.take();
236243
process.stderr.take();

0 commit comments

Comments
 (0)