Merge pull request #1927 from palaviv/threading-stdlib-3

Convert more stdlib objects to thread safe
This commit is contained in:
Jeong YunWon
2020-05-16 03:19:54 +09:00
committed by GitHub
5 changed files with 90 additions and 55 deletions

View File

@@ -1,9 +1,10 @@
use std::cell::{Cell, Ref, RefCell};
use std::io::{self, prelude::*};
use std::net::{Ipv4Addr, Shutdown, SocketAddr, ToSocketAddrs};
use std::sync::{RwLock, RwLockReadGuard, RwLockWriteGuard};
use std::time::Duration;
use byteorder::{BigEndian, ByteOrder};
use crossbeam_utils::atomic::AtomicCell;
use gethostname::gethostname;
#[cfg(all(unix, not(target_os = "redox")))]
use nix::unistd::sethostname;
@@ -21,7 +22,8 @@ use crate::obj::objstr::{PyString, PyStringRef};
use crate::obj::objtuple::PyTupleRef;
use crate::obj::objtype::PyClassRef;
use crate::pyobject::{
Either, IntoPyObject, PyClassImpl, PyObjectRef, PyRef, PyResult, PyValue, TryFromObject,
Either, IntoPyObject, PyClassImpl, PyObjectRef, PyRef, PyResult, PyValue, ThreadSafe,
TryFromObject,
};
use crate::vm::VirtualMachine;
@@ -44,12 +46,14 @@ mod c {
#[pyclass]
#[derive(Debug)]
pub struct PySocket {
kind: Cell<i32>,
family: Cell<i32>,
proto: Cell<i32>,
sock: RefCell<Socket>,
kind: AtomicCell<i32>,
family: AtomicCell<i32>,
proto: AtomicCell<i32>,
sock: RwLock<Socket>,
}
impl ThreadSafe for PySocket {}
impl PyValue for PySocket {
fn class(vm: &VirtualMachine) -> PyClassRef {
vm.class("_socket", "socket")
@@ -60,17 +64,21 @@ pub type PySocketRef = PyRef<PySocket>;
#[pyimpl(flags(BASETYPE))]
impl PySocket {
fn sock(&self) -> Ref<Socket> {
self.sock.borrow()
fn sock(&self) -> RwLockReadGuard<'_, Socket> {
self.sock.read().unwrap()
}
fn sock_mut(&self) -> RwLockWriteGuard<'_, Socket> {
self.sock.write().unwrap()
}
#[pyslot]
fn tp_new(cls: PyClassRef, _args: PyFuncArgs, vm: &VirtualMachine) -> PyResult<PyRef<Self>> {
PySocket {
kind: Cell::default(),
family: Cell::default(),
proto: Cell::default(),
sock: RefCell::new(invalid_sock()),
kind: AtomicCell::default(),
family: AtomicCell::default(),
proto: AtomicCell::default(),
sock: RwLock::new(invalid_sock()),
}
.into_ref_with_type(vm, cls)
}
@@ -103,12 +111,12 @@ impl PySocket {
)
.map_err(|err| convert_sock_error(vm, err))?;
self.family.set(family);
self.kind.set(socket_kind);
self.proto.set(proto);
self.family.store(family);
self.kind.store(socket_kind);
self.proto.store(proto);
sock
};
self.sock.replace(sock);
*self.sock.write().unwrap() = sock;
Ok(())
}
@@ -191,7 +199,7 @@ impl PySocket {
#[pymethod]
fn sendall(&self, bytes: PyBytesLike, vm: &VirtualMachine) -> PyResult<()> {
bytes
.with_ref(|b| self.sock.borrow_mut().write_all(b))
.with_ref(|b| self.sock_mut().write_all(b))
.map_err(|err| convert_sock_error(vm, err))
}
@@ -206,11 +214,11 @@ impl PySocket {
#[pymethod]
fn close(&self) {
self.sock.replace(invalid_sock());
*self.sock_mut() = invalid_sock();
}
#[pymethod]
fn detach(&self) -> RawSocket {
into_sock_fileno(self.sock.replace(invalid_sock()))
into_sock_fileno(std::mem::replace(&mut *self.sock_mut(), invalid_sock()))
}
#[pymethod]
@@ -384,29 +392,29 @@ impl PySocket {
#[pyproperty(name = "type")]
fn kind(&self) -> i32 {
self.kind.get()
self.kind.load()
}
#[pyproperty]
fn family(&self) -> i32 {
self.family.get()
self.family.load()
}
#[pyproperty]
fn proto(&self) -> i32 {
self.proto.get()
self.proto.load()
}
}
impl io::Read for PySocketRef {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
<Socket as io::Read>::read(&mut self.sock.borrow_mut(), buf)
<Socket as io::Read>::read(&mut self.sock_mut(), buf)
}
}
impl io::Write for PySocketRef {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
<Socket as io::Write>::write(&mut self.sock.borrow_mut(), buf)
<Socket as io::Write>::write(&mut self.sock_mut(), buf)
}
fn flush(&mut self) -> io::Result<()> {
<Socket as io::Write>::flush(&mut self.sock.borrow_mut())
<Socket as io::Write>::flush(&mut self.sock_mut())
}
}

View File

@@ -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,23 @@ 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<subprocess::Popen>,
process: RwLock<subprocess::Popen>,
args: PyObjectRef,
}
// Remove once https://github.com/hniksic/rust-subprocess/issues/42 is resolved
#[cfg(windows)]
unsafe impl Sync for Popen {}
impl ThreadSafe for Popen {}
impl PyValue for Popen {
fn class(vm: &VirtualMachine) -> PyClassRef {
vm.class("_subprocess", "Popen")
@@ -103,6 +109,14 @@ fn convert_to_file_io(file: &Option<File>, 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<PopenRef> {
let stdin = convert_redirection(args.stdin, vm)?;
let stdout = convert_redirection(args.stdout, vm)?;
@@ -130,27 +144,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<subprocess::ExitStatus> {
self.process.borrow_mut().poll()
self.borrow_process_mut().poll()
}
fn return_code(self) -> Option<subprocess::ExitStatus> {
self.process.borrow().exit_status()
self.borrow_process().exit_status()
}
fn wait(self, args: PopenWaitArgs, vm: &VirtualMachine) -> PyResult<i64> {
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 +180,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 +213,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 +228,7 @@ impl PopenRef {
}
fn pid(self) -> Option<u32> {
self.process.borrow().pid()
self.borrow_process().pid()
}
fn enter(self) -> Self {
@@ -230,7 +241,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();

View File

@@ -5,7 +5,7 @@ use rustpython_parser::parser;
use crate::obj::objstr::PyStringRef;
use crate::obj::objtype::PyClassRef;
use crate::pyobject::{PyClassImpl, PyObjectRef, PyRef, PyResult, PyValue};
use crate::pyobject::{PyClassImpl, PyObjectRef, PyRef, PyResult, PyValue, ThreadSafe};
use crate::vm::VirtualMachine;
pub fn make_module(vm: &VirtualMachine) -> PyObjectRef {
@@ -72,6 +72,8 @@ struct PySymbolTable {
symtable: symboltable::SymbolTable,
}
impl ThreadSafe for PySymbolTable {}
impl fmt::Debug for PySymbolTable {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "SymbolTable()")
@@ -158,6 +160,8 @@ struct PySymbol {
symbol: symboltable::Symbol,
}
impl ThreadSafe for PySymbol {}
impl fmt::Debug for PySymbol {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "Symbol()")

View File

@@ -5,7 +5,7 @@
use crate::function::OptionalArg;
use crate::obj::objstr::PyStringRef;
use crate::obj::objtype::PyClassRef;
use crate::pyobject::{PyClassImpl, PyObject, PyObjectRef, PyResult, PyValue};
use crate::pyobject::{PyClassImpl, PyObject, PyObjectRef, PyResult, PyValue, ThreadSafe};
use crate::vm::VirtualMachine;
use itertools::Itertools;
@@ -60,6 +60,8 @@ struct PyUCD {
unic_version: UnicodeVersion,
}
impl ThreadSafe for PyUCD {}
impl PyValue for PyUCD {
fn class(vm: &VirtualMachine) -> PyClassRef {
vm.class("unicodedata", "UCD")

View File

@@ -1,14 +1,15 @@
#![allow(non_snake_case)]
use std::cell::{Ref, RefCell};
use std::convert::TryInto;
use std::io;
use std::sync::{RwLock, RwLockReadGuard, RwLockWriteGuard};
use super::os;
use crate::function::OptionalArg;
use crate::obj::objstr::PyStringRef;
use crate::obj::objtype::PyClassRef;
use crate::pyobject::{PyClassImpl, PyObjectRef, PyRef, PyResult, PyValue, TryFromObject};
use crate::pyobject::{
PyClassImpl, PyObjectRef, PyRef, PyResult, PyValue, ThreadSafe, TryFromObject,
};
use crate::VirtualMachine;
use winapi::shared::winerror;
@@ -17,10 +18,15 @@ use winreg::{enums::RegType, RegKey, RegValue};
#[pyclass]
#[derive(Debug)]
struct PyHKEY {
key: RefCell<RegKey>,
key: RwLock<RegKey>,
}
type PyHKEYRef = PyRef<PyHKEY>;
// TODO: fix this
unsafe impl Sync for PyHKEY {}
impl ThreadSafe for PyHKEY {}
impl PyValue for PyHKEY {
fn class(vm: &VirtualMachine) -> PyClassRef {
vm.class("winreg", "HKEYType")
@@ -31,24 +37,28 @@ impl PyValue for PyHKEY {
impl PyHKEY {
fn new(key: RegKey) -> Self {
Self {
key: RefCell::new(key),
key: RwLock::new(key),
}
}
fn key(&self) -> Ref<RegKey> {
self.key.borrow()
fn key(&self) -> RwLockReadGuard<'_, RegKey> {
self.key.read().unwrap()
}
fn key_mut(&self) -> RwLockWriteGuard<'_, RegKey> {
self.key.write().unwrap()
}
#[pymethod]
fn Close(&self) {
let null_key = RegKey::predef(0 as winreg::HKEY);
let key = self.key.replace(null_key);
let key = std::mem::replace(&mut *self.key_mut(), null_key);
drop(key);
}
#[pymethod]
fn Detach(&self) -> usize {
let null_key = RegKey::predef(0 as winreg::HKEY);
let key = self.key.replace(null_key);
let key = std::mem::replace(&mut *self.key_mut(), null_key);
let handle = key.raw_handle();
std::mem::forget(key);
handle as usize