mirror of
https://github.com/RustPython/RustPython.git
synced 2026-06-09 22:49:57 +09:00
Merge pull request #2559 from RustPython/coolreader18/moduless
Add some os-related modules and improve stdlib_inits
This commit is contained in:
2
Cargo.lock
generated
2
Cargo.lock
generated
@@ -2336,6 +2336,8 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "sre-engine"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e5872399287c284fed4bc773cb7f6041623ac88213774f5e11e89e2131681fc1"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"num_enum",
|
||||
|
||||
@@ -172,7 +172,7 @@ fn generate_field((i, field): (usize, &Field)) -> Result<TokenStream2, Diagnosti
|
||||
::rustpython_vm::function::ArgumentError::TooFewArgs
|
||||
},
|
||||
ParameterKind::KeywordOnly => quote! {
|
||||
::rustpython_vm::function::ArgumentError::RequiredKeywordArgument(#pyname)
|
||||
::rustpython_vm::function::ArgumentError::RequiredKeywordArgument(#pyname.to_owned())
|
||||
},
|
||||
ParameterKind::Flatten => unreachable!(),
|
||||
};
|
||||
|
||||
@@ -39,6 +39,11 @@ pub(crate) fn impl_pystruct_sequence(
|
||||
::rustpython_vm::builtins::tuple::PyTuple::_new(items.into_boxed_slice())
|
||||
}
|
||||
}
|
||||
impl ::rustpython_vm::pyobject::IntoPyObject for #ty {
|
||||
fn into_pyobject(self, vm: &::rustpython_vm::VirtualMachine) -> ::rustpython_vm::pyobject::PyObjectRef {
|
||||
::rustpython_vm::pyobject::PyStructSequence::into_struct_sequence(self, vm).into_object()
|
||||
}
|
||||
}
|
||||
};
|
||||
Ok(ret)
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ fn main() {
|
||||
let mut f = std::fs::File::create(env_path).unwrap();
|
||||
write!(
|
||||
f,
|
||||
"hashmap! {{ {} }}",
|
||||
"sysvars! {{ {} }}",
|
||||
std::env::vars_os().format_with(", ", |(k, v), f| f(&format_args!("{:?} => {:?}", k, v)))
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
use crate::builtins::memory::{try_buffer_from_object, BufferRef};
|
||||
use crate::builtins::PyStrRef;
|
||||
use crate::common::borrow::{BorrowedValue, BorrowedValueMut};
|
||||
use crate::pyobject::{BorrowValue, PyObjectRef, PyResult, TryFromObject};
|
||||
use crate::vm::VirtualMachine;
|
||||
@@ -124,3 +125,27 @@ impl<'a> BorrowValue<'a> for PyRwBytesLike {
|
||||
self.0.as_contiguous_mut().unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
/// A buffer or utf8 string. Like the `s*` format code for `PyArg_Parse` in CPython.
|
||||
pub enum BufOrStr {
|
||||
Buf(PyBytesLike),
|
||||
Str(PyStrRef),
|
||||
}
|
||||
|
||||
impl TryFromObject for BufOrStr {
|
||||
fn try_from_object(vm: &VirtualMachine, obj: PyObjectRef) -> PyResult<Self> {
|
||||
obj.downcast()
|
||||
.map(Self::Str)
|
||||
.or_else(|obj| PyBytesLike::try_from_object(vm, obj).map(Self::Buf))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> BorrowValue<'a> for BufOrStr {
|
||||
type Borrowed = BorrowedValue<'a, [u8]>;
|
||||
fn borrow_value(&'a self) -> Self::Borrowed {
|
||||
match self {
|
||||
Self::Buf(b) => b.borrow_value(),
|
||||
Self::Str(s) => s.borrow_value().as_bytes().into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
#![allow(clippy::upper_case_acronyms)]
|
||||
#![doc(html_logo_url = "https://raw.githubusercontent.com/RustPython/RustPython/master/logo.png")]
|
||||
#![doc(html_root_url = "https://docs.rs/rustpython-vm/")]
|
||||
#![cfg_attr(target_os = "redox", feature(array_value_iter))]
|
||||
|
||||
#[cfg(feature = "flame-it")]
|
||||
#[macro_use]
|
||||
|
||||
@@ -256,21 +256,3 @@ cfg_if::cfg_if! {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A modified version of the hashmap! macro from the maplit crate
|
||||
macro_rules! hashmap {
|
||||
(@single $($x:tt)*) => (());
|
||||
(@count $($rest:expr),*) => (<[()]>::len(&[$(hashmap!(@single $rest)),*]));
|
||||
|
||||
(hasher=$hasher:expr, $($key:expr => $value:expr,)+) => { hashmap!(hasher=$hasher, $($key => $value),+) };
|
||||
(hasher=$hasher:expr, $($key:expr => $value:expr),*) => {
|
||||
{
|
||||
let _cap = hashmap!(@count $($key),*);
|
||||
let mut _map = ::std::collections::HashMap::with_capacity_and_hasher(_cap, $hasher);
|
||||
$(
|
||||
let _ = _map.insert($key, $value);
|
||||
)*
|
||||
_map
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1139,9 +1139,10 @@ pub trait PyStructSequence: StaticType + PyClassImpl + Sized + 'static {
|
||||
|
||||
fn into_tuple(self, vm: &VirtualMachine) -> PyTuple;
|
||||
|
||||
fn into_struct_sequence(self, vm: &VirtualMachine) -> PyResult<PyTupleRef> {
|
||||
fn into_struct_sequence(self, vm: &VirtualMachine) -> PyTupleRef {
|
||||
self.into_tuple(vm)
|
||||
.into_ref_with_type(vm, Self::static_type().clone())
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
#[pymethod(magic)]
|
||||
|
||||
109
vm/src/stdlib/fcntl.rs
Normal file
109
vm/src/stdlib/fcntl.rs
Normal file
@@ -0,0 +1,109 @@
|
||||
pub(crate) use fcntl::make_module;
|
||||
|
||||
#[pymodule]
|
||||
mod fcntl {
|
||||
use super::super::os;
|
||||
use crate::builtins::int;
|
||||
use crate::byteslike::{BufOrStr, PyRwBytesLike};
|
||||
use crate::function::OptionalArg;
|
||||
use crate::pyobject::{BorrowValue, Either, PyResult};
|
||||
use crate::VirtualMachine;
|
||||
|
||||
#[pyattr]
|
||||
use libc::{FD_CLOEXEC, F_GETFD, F_GETFL, F_SETFD, F_SETFL};
|
||||
|
||||
#[cfg(not(target_os = "wasi"))]
|
||||
#[pyattr]
|
||||
use libc::{F_DUPFD, F_DUPFD_CLOEXEC, F_GETLK, F_SETLK, F_SETLKW};
|
||||
|
||||
#[cfg(not(any(target_os = "wasi", target_os = "redox")))]
|
||||
#[pyattr]
|
||||
use libc::{F_GETOWN, F_RDLCK, F_SETOWN, F_UNLCK, F_WRLCK};
|
||||
|
||||
#[pyfunction]
|
||||
fn fcntl(
|
||||
fd: i32,
|
||||
cmd: i32,
|
||||
arg: OptionalArg<Either<BufOrStr, int::PyIntRef>>,
|
||||
vm: &VirtualMachine,
|
||||
) -> PyResult {
|
||||
let int = match arg {
|
||||
OptionalArg::Present(Either::A(arg)) => {
|
||||
let mut buf = [0u8; 1024];
|
||||
let arg_len;
|
||||
{
|
||||
let s = arg.borrow_value();
|
||||
arg_len = s.len();
|
||||
buf.get_mut(..arg_len)
|
||||
.ok_or_else(|| vm.new_value_error("fcntl string arg too long".to_owned()))?
|
||||
.copy_from_slice(&*s)
|
||||
}
|
||||
let ret = unsafe { libc::fcntl(fd, cmd, buf.as_mut_ptr()) };
|
||||
if ret < 0 {
|
||||
return Err(os::errno_err(vm));
|
||||
}
|
||||
return Ok(vm.ctx.new_bytes(buf[..arg_len].to_vec()));
|
||||
}
|
||||
OptionalArg::Present(Either::B(i)) => int::bigint_unsigned_mask(i.borrow_value()),
|
||||
OptionalArg::Missing => 0,
|
||||
};
|
||||
let ret = unsafe { libc::fcntl(fd, cmd, int as i32) };
|
||||
if ret < 0 {
|
||||
return Err(os::errno_err(vm));
|
||||
}
|
||||
Ok(vm.ctx.new_int(ret))
|
||||
}
|
||||
|
||||
#[pyfunction]
|
||||
fn ioctl(
|
||||
fd: i32,
|
||||
request: i32,
|
||||
arg: OptionalArg<Either<Either<PyRwBytesLike, BufOrStr>, i32>>,
|
||||
mutate_flag: OptionalArg<bool>,
|
||||
vm: &VirtualMachine,
|
||||
) -> PyResult {
|
||||
let arg = arg.unwrap_or_else(|| Either::B(0));
|
||||
match arg {
|
||||
Either::A(buf_kind) => {
|
||||
const BUF_SIZE: usize = 1024;
|
||||
let mut buf = [0u8; BUF_SIZE + 1]; // nul byte
|
||||
let mut fill_buf = |b: &[u8]| {
|
||||
if b.len() > BUF_SIZE {
|
||||
return Err(vm.new_value_error("fcntl string arg too long".to_owned()));
|
||||
}
|
||||
buf[..b.len()].copy_from_slice(b);
|
||||
Ok(b.len())
|
||||
};
|
||||
let buf_len = match buf_kind {
|
||||
Either::A(rw_arg) => {
|
||||
let mutate_flag = mutate_flag.unwrap_or(true);
|
||||
let mut arg_buf = rw_arg.borrow_value();
|
||||
if mutate_flag {
|
||||
let ret =
|
||||
unsafe { libc::ioctl(fd, request as _, arg_buf.as_mut_ptr()) };
|
||||
if ret < 0 {
|
||||
return Err(os::errno_err(vm));
|
||||
}
|
||||
return Ok(vm.ctx.new_int(ret));
|
||||
}
|
||||
// treat like an immutable buffer
|
||||
fill_buf(&arg_buf)?
|
||||
}
|
||||
Either::B(ro_buf) => fill_buf(&ro_buf.borrow_value())?,
|
||||
};
|
||||
let ret = unsafe { libc::ioctl(fd, request as _, buf.as_mut_ptr()) };
|
||||
if ret < 0 {
|
||||
return Err(os::errno_err(vm));
|
||||
}
|
||||
Ok(vm.ctx.new_bytes(buf[..buf_len].to_vec()))
|
||||
}
|
||||
Either::B(i) => {
|
||||
let ret = unsafe { libc::ioctl(fd, request as _, i) };
|
||||
if ret < 0 {
|
||||
return Err(os::errno_err(vm));
|
||||
}
|
||||
Ok(vm.ctx.new_int(ret))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
use crate::pyobject::PyObjectRef;
|
||||
use crate::vm::VirtualMachine;
|
||||
use std::borrow::Cow;
|
||||
use std::collections::HashMap;
|
||||
|
||||
pub mod array;
|
||||
@@ -48,6 +49,8 @@ mod os;
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
mod faulthandler;
|
||||
#[cfg(any(unix, target_os = "wasi"))]
|
||||
mod fcntl;
|
||||
#[cfg(windows)]
|
||||
mod msvcrt;
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
@@ -56,6 +59,9 @@ mod multiprocessing;
|
||||
mod posixsubprocess;
|
||||
#[cfg(all(unix, not(any(target_os = "android", target_os = "redox"))))]
|
||||
mod pwd;
|
||||
// libc is missing constants on redox
|
||||
#[cfg(all(unix, not(target_os = "redox")))]
|
||||
mod resource;
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
mod select;
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
@@ -71,108 +77,116 @@ mod winreg;
|
||||
|
||||
pub type StdlibInitFunc = Box<py_dyn_fn!(dyn Fn(&VirtualMachine) -> PyObjectRef)>;
|
||||
|
||||
pub fn get_module_inits() -> HashMap<String, StdlibInitFunc, ahash::RandomState> {
|
||||
#[allow(unused_mut)]
|
||||
let mut modules = hashmap! {
|
||||
hasher = ahash::RandomState::default(),
|
||||
"array".to_owned() => Box::new(array::make_module) as StdlibInitFunc,
|
||||
"atexit".to_owned() => Box::new(atexit::make_module),
|
||||
"binascii".to_owned() => Box::new(binascii::make_module),
|
||||
"_collections".to_owned() => Box::new(collections::make_module),
|
||||
"_csv".to_owned() => Box::new(csv::make_module),
|
||||
"dis".to_owned() => Box::new(dis::make_module),
|
||||
"errno".to_owned() => Box::new(errno::make_module),
|
||||
"_functools".to_owned() => Box::new(functools::make_module),
|
||||
"hashlib".to_owned() => Box::new(hashlib::make_module),
|
||||
"itertools".to_owned() => Box::new(itertools::make_module),
|
||||
"_io".to_owned() => Box::new(io::make_module),
|
||||
"_json".to_owned() => Box::new(json::make_module),
|
||||
"marshal".to_owned() => Box::new(marshal::make_module),
|
||||
"math".to_owned() => Box::new(math::make_module),
|
||||
"_operator".to_owned() => Box::new(operator::make_module),
|
||||
"_platform".to_owned() => Box::new(platform::make_module),
|
||||
"regex_crate".to_owned() => Box::new(re::make_module),
|
||||
"_random".to_owned() => Box::new(random::make_module),
|
||||
"_serde_json".to_owned() => Box::new(serde_json::make_module),
|
||||
"_sre".to_owned() => Box::new(sre::make_module),
|
||||
"_string".to_owned() => Box::new(string::make_module),
|
||||
"_struct".to_owned() => Box::new(pystruct::make_module),
|
||||
"time".to_owned() => Box::new(time_module::make_module),
|
||||
"_weakref".to_owned() => Box::new(weakref::make_module),
|
||||
"_imp".to_owned() => Box::new(imp::make_module),
|
||||
"unicodedata".to_owned() => Box::new(unicodedata::make_module),
|
||||
"_warnings".to_owned() => Box::new(warnings::make_module),
|
||||
"zlib".to_owned() => Box::new(zlib::make_module),
|
||||
crate::sysmodule::sysconfigdata_name() => Box::new(sysconfigdata::make_module),
|
||||
};
|
||||
pub type StdlibMap = HashMap<Cow<'static, str>, StdlibInitFunc, ahash::RandomState>;
|
||||
|
||||
// Insert parser related modules:
|
||||
#[cfg(feature = "rustpython-ast")]
|
||||
{
|
||||
modules.insert(
|
||||
"_ast".to_owned(),
|
||||
Box::new(ast::make_module) as StdlibInitFunc,
|
||||
);
|
||||
pub fn get_module_inits() -> StdlibMap {
|
||||
macro_rules! modules {
|
||||
{
|
||||
$(
|
||||
#[cfg($cfg:meta)]
|
||||
{ $( $key:expr => $val:expr),* $(,)? }
|
||||
)*
|
||||
} => {{
|
||||
let iter = std::array::IntoIter::new([
|
||||
$(
|
||||
$(#[cfg($cfg)] (Cow::<'static, str>::from($key), Box::new($val) as StdlibInitFunc),)*
|
||||
)*
|
||||
]);
|
||||
iter.collect()
|
||||
}};
|
||||
}
|
||||
|
||||
#[cfg(feature = "rustpython-parser")]
|
||||
{
|
||||
modules.insert("keyword".to_owned(), Box::new(keyword::make_module));
|
||||
}
|
||||
|
||||
// Insert compiler related modules:
|
||||
#[cfg(feature = "rustpython-compiler")]
|
||||
{
|
||||
modules.insert("symtable".to_owned(), Box::new(symtable::make_module));
|
||||
}
|
||||
|
||||
#[cfg(any(unix, windows, target_os = "wasi"))]
|
||||
modules.insert(os::MODULE_NAME.to_owned(), Box::new(os::make_module));
|
||||
|
||||
// disable some modules on WASM
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
{
|
||||
modules.insert("_socket".to_owned(), Box::new(socket::make_module));
|
||||
modules.insert(
|
||||
"_multiprocessing".to_owned(),
|
||||
Box::new(multiprocessing::make_module),
|
||||
);
|
||||
modules.insert("_signal".to_owned(), Box::new(signal::make_module));
|
||||
modules.insert("select".to_owned(), Box::new(select::make_module));
|
||||
modules! {
|
||||
#[cfg(all())]
|
||||
{
|
||||
"array" => array::make_module,
|
||||
"atexit" => atexit::make_module,
|
||||
"binascii" => binascii::make_module,
|
||||
"_collections" => collections::make_module,
|
||||
"_csv" => csv::make_module,
|
||||
"dis" => dis::make_module,
|
||||
"errno" => errno::make_module,
|
||||
"_functools" => functools::make_module,
|
||||
"hashlib" => hashlib::make_module,
|
||||
"itertools" => itertools::make_module,
|
||||
"_io" => io::make_module,
|
||||
"_json" => json::make_module,
|
||||
"marshal" => marshal::make_module,
|
||||
"math" => math::make_module,
|
||||
"_operator" => operator::make_module,
|
||||
"_platform" => platform::make_module,
|
||||
"regex_crate" => re::make_module,
|
||||
"_random" => random::make_module,
|
||||
"_serde_json" => serde_json::make_module,
|
||||
"_sre" => sre::make_module,
|
||||
"_string" => string::make_module,
|
||||
"_struct" => pystruct::make_module,
|
||||
"time" => time_module::make_module,
|
||||
"_weakref" => weakref::make_module,
|
||||
"_imp" => imp::make_module,
|
||||
"unicodedata" => unicodedata::make_module,
|
||||
"_warnings" => warnings::make_module,
|
||||
"zlib" => zlib::make_module,
|
||||
crate::sysmodule::sysconfigdata_name() => sysconfigdata::make_module,
|
||||
}
|
||||
// parser related modules:
|
||||
#[cfg(feature = "rustpython-ast")]
|
||||
{
|
||||
"_ast" => ast::make_module,
|
||||
}
|
||||
#[cfg(feature = "rustpython-parser")]
|
||||
{
|
||||
"keyword" => keyword::make_module,
|
||||
}
|
||||
// compiler related modules:
|
||||
#[cfg(feature = "rustpython-compiler")]
|
||||
{
|
||||
"symtable" => symtable::make_module,
|
||||
}
|
||||
#[cfg(any(unix, windows, target_os = "wasi"))]
|
||||
{
|
||||
os::MODULE_NAME => os::make_module,
|
||||
}
|
||||
#[cfg(any(unix, target_os = "wasi"))]
|
||||
{
|
||||
"fcntl" => fcntl::make_module,
|
||||
}
|
||||
// disable some modules on WASM
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
{
|
||||
"_socket" => socket::make_module,
|
||||
"_multiprocessing" => multiprocessing::make_module,
|
||||
"_signal" => signal::make_module,
|
||||
"select" => select::make_module,
|
||||
"faulthandler" => faulthandler::make_module,
|
||||
}
|
||||
#[cfg(feature = "ssl")]
|
||||
modules.insert("_ssl".to_owned(), Box::new(ssl::make_module));
|
||||
#[cfg(feature = "threading")]
|
||||
modules.insert("_thread".to_owned(), Box::new(thread::make_module));
|
||||
modules.insert(
|
||||
"faulthandler".to_owned(),
|
||||
Box::new(faulthandler::make_module),
|
||||
);
|
||||
{
|
||||
"_ssl" => ssl::make_module,
|
||||
}
|
||||
#[cfg(all(feature = "threading", not(target_arch = "wasm32")))]
|
||||
{
|
||||
"_thread" => thread::make_module,
|
||||
}
|
||||
// Unix-only
|
||||
#[cfg(all(unix, not(any(target_os = "android", target_os = "redox"))))]
|
||||
{
|
||||
"pwd" => pwd::make_module,
|
||||
}
|
||||
#[cfg(all(unix, not(target_os = "redox")))]
|
||||
{
|
||||
"termios" => termios::make_module,
|
||||
"resource" => resource::make_module,
|
||||
}
|
||||
#[cfg(unix)]
|
||||
{
|
||||
"_posixsubprocess" => posixsubprocess::make_module,
|
||||
}
|
||||
// Windows-only
|
||||
#[cfg(windows)]
|
||||
{
|
||||
"msvcrt" => msvcrt::make_module,
|
||||
"_winapi" => winapi::make_module,
|
||||
"winreg" => winreg::make_module,
|
||||
}
|
||||
}
|
||||
|
||||
// Unix-only
|
||||
#[cfg(all(unix, not(any(target_os = "android", target_os = "redox"))))]
|
||||
{
|
||||
modules.insert("pwd".to_owned(), Box::new(pwd::make_module));
|
||||
}
|
||||
|
||||
#[cfg(all(unix, not(target_os = "redox")))]
|
||||
modules.insert("termios".to_owned(), Box::new(termios::make_module));
|
||||
|
||||
#[cfg(unix)]
|
||||
{
|
||||
modules.insert(
|
||||
"_posixsubprocess".to_owned(),
|
||||
Box::new(posixsubprocess::make_module),
|
||||
);
|
||||
}
|
||||
|
||||
// Windows-only
|
||||
#[cfg(windows)]
|
||||
{
|
||||
modules.insert("msvcrt".to_owned(), Box::new(msvcrt::make_module));
|
||||
modules.insert("_winapi".to_owned(), Box::new(winapi::make_module));
|
||||
modules.insert("winreg".to_owned(), Box::new(winreg::make_module));
|
||||
}
|
||||
|
||||
modules
|
||||
}
|
||||
|
||||
@@ -475,13 +475,6 @@ mod _os {
|
||||
Ok(vm.ctx.new_int(written as u64))
|
||||
}
|
||||
|
||||
#[pyfunction]
|
||||
fn error(message: OptionalArg<PyStrRef>, vm: &VirtualMachine) -> PyResult {
|
||||
let msg = message.map_or("".to_owned(), |msg| msg.borrow_value().to_owned());
|
||||
|
||||
Err(vm.new_os_error(msg))
|
||||
}
|
||||
|
||||
#[pyfunction]
|
||||
fn fsync(fd: i64, vm: &VirtualMachine) -> PyResult<()> {
|
||||
let file = rust_file(fd);
|
||||
@@ -793,10 +786,6 @@ mod _os {
|
||||
|
||||
#[pyimpl(with(PyStructSequence))]
|
||||
impl StatResult {
|
||||
fn into_obj(self, vm: &VirtualMachine) -> PyObjectRef {
|
||||
self.into_struct_sequence(vm).unwrap().into_object()
|
||||
}
|
||||
|
||||
fn from_metadata(meta: fs::Metadata) -> io::Result<Self> {
|
||||
let (st_mode, st_ino, st_dev, st_nlink, st_uid, st_gid, ctime);
|
||||
#[cfg(windows)]
|
||||
@@ -919,7 +908,7 @@ mod _os {
|
||||
}
|
||||
};
|
||||
meta.and_then(StatResult::from_metadata)
|
||||
.map(|stat| stat.into_obj(vm))
|
||||
.map(|stat| stat.into_pyobject(vm))
|
||||
.map_err(|err| err.into_pyexception(vm))
|
||||
}
|
||||
|
||||
@@ -1274,7 +1263,7 @@ mod _os {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
#[cfg(all(unix, not(any(target_os = "redox", target_os = "android"))))]
|
||||
#[pyfunction]
|
||||
fn getloadavg(vm: &VirtualMachine) -> PyResult<(f64, f64, f64)> {
|
||||
let mut loadavg = [0f64; 3];
|
||||
@@ -1418,6 +1407,7 @@ pub fn make_module(vm: &VirtualMachine) -> PyObjectRef {
|
||||
"supports_fd" => supports_fd.into_object(),
|
||||
"supports_dir_fd" => supports_dir_fd.into_object(),
|
||||
"supports_follow_symlinks" => supports_follow_symlinks.into_object(),
|
||||
"error" => vm.ctx.exceptions.os_error.clone(),
|
||||
});
|
||||
|
||||
module
|
||||
@@ -2112,14 +2102,10 @@ mod posix {
|
||||
}
|
||||
|
||||
#[pyimpl(with(PyStructSequence))]
|
||||
impl UnameResult {
|
||||
fn into_obj(self, vm: &VirtualMachine) -> PyObjectRef {
|
||||
self.into_struct_sequence(vm).unwrap().into_object()
|
||||
}
|
||||
}
|
||||
impl UnameResult {}
|
||||
|
||||
#[pyfunction]
|
||||
fn uname(vm: &VirtualMachine) -> PyResult {
|
||||
fn uname(vm: &VirtualMachine) -> PyResult<UnameResult> {
|
||||
let info = uname::uname().map_err(|err| err.into_pyexception(vm))?;
|
||||
Ok(UnameResult {
|
||||
sysname: info.sysname,
|
||||
@@ -2127,8 +2113,7 @@ mod posix {
|
||||
release: info.release,
|
||||
version: info.version,
|
||||
machine: info.machine,
|
||||
}
|
||||
.into_obj(vm))
|
||||
})
|
||||
}
|
||||
|
||||
#[pyfunction]
|
||||
@@ -2473,23 +2458,23 @@ mod posix {
|
||||
}
|
||||
|
||||
#[pyfunction]
|
||||
fn get_terminal_size(fd: OptionalArg<i32>, vm: &VirtualMachine) -> PyResult<PyTupleRef> {
|
||||
fn get_terminal_size(
|
||||
fd: OptionalArg<i32>,
|
||||
vm: &VirtualMachine,
|
||||
) -> PyResult<super::_os::PyTerminalSize> {
|
||||
let (columns, lines) = {
|
||||
#[cfg(unix)]
|
||||
{
|
||||
nix::ioctl_read_bad!(winsz, libc::TIOCGWINSZ, libc::winsize);
|
||||
let mut w = libc::winsize {
|
||||
ws_row: 0,
|
||||
ws_col: 0,
|
||||
ws_xpixel: 0,
|
||||
ws_ypixel: 0,
|
||||
};
|
||||
unsafe { winsz(fd.unwrap_or(libc::STDOUT_FILENO), &mut w) }
|
||||
.map_err(|err| err.into_pyexception(vm))?;
|
||||
(w.ws_col.into(), w.ws_row.into())
|
||||
}
|
||||
nix::ioctl_read_bad!(winsz, libc::TIOCGWINSZ, libc::winsize);
|
||||
let mut w = libc::winsize {
|
||||
ws_row: 0,
|
||||
ws_col: 0,
|
||||
ws_xpixel: 0,
|
||||
ws_ypixel: 0,
|
||||
};
|
||||
unsafe { winsz(fd.unwrap_or(libc::STDOUT_FILENO), &mut w) }
|
||||
.map_err(|err| err.into_pyexception(vm))?;
|
||||
(w.ws_col.into(), w.ws_row.into())
|
||||
};
|
||||
super::_os::PyTerminalSize { columns, lines }.into_struct_sequence(vm)
|
||||
Ok(super::_os::PyTerminalSize { columns, lines })
|
||||
}
|
||||
|
||||
// from libstd:
|
||||
@@ -2818,36 +2803,37 @@ mod nt {
|
||||
}
|
||||
|
||||
#[pyfunction]
|
||||
fn get_terminal_size(fd: OptionalArg<i32>, vm: &VirtualMachine) -> PyResult<PyTupleRef> {
|
||||
fn get_terminal_size(
|
||||
fd: OptionalArg<i32>,
|
||||
vm: &VirtualMachine,
|
||||
) -> PyResult<super::_os::PyTerminalSize> {
|
||||
let (columns, lines) = {
|
||||
{
|
||||
use winapi::um::{handleapi, processenv, winbase, wincon};
|
||||
let stdhandle = match fd {
|
||||
OptionalArg::Present(0) => winbase::STD_INPUT_HANDLE,
|
||||
OptionalArg::Present(1) | OptionalArg::Missing => winbase::STD_OUTPUT_HANDLE,
|
||||
OptionalArg::Present(2) => winbase::STD_ERROR_HANDLE,
|
||||
_ => return Err(vm.new_value_error("bad file descriptor".to_owned())),
|
||||
};
|
||||
let h = unsafe { processenv::GetStdHandle(stdhandle) };
|
||||
if h.is_null() {
|
||||
return Err(vm.new_os_error("handle cannot be retrieved".to_owned()));
|
||||
}
|
||||
if h == handleapi::INVALID_HANDLE_VALUE {
|
||||
return Err(errno_err(vm));
|
||||
}
|
||||
let mut csbi = wincon::CONSOLE_SCREEN_BUFFER_INFO::default();
|
||||
let ret = unsafe { wincon::GetConsoleScreenBufferInfo(h, &mut csbi) };
|
||||
if ret == 0 {
|
||||
return Err(errno_err(vm));
|
||||
}
|
||||
let w = csbi.srWindow;
|
||||
(
|
||||
(w.Right - w.Left + 1) as usize,
|
||||
(w.Bottom - w.Top + 1) as usize,
|
||||
)
|
||||
use winapi::um::{handleapi, processenv, winbase, wincon};
|
||||
let stdhandle = match fd {
|
||||
OptionalArg::Present(0) => winbase::STD_INPUT_HANDLE,
|
||||
OptionalArg::Present(1) | OptionalArg::Missing => winbase::STD_OUTPUT_HANDLE,
|
||||
OptionalArg::Present(2) => winbase::STD_ERROR_HANDLE,
|
||||
_ => return Err(vm.new_value_error("bad file descriptor".to_owned())),
|
||||
};
|
||||
let h = unsafe { processenv::GetStdHandle(stdhandle) };
|
||||
if h.is_null() {
|
||||
return Err(vm.new_os_error("handle cannot be retrieved".to_owned()));
|
||||
}
|
||||
if h == handleapi::INVALID_HANDLE_VALUE {
|
||||
return Err(errno_err(vm));
|
||||
}
|
||||
let mut csbi = wincon::CONSOLE_SCREEN_BUFFER_INFO::default();
|
||||
let ret = unsafe { wincon::GetConsoleScreenBufferInfo(h, &mut csbi) };
|
||||
if ret == 0 {
|
||||
return Err(errno_err(vm));
|
||||
}
|
||||
let w = csbi.srWindow;
|
||||
(
|
||||
(w.Right - w.Left + 1) as usize,
|
||||
(w.Bottom - w.Top + 1) as usize,
|
||||
)
|
||||
};
|
||||
super::_os::PyTerminalSize { columns, lines }.into_struct_sequence(vm)
|
||||
Ok(super::_os::PyTerminalSize { columns, lines })
|
||||
}
|
||||
|
||||
#[cfg(target_env = "msvc")]
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
use crate::builtins::int::PyIntRef;
|
||||
use crate::builtins::pystr::PyStrRef;
|
||||
use crate::exceptions::IntoPyException;
|
||||
use crate::pyobject::{BorrowValue, PyClassImpl, PyObjectRef, PyResult, PyStructSequence};
|
||||
use crate::pyobject::{
|
||||
BorrowValue, IntoPyObject, PyClassImpl, PyObjectRef, PyResult, PyStructSequence,
|
||||
};
|
||||
use crate::vm::VirtualMachine;
|
||||
use std::convert::TryFrom;
|
||||
use std::ptr::NonNull;
|
||||
@@ -46,9 +48,9 @@ impl From<User> for Passwd {
|
||||
}
|
||||
}
|
||||
|
||||
fn pwd_getpwnam(name: PyStrRef, vm: &VirtualMachine) -> PyResult {
|
||||
fn pwd_getpwnam(name: PyStrRef, vm: &VirtualMachine) -> PyResult<Passwd> {
|
||||
match User::from_name(name.borrow_value()).map_err(|err| err.into_pyexception(vm))? {
|
||||
Some(user) => Ok(Passwd::from(user).into_struct_sequence(vm)?.into_object()),
|
||||
Some(user) => Ok(Passwd::from(user)),
|
||||
None => {
|
||||
let name_repr = vm.to_repr(name.as_object())?;
|
||||
let message = vm
|
||||
@@ -59,14 +61,14 @@ fn pwd_getpwnam(name: PyStrRef, vm: &VirtualMachine) -> PyResult {
|
||||
}
|
||||
}
|
||||
|
||||
fn pwd_getpwuid(uid: PyIntRef, vm: &VirtualMachine) -> PyResult {
|
||||
fn pwd_getpwuid(uid: PyIntRef, vm: &VirtualMachine) -> PyResult<Passwd> {
|
||||
let uid_t = libc::uid_t::try_from(uid.borrow_value()).map(unistd::Uid::from_raw);
|
||||
let user = match uid_t {
|
||||
Ok(uid) => User::from_uid(uid).map_err(|err| err.into_pyexception(vm))?,
|
||||
Err(_) => None,
|
||||
};
|
||||
match user {
|
||||
Some(user) => Ok(Passwd::from(user).into_struct_sequence(vm)?.into_object()),
|
||||
Some(user) => Ok(Passwd::from(user)),
|
||||
None => {
|
||||
let message = vm
|
||||
.ctx
|
||||
@@ -86,7 +88,7 @@ fn pwd_getpwall(vm: &VirtualMachine) -> PyResult {
|
||||
unsafe { libc::setpwent() };
|
||||
while let Some(ptr) = NonNull::new(unsafe { libc::getpwent() }) {
|
||||
let user = User::from(unsafe { ptr.as_ref() });
|
||||
let passwd = Passwd::from(user).into_struct_sequence(vm)?.into_object();
|
||||
let passwd = Passwd::from(user).into_pyobject(vm);
|
||||
list.push(passwd);
|
||||
}
|
||||
unsafe { libc::endpwent() };
|
||||
|
||||
172
vm/src/stdlib/resource.rs
Normal file
172
vm/src/stdlib/resource.rs
Normal file
@@ -0,0 +1,172 @@
|
||||
pub(crate) use resource::make_module;
|
||||
|
||||
#[pymodule]
|
||||
mod resource {
|
||||
use super::super::os;
|
||||
use crate::exceptions::IntoPyException;
|
||||
use crate::pyobject::{IntoPyObject, PyObjectRef, PyResult, PyStructSequence, TryFromObject};
|
||||
use crate::VirtualMachine;
|
||||
use std::{io, mem};
|
||||
|
||||
cfg_if::cfg_if! {
|
||||
if #[cfg(target_os = "linux")] {
|
||||
use libc::RLIMIT_NLIMITS as RLIM_NLIMITS;
|
||||
} else if #[cfg(target_os = "android")] {
|
||||
// TODO: this should be in libc soon
|
||||
const RLIM_NLIMITS: i32 = 16;
|
||||
} else {
|
||||
// in bsd-ish platforms, this constant isn't abi-stable across os versions, so we just
|
||||
// pick a high number so we don't get false positive ValueErrors and just bubble up the
|
||||
// EINVAL that get/setrlimit return on an invalid resource
|
||||
const RLIM_NLIMITS: i32 = 256;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: RLIMIT_OFILE,
|
||||
#[pyattr]
|
||||
use libc::{
|
||||
RLIMIT_AS, RLIMIT_CORE, RLIMIT_CPU, RLIMIT_DATA, RLIMIT_FSIZE, RLIMIT_MEMLOCK,
|
||||
RLIMIT_NOFILE, RLIMIT_NPROC, RLIMIT_RSS, RLIMIT_STACK, RLIM_INFINITY,
|
||||
};
|
||||
|
||||
#[cfg(any(target_os = "linux", target_os = "android", target_os = "emscripten"))]
|
||||
#[pyattr]
|
||||
use libc::{RLIMIT_MSGQUEUE, RLIMIT_NICE, RLIMIT_RTPRIO, RLIMIT_SIGPENDING};
|
||||
// TODO: I think this is supposed to be defined for all linux_like?
|
||||
#[cfg(target_os = "linux")]
|
||||
#[pyattr]
|
||||
use libc::RLIMIT_RTTIME;
|
||||
|
||||
#[cfg(any(target_os = "freebsd", target_os = "netbsd"))]
|
||||
#[pyattr]
|
||||
use libc::{RLIMIT_NPTS, RLIMIT_SBSIZE, RLIMIT_SWAP};
|
||||
|
||||
#[cfg(any(target_os = "freebsd", target_os = "solaris", target_os = "illumos"))]
|
||||
#[pyattr]
|
||||
use libc::{RLIMIT_NPTS, RLIMIT_SBSIZE, RLIMIT_SWAP, RLIMIT_VMEM};
|
||||
|
||||
#[pyattr]
|
||||
#[pyclass(name = "struct_rusage")]
|
||||
#[derive(PyStructSequence)]
|
||||
struct Rusage {
|
||||
ru_utime: f64,
|
||||
ru_stime: f64,
|
||||
ru_maxrss: libc::c_long,
|
||||
ru_ixrss: libc::c_long,
|
||||
ru_idrss: libc::c_long,
|
||||
ru_isrss: libc::c_long,
|
||||
ru_minflt: libc::c_long,
|
||||
ru_majflt: libc::c_long,
|
||||
ru_nswap: libc::c_long,
|
||||
ru_inblock: libc::c_long,
|
||||
ru_oublock: libc::c_long,
|
||||
ru_msgsnd: libc::c_long,
|
||||
ru_msgrcv: libc::c_long,
|
||||
ru_nsignals: libc::c_long,
|
||||
ru_nvcsw: libc::c_long,
|
||||
ru_nivcsw: libc::c_long,
|
||||
}
|
||||
|
||||
#[pyimpl(with(PyStructSequence))]
|
||||
impl Rusage {}
|
||||
|
||||
impl From<libc::rusage> for Rusage {
|
||||
fn from(rusage: libc::rusage) -> Self {
|
||||
let tv = |tv: libc::timeval| tv.tv_sec as f64 + (tv.tv_usec as f64 / 1_000_000.0);
|
||||
Rusage {
|
||||
ru_utime: tv(rusage.ru_utime),
|
||||
ru_stime: tv(rusage.ru_utime),
|
||||
ru_maxrss: rusage.ru_maxrss,
|
||||
ru_ixrss: rusage.ru_ixrss,
|
||||
ru_idrss: rusage.ru_idrss,
|
||||
ru_isrss: rusage.ru_isrss,
|
||||
ru_minflt: rusage.ru_minflt,
|
||||
ru_majflt: rusage.ru_majflt,
|
||||
ru_nswap: rusage.ru_nswap,
|
||||
ru_inblock: rusage.ru_inblock,
|
||||
ru_oublock: rusage.ru_oublock,
|
||||
ru_msgsnd: rusage.ru_msgsnd,
|
||||
ru_msgrcv: rusage.ru_msgrcv,
|
||||
ru_nsignals: rusage.ru_nsignals,
|
||||
ru_nvcsw: rusage.ru_nvcsw,
|
||||
ru_nivcsw: rusage.ru_nivcsw,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[pyfunction]
|
||||
fn getrusage(who: i32, vm: &VirtualMachine) -> PyResult<Rusage> {
|
||||
let res = unsafe {
|
||||
let mut rusage = mem::MaybeUninit::<libc::rusage>::uninit();
|
||||
if libc::getrusage(who, rusage.as_mut_ptr()) == -1 {
|
||||
Err(io::Error::last_os_error())
|
||||
} else {
|
||||
Ok(rusage.assume_init())
|
||||
}
|
||||
};
|
||||
res.map(Rusage::from).map_err(|e| {
|
||||
if e.kind() == io::ErrorKind::InvalidInput {
|
||||
vm.new_value_error("invalid who parameter".to_owned())
|
||||
} else {
|
||||
e.into_pyexception(vm)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
struct Limits(libc::rlimit);
|
||||
impl TryFromObject for Limits {
|
||||
fn try_from_object(vm: &VirtualMachine, obj: PyObjectRef) -> PyResult<Self> {
|
||||
let seq = vm.extract_elements::<libc::rlim_t>(&obj)?;
|
||||
match *seq {
|
||||
[cur, max] => Ok(Self(libc::rlimit {
|
||||
rlim_cur: cur & RLIM_INFINITY,
|
||||
rlim_max: max & RLIM_INFINITY,
|
||||
})),
|
||||
_ => Err(vm.new_value_error("expected a tuple of 2 integers".to_owned())),
|
||||
}
|
||||
}
|
||||
}
|
||||
impl IntoPyObject for Limits {
|
||||
fn into_pyobject(self, vm: &VirtualMachine) -> PyObjectRef {
|
||||
(self.0.rlim_cur, self.0.rlim_max).into_pyobject(vm)
|
||||
}
|
||||
}
|
||||
|
||||
#[pyfunction]
|
||||
fn getrlimit(resource: i32, vm: &VirtualMachine) -> PyResult<Limits> {
|
||||
if resource < 0 || resource >= RLIM_NLIMITS as _ {
|
||||
return Err(vm.new_value_error("invalid resource specified".to_owned()));
|
||||
}
|
||||
let rlimit = unsafe {
|
||||
let mut rlimit = mem::MaybeUninit::<libc::rlimit>::uninit();
|
||||
if libc::getrlimit(resource as _, rlimit.as_mut_ptr()) == -1 {
|
||||
return Err(os::errno_err(vm));
|
||||
}
|
||||
rlimit.assume_init()
|
||||
};
|
||||
Ok(Limits(rlimit))
|
||||
}
|
||||
|
||||
#[pyfunction]
|
||||
fn setrlimit(resource: i32, limits: Limits, vm: &VirtualMachine) -> PyResult<()> {
|
||||
if resource < 0 || resource >= RLIM_NLIMITS as _ {
|
||||
return Err(vm.new_value_error("invalid resource specified".to_owned()));
|
||||
}
|
||||
let res = unsafe {
|
||||
if libc::setrlimit(resource as _, &limits.0) == -1 {
|
||||
Err(io::Error::last_os_error())
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
};
|
||||
res.map_err(|e| match e.kind() {
|
||||
io::ErrorKind::InvalidInput => {
|
||||
vm.new_value_error("current limit exceeds maximum limit".to_owned())
|
||||
}
|
||||
io::ErrorKind::PermissionDenied => {
|
||||
vm.new_value_error("not allowed to raise maximum limit".to_owned())
|
||||
}
|
||||
_ => e.into_pyexception(vm),
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -3,10 +3,7 @@ use crate::vm::VirtualMachine;
|
||||
use std::io;
|
||||
|
||||
pub(crate) fn make_module(vm: &VirtualMachine) -> PyObjectRef {
|
||||
#[cfg(windows)]
|
||||
{
|
||||
let _ = unsafe { winapi::um::winsock2::WSAStartup(0x0101, &mut std::mem::zeroed()) };
|
||||
}
|
||||
super::socket::init_winsock();
|
||||
|
||||
decl::make_module(vm)
|
||||
}
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
use crate::exceptions::IntoPyException;
|
||||
use crate::pyobject::{PyObjectRef, PyResult, TryFromObject};
|
||||
use crate::vm::{VirtualMachine, NSIG};
|
||||
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
use std::sync::atomic::{self, AtomicBool, Ordering};
|
||||
|
||||
#[cfg(unix)]
|
||||
use nix::unistd::alarm as sig_alarm;
|
||||
@@ -23,9 +24,37 @@ static TRIGGERS: [AtomicBool; NSIG] = [ATOMIC_FALSE; NSIG];
|
||||
|
||||
static ANY_TRIGGERED: AtomicBool = AtomicBool::new(false);
|
||||
|
||||
cfg_if::cfg_if! {
|
||||
if #[cfg(windows)] {
|
||||
use winapi::um::winsock2;
|
||||
type WakeupFd = libc::SOCKET;
|
||||
const INVALID_WAKEUP: WakeupFd = (-1isize) as usize;
|
||||
static WAKEUP: atomic::AtomicUsize = atomic::AtomicUsize::new(INVALID_WAKEUP);
|
||||
// windows doesn't use the same fds for files and sockets like windows does, so we need
|
||||
// this to know whether to send() or write()
|
||||
static WAKEUP_IS_SOCKET: AtomicBool = AtomicBool::new(false);
|
||||
} else {
|
||||
type WakeupFd = i32;
|
||||
const INVALID_WAKEUP: WakeupFd = -1;
|
||||
static WAKEUP: atomic::AtomicI32 = atomic::AtomicI32::new(INVALID_WAKEUP);
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" fn run_signal(signum: i32) {
|
||||
ANY_TRIGGERED.store(true, Ordering::Relaxed);
|
||||
TRIGGERS[signum as usize].store(true, Ordering::Relaxed);
|
||||
ANY_TRIGGERED.store(true, Ordering::SeqCst);
|
||||
let wakeup_fd = WAKEUP.load(Ordering::Relaxed);
|
||||
if wakeup_fd != INVALID_WAKEUP {
|
||||
let sigbyte = signum as u8;
|
||||
#[cfg(windows)]
|
||||
if WAKEUP_IS_SOCKET.load(Ordering::Relaxed) {
|
||||
let _res =
|
||||
unsafe { winsock2::send(wakeup_fd, &sigbyte as *const u8 as *const _, 1, 0) };
|
||||
return;
|
||||
}
|
||||
let _res = unsafe { libc::write(wakeup_fd as _, &sigbyte as *const u8 as *const _, 1) };
|
||||
// TODO: handle _res < 1, support warn_on_full_buffer
|
||||
}
|
||||
}
|
||||
|
||||
fn assert_in_range(signum: i32, vm: &VirtualMachine) -> PyResult<()> {
|
||||
@@ -36,6 +65,11 @@ fn assert_in_range(signum: i32, vm: &VirtualMachine) -> PyResult<()> {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(all(unix, not(target_os = "redox")))]
|
||||
extern "C" {
|
||||
fn siginterrupt(sig: i32, flag: i32) -> i32;
|
||||
}
|
||||
|
||||
fn _signal_signal(
|
||||
signalnum: i32,
|
||||
handler: PyObjectRef,
|
||||
@@ -65,13 +99,8 @@ fn _signal_signal(
|
||||
return Err(vm.new_os_error("Failed to set signal".to_owned()));
|
||||
}
|
||||
#[cfg(all(unix, not(target_os = "redox")))]
|
||||
{
|
||||
extern "C" {
|
||||
fn siginterrupt(sig: i32, flag: i32);
|
||||
}
|
||||
unsafe {
|
||||
siginterrupt(signalnum, 1);
|
||||
}
|
||||
unsafe {
|
||||
siginterrupt(signalnum, 1);
|
||||
}
|
||||
|
||||
let old_handler = std::mem::replace(
|
||||
@@ -145,6 +174,78 @@ fn _signal_default_int_handler(
|
||||
Err(vm.new_exception_empty(vm.ctx.exceptions.keyboard_interrupt.clone()))
|
||||
}
|
||||
|
||||
#[derive(FromArgs)]
|
||||
struct SetWakeupFdArgs {
|
||||
#[pyarg(any)]
|
||||
fd: WakeupFd,
|
||||
#[pyarg(named, default = "true")]
|
||||
warn_on_full_buffer: bool,
|
||||
}
|
||||
|
||||
fn _signal_set_wakeup_fd(args: SetWakeupFdArgs, vm: &VirtualMachine) -> PyResult<WakeupFd> {
|
||||
// TODO: implement warn_on_full_buffer
|
||||
let _ = args.warn_on_full_buffer;
|
||||
let fd = args.fd;
|
||||
|
||||
if vm.signal_handlers.is_none() {
|
||||
return Err(vm.new_value_error("signal only works in main thread".to_owned()));
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
let is_socket = if fd != INVALID_WAKEUP {
|
||||
super::socket::init_winsock();
|
||||
let mut res = 0i32;
|
||||
let mut res_size = std::mem::size_of::<i32>() as i32;
|
||||
let res = unsafe {
|
||||
winsock2::getsockopt(
|
||||
fd,
|
||||
winsock2::SOL_SOCKET,
|
||||
winsock2::SO_ERROR,
|
||||
&mut res as *mut i32 as *mut _,
|
||||
&mut res_size,
|
||||
)
|
||||
};
|
||||
// if getsockopt succeeded, fd is for sure a socket
|
||||
let is_socket = res == 0;
|
||||
if !is_socket {
|
||||
let err = std::io::Error::last_os_error();
|
||||
// if getsockopt failed for some other reason, throw
|
||||
if err.raw_os_error() != Some(winsock2::WSAENOTSOCK) {
|
||||
return Err(err.into_pyexception(vm));
|
||||
}
|
||||
}
|
||||
is_socket
|
||||
} else {
|
||||
false
|
||||
};
|
||||
#[cfg(not(windows))]
|
||||
if fd != INVALID_WAKEUP {
|
||||
use nix::fcntl;
|
||||
let oflags = fcntl::fcntl(fd, fcntl::F_GETFL).map_err(|e| e.into_pyexception(vm))?;
|
||||
let nonblock = fcntl::OFlag::from_bits_truncate(oflags).contains(fcntl::OFlag::O_NONBLOCK);
|
||||
if !nonblock {
|
||||
return Err(vm.new_value_error(format!("the fd {} must be in non-blocking mode", fd)));
|
||||
}
|
||||
}
|
||||
|
||||
let old_fd = WAKEUP.swap(fd, Ordering::Relaxed);
|
||||
#[cfg(windows)]
|
||||
WAKEUP_IS_SOCKET.store(is_socket, Ordering::Relaxed);
|
||||
|
||||
Ok(old_fd)
|
||||
}
|
||||
|
||||
#[cfg(all(unix, not(target_os = "redox")))]
|
||||
fn _signal_siginterrupt(signum: i32, flag: i32, vm: &VirtualMachine) -> PyResult<()> {
|
||||
assert_in_range(signum, vm)?;
|
||||
let res = unsafe { siginterrupt(signum, flag) };
|
||||
if res < 0 {
|
||||
Err(super::os::errno_err(vm))
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn make_module(vm: &VirtualMachine) -> PyObjectRef {
|
||||
let ctx = &vm.ctx;
|
||||
|
||||
@@ -156,6 +257,7 @@ pub fn make_module(vm: &VirtualMachine) -> PyObjectRef {
|
||||
let module = py_module!(vm, "_signal", {
|
||||
"signal" => named_function!(ctx, _signal, signal),
|
||||
"getsignal" => named_function!(ctx, _signal, getsignal),
|
||||
"set_wakeup_fd" => named_function!(ctx, _signal, set_wakeup_fd),
|
||||
"SIG_DFL" => sig_dfl.clone(),
|
||||
"SIG_IGN" => sig_ign.clone(),
|
||||
"SIGABRT" => ctx.new_int(libc::SIGABRT as u8),
|
||||
@@ -220,6 +322,11 @@ fn extend_module_platform_specific(vm: &VirtualMachine, module: &PyObjectRef) {
|
||||
"SIGSYS" => ctx.new_int(libc::SIGSYS as u8),
|
||||
});
|
||||
|
||||
#[cfg(not(target_os = "redox"))]
|
||||
extend_module!(vm, module, {
|
||||
"siginterrupt" => named_function!(ctx, _signal, siginterrupt),
|
||||
});
|
||||
|
||||
#[cfg(not(any(target_os = "macos", target_os = "openbsd", target_os = "freebsd")))]
|
||||
{
|
||||
extend_module!(vm, module, {
|
||||
|
||||
@@ -1077,6 +1077,8 @@ rustpython_common::static_cell! {
|
||||
}
|
||||
|
||||
pub fn make_module(vm: &VirtualMachine) -> PyObjectRef {
|
||||
init_winsock();
|
||||
|
||||
let ctx = &vm.ctx;
|
||||
let socket_timeout = TIMEOUT_ERROR
|
||||
.get_or_init(|| {
|
||||
@@ -1184,3 +1186,13 @@ fn extend_module_platform_specific(vm: &VirtualMachine, module: &PyObjectRef) {
|
||||
"sethostname" => named_function!(ctx, _socket, sethostname),
|
||||
});
|
||||
}
|
||||
|
||||
pub fn init_winsock() {
|
||||
#[cfg(windows)]
|
||||
{
|
||||
static WSA_INIT: parking_lot::Once = parking_lot::Once::new();
|
||||
WSA_INIT.call_once(|| {
|
||||
let _ = unsafe { winapi::um::winsock2::WSAStartup(0x0101, &mut std::mem::zeroed()) };
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,19 +1,21 @@
|
||||
use crate::pyobject::{ItemProtocol, PyObjectRef};
|
||||
use crate::pyobject::{IntoPyObject, ItemProtocol, PyObjectRef};
|
||||
use crate::VirtualMachine;
|
||||
|
||||
use crate::sysmodule::MULTIARCH;
|
||||
|
||||
pub fn make_module(vm: &VirtualMachine) -> PyObjectRef {
|
||||
let vars = vm.ctx.new_dict();
|
||||
macro_rules! hashmap {
|
||||
macro_rules! sysvars {
|
||||
($($key:literal => $value:expr),*$(,)?) => {{
|
||||
$(vars.set_item($key, vm.ctx.new_str($value), vm).unwrap();)*
|
||||
$(vars.set_item($key, $value.into_pyobject(vm), vm).unwrap();)*
|
||||
}};
|
||||
}
|
||||
hashmap! {
|
||||
sysvars! {
|
||||
// fake shared module extension
|
||||
"EXT_SUFFIX" => format!(".rustpython-{}", MULTIARCH),
|
||||
"MULTIARCH" => MULTIARCH,
|
||||
// enough for tests to stop expecting urandom() to fail after restricting file resources
|
||||
"HAVE_GETRANDOM" => 1,
|
||||
}
|
||||
include!(concat!(env!("OUT_DIR"), "/env_vars.rs"));
|
||||
|
||||
|
||||
@@ -10,6 +10,9 @@ mod termios {
|
||||
use std::convert::TryFrom;
|
||||
use termios::Termios;
|
||||
|
||||
// TODO: more ioctl numbers
|
||||
#[pyattr]
|
||||
use libc::{TIOCGWINSZ, TIOCSWINSZ};
|
||||
#[pyattr]
|
||||
use termios::{
|
||||
os::target::NCCS, B0, B110, B1200, B134, B150, B1800, B19200, B200, B2400, B300, B38400,
|
||||
|
||||
@@ -9,7 +9,6 @@ use chrono::{Datelike, Timelike};
|
||||
|
||||
use crate::builtins::pystr::PyStrRef;
|
||||
use crate::builtins::pytype::PyTypeRef;
|
||||
use crate::builtins::tuple::PyTupleRef;
|
||||
use crate::function::OptionalArg;
|
||||
use crate::pyobject::{
|
||||
BorrowValue, Either, PyClassImpl, PyObjectRef, PyResult, PyStructSequence, TryFromObject,
|
||||
@@ -90,23 +89,23 @@ fn pyobj_to_naive_date_time(
|
||||
}
|
||||
|
||||
/// https://docs.python.org/3/library/time.html?highlight=gmtime#time.gmtime
|
||||
fn time_gmtime(secs: OptionalArg<Either<f64, i64>>, vm: &VirtualMachine) -> PyResult<PyObjectRef> {
|
||||
fn time_gmtime(secs: OptionalArg<Either<f64, i64>>, vm: &VirtualMachine) -> PyResult<PyStructTime> {
|
||||
let default = chrono::offset::Utc::now().naive_utc();
|
||||
let instant = match secs {
|
||||
OptionalArg::Present(secs) => pyobj_to_naive_date_time(secs, vm)?,
|
||||
OptionalArg::Missing => default,
|
||||
};
|
||||
Ok(PyStructTime::new(vm, instant, 0).into_obj(vm))
|
||||
Ok(PyStructTime::new(vm, instant, 0))
|
||||
}
|
||||
|
||||
fn time_localtime(
|
||||
secs: OptionalArg<Either<f64, i64>>,
|
||||
vm: &VirtualMachine,
|
||||
) -> PyResult<PyObjectRef> {
|
||||
) -> PyResult<PyStructTime> {
|
||||
let instant = optional_or_localtime(secs, vm)?;
|
||||
// TODO: isdst flag must be valid value here
|
||||
// https://docs.python.org/3/library/time.html#time.localtime
|
||||
Ok(PyStructTime::new(vm, instant, -1).into_obj(vm))
|
||||
Ok(PyStructTime::new(vm, instant, -1))
|
||||
}
|
||||
|
||||
fn time_mktime(t: PyStructTime, vm: &VirtualMachine) -> PyResult {
|
||||
@@ -154,14 +153,18 @@ fn time_strftime(format: PyStrRef, t: OptionalArg<PyStructTime>, vm: &VirtualMac
|
||||
Ok(vm.ctx.new_str(formatted_time))
|
||||
}
|
||||
|
||||
fn time_strptime(string: PyStrRef, format: OptionalArg<PyStrRef>, vm: &VirtualMachine) -> PyResult {
|
||||
fn time_strptime(
|
||||
string: PyStrRef,
|
||||
format: OptionalArg<PyStrRef>,
|
||||
vm: &VirtualMachine,
|
||||
) -> PyResult<PyStructTime> {
|
||||
let format = match format {
|
||||
OptionalArg::Present(ref format) => format.borrow_value(),
|
||||
OptionalArg::Missing => "%a %b %H:%M:%S %Y",
|
||||
};
|
||||
let instant = NaiveDateTime::parse_from_str(string.borrow_value(), format)
|
||||
.map_err(|e| vm.new_value_error(format!("Parse error: {:?}", e)))?;
|
||||
Ok(PyStructTime::new(vm, instant, -1).into_obj(vm))
|
||||
Ok(PyStructTime::new(vm, instant, -1))
|
||||
}
|
||||
|
||||
#[pyclass(module = "time", name = "struct_time")]
|
||||
@@ -217,14 +220,10 @@ impl PyStructTime {
|
||||
Ok(dt)
|
||||
}
|
||||
|
||||
fn into_obj(self, vm: &VirtualMachine) -> PyObjectRef {
|
||||
self.into_struct_sequence(vm).unwrap().into_object()
|
||||
}
|
||||
|
||||
#[pyslot]
|
||||
fn tp_new(_cls: PyTypeRef, seq: PyObjectRef, vm: &VirtualMachine) -> PyResult<PyTupleRef> {
|
||||
fn tp_new(_cls: PyTypeRef, seq: PyObjectRef, vm: &VirtualMachine) -> PyResult<Self> {
|
||||
// cls is ignorable because this is not a basetype
|
||||
Self::try_from_object(vm, seq)?.into_struct_sequence(vm)
|
||||
Self::try_from_object(vm, seq)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -319,7 +319,7 @@ fn sys_getwindowsversion(vm: &VirtualMachine) -> PyResult<crate::builtins::tuple
|
||||
sp.into_string()
|
||||
.map_err(|_| vm.new_os_error("service pack is not ASCII".to_owned()))?
|
||||
};
|
||||
WindowsVersion {
|
||||
Ok(WindowsVersion {
|
||||
major: version.dwMajorVersion,
|
||||
minor: version.dwMinorVersion,
|
||||
build: version.dwBuildNumber,
|
||||
@@ -335,7 +335,7 @@ fn sys_getwindowsversion(vm: &VirtualMachine) -> PyResult<crate::builtins::tuple
|
||||
version.dwBuildNumber,
|
||||
), // TODO Provide accurate version, like CPython impl
|
||||
}
|
||||
.into_struct_sequence(vm)
|
||||
.into_struct_sequence(vm))
|
||||
}
|
||||
|
||||
pub fn get_stdin(vm: &VirtualMachine) -> PyResult {
|
||||
@@ -497,23 +497,19 @@ pub(crate) fn make_module(vm: &VirtualMachine, module: PyObjectRef, builtins: Py
|
||||
let ctx = &vm.ctx;
|
||||
|
||||
let _flags_type = SysFlags::make_class(ctx);
|
||||
let flags = SysFlags::from_settings(&vm.state.settings)
|
||||
.into_struct_sequence(vm)
|
||||
.unwrap();
|
||||
let flags = SysFlags::from_settings(&vm.state.settings).into_struct_sequence(vm);
|
||||
|
||||
let _version_info_type = version::VersionInfo::make_class(ctx);
|
||||
let version_info = version::VersionInfo::VERSION
|
||||
.into_struct_sequence(vm)
|
||||
.unwrap();
|
||||
let version_info = version::VersionInfo::VERSION.into_struct_sequence(vm);
|
||||
|
||||
let _hash_info_type = PyHashInfo::make_class(ctx);
|
||||
let hash_info = PyHashInfo::INFO.into_struct_sequence(vm).unwrap();
|
||||
let hash_info = PyHashInfo::INFO.into_struct_sequence(vm);
|
||||
|
||||
let _float_info_type = PyFloatInfo::make_class(ctx);
|
||||
let float_info = PyFloatInfo::INFO.into_struct_sequence(vm).unwrap();
|
||||
let float_info = PyFloatInfo::INFO.into_struct_sequence(vm);
|
||||
|
||||
let _int_info_type = PyIntInfo::make_class(ctx);
|
||||
let int_info = PyIntInfo::INFO.into_struct_sequence(vm).unwrap();
|
||||
let int_info = PyIntInfo::INFO.into_struct_sequence(vm);
|
||||
|
||||
// TODO Add crate version to this namespace
|
||||
let implementation = py_namespace!(vm, {
|
||||
@@ -634,12 +630,16 @@ setprofile() -- set the global profiling function
|
||||
setrecursionlimit() -- set the max recursion depth for the interpreter
|
||||
settrace() -- set the global debug tracing function
|
||||
";
|
||||
let mut module_names: Vec<String> = vm.state.stdlib_inits.keys().cloned().collect();
|
||||
module_names.push("sys".to_owned());
|
||||
module_names.push("builtins".to_owned());
|
||||
let mut module_names: Vec<_> = vm.state.stdlib_inits.keys().cloned().collect();
|
||||
module_names.push("sys".into());
|
||||
module_names.push("builtins".into());
|
||||
module_names.sort();
|
||||
let builtin_module_names =
|
||||
ctx.new_tuple(module_names.into_iter().map(|n| ctx.new_str(n)).collect());
|
||||
let builtin_module_names = ctx.new_tuple(
|
||||
module_names
|
||||
.into_iter()
|
||||
.map(|n| ctx.new_str(n.into_owned()))
|
||||
.collect(),
|
||||
);
|
||||
let modules = ctx.new_dict();
|
||||
|
||||
let prefix = option_env!("RUSTPYTHON_PREFIX").unwrap_or("/usr/local");
|
||||
|
||||
10
vm/src/vm.rs
10
vm/src/vm.rs
@@ -4,6 +4,7 @@
|
||||
//! https://github.com/ProgVal/pythonvm-rust/blob/master/src/processor/mod.rs
|
||||
//!
|
||||
|
||||
use std::borrow::Cow;
|
||||
use std::cell::{Cell, Ref, RefCell};
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::fmt;
|
||||
@@ -115,7 +116,7 @@ pub(crate) mod thread {
|
||||
|
||||
pub struct PyGlobalState {
|
||||
pub settings: PySettings,
|
||||
pub stdlib_inits: HashMap<String, stdlib::StdlibInitFunc, ahash::RandomState>,
|
||||
pub stdlib_inits: stdlib::StdlibMap,
|
||||
pub frozen: HashMap<String, code::FrozenModule, ahash::RandomState>,
|
||||
pub stacksize: AtomicCell<usize>,
|
||||
pub thread_count: AtomicCell<usize>,
|
||||
@@ -361,10 +362,13 @@ impl VirtualMachine {
|
||||
}
|
||||
|
||||
/// Can only be used in the initialization closure passed to [`Interpreter::new_with_init`]
|
||||
pub fn add_native_module(&mut self, name: String, module: stdlib::StdlibInitFunc) {
|
||||
pub fn add_native_module<S>(&mut self, name: S, module: stdlib::StdlibInitFunc)
|
||||
where
|
||||
S: Into<Cow<'static, str>>,
|
||||
{
|
||||
let state = PyRc::get_mut(&mut self.state)
|
||||
.expect("can't add_native_module when there are multiple threads");
|
||||
state.stdlib_inits.insert(name, module);
|
||||
state.stdlib_inits.insert(name.into(), module);
|
||||
}
|
||||
|
||||
/// Can only be used in the initialization closure passed to [`Interpreter::new_with_init`]
|
||||
|
||||
Reference in New Issue
Block a user