From 0d492e7875dec53372e3e6a7c6cfb027e7d8c466 Mon Sep 17 00:00:00 2001 From: coolreader18 <33094578+coolreader18@users.noreply.github.com> Date: Mon, 19 Aug 2019 23:47:27 -0500 Subject: [PATCH 1/6] Raise a KeyboardInterrupt on a SIGINT --- src/main.rs | 21 +++--- vm/src/exceptions.rs | 8 +- vm/src/frame.rs | 5 +- vm/src/stdlib/signal.rs | 139 +++++++++++++++++++++-------------- vm/src/stdlib/time_module.rs | 33 +++++++-- vm/src/vm.rs | 12 ++- 6 files changed, 137 insertions(+), 81 deletions(-) diff --git a/src/main.rs b/src/main.rs index 7e62ff914..221e2e26c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -9,7 +9,7 @@ use rustpython_compiler::{compile, error::CompileError, error::CompileErrorType} use rustpython_parser::error::ParseErrorType; use rustpython_vm::{ import, - obj::objstr, + obj::objstr::PyStringRef, print_exception, pyobject::{ItemProtocol, PyResult}, scope::Scope, @@ -486,12 +486,10 @@ fn get_history_path() -> PathBuf { xdg_dirs.place_cache_file("repl_history.txt").unwrap() } -fn get_prompt(vm: &VirtualMachine, prompt_name: &str) -> String { +fn get_prompt(vm: &VirtualMachine, prompt_name: &str) -> Option { vm.get_attribute(vm.sys_module.clone(), prompt_name) + .and_then(|prompt| vm.to_str(&prompt)) .ok() - .as_ref() - .map(objstr::get_value) - .unwrap_or_else(String::new) } #[cfg(not(target_os = "redox"))] @@ -521,7 +519,8 @@ fn run_shell(vm: &VirtualMachine, scope: Scope) -> PyResult<()> { } else { get_prompt(vm, "ps1") }; - match repl.readline(&prompt) { + let prompt = prompt.as_ref().map(|s| s.as_str()).unwrap_or(""); + match repl.readline(prompt) { Ok(line) => { debug!("You entered {:?}", line); input.push_str(&line); @@ -542,7 +541,6 @@ fn run_shell(vm: &VirtualMachine, scope: Scope) -> PyResult<()> { .. }) => { continuing = true; - continue; } _ => { input = String::new(); @@ -550,10 +548,11 @@ fn run_shell(vm: &VirtualMachine, scope: Scope) -> PyResult<()> { } } Err(ReadlineError::Interrupted) => { - // TODO: Raise a real KeyboardInterrupt exception - println!("^C"); + let exc = vm + .new_empty_exception(vm.ctx.exceptions.keyboard_interrupt.clone()) + .unwrap(); + print_exception(vm, &exc); continuing = false; - continue; } Err(ReadlineError::Eof) => { break; @@ -562,7 +561,7 @@ fn run_shell(vm: &VirtualMachine, scope: Scope) -> PyResult<()> { println!("Error: {:?}", err); break; } - }; + } } repl.save_history(repl_history_path_str).unwrap(); diff --git a/vm/src/exceptions.rs b/vm/src/exceptions.rs index a78a286b8..c9d7680dd 100644 --- a/vm/src/exceptions.rs +++ b/vm/src/exceptions.rs @@ -15,8 +15,8 @@ fn exception_init(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult { let exc_args = vm.ctx.new_tuple(args.args[1..].to_vec()); vm.set_attr(&exc_self, "args", exc_args)?; - let traceback = vm.ctx.new_list(Vec::new()); - vm.set_attr(&exc_self, "__traceback__", traceback)?; + // TODO: have an actual `traceback` object for __traceback__ + vm.set_attr(&exc_self, "__traceback__", vm.ctx.new_list(vec![]))?; vm.set_attr(&exc_self, "__cause__", vm.get_none())?; vm.set_attr(&exc_self, "__context__", vm.get_none())?; vm.set_attr(&exc_self, "__suppress_context__", vm.new_bool(false))?; @@ -102,11 +102,13 @@ fn print_traceback_entry(vm: &VirtualMachine, tb_entry: &PyObjectRef) { /// Print exception with traceback pub fn print_exception_inner(vm: &VirtualMachine, exc: &PyObjectRef) { if let Ok(tb) = vm.get_attribute(exc.clone(), "__traceback__") { - println!("Traceback (most recent call last):"); if objtype::isinstance(&tb, &vm.ctx.list_type()) { let mut tb_entries = objsequence::get_elements_list(&tb).to_vec(); tb_entries.reverse(); + if !tb_entries.is_empty() { + println!("Traceback (most recent call last):"); + } for exc_location in tb_entries.iter() { print_traceback_entry(vm, exc_location); } diff --git a/vm/src/frame.rs b/vm/src/frame.rs index c8f93d55e..b29c9d2b2 100644 --- a/vm/src/frame.rs +++ b/vm/src/frame.rs @@ -167,9 +167,8 @@ impl Frame { #[allow(clippy::cognitive_complexity)] fn execute_instruction(&self, vm: &VirtualMachine) -> FrameResult { #[cfg(not(target_arch = "wasm32"))] - { - check_signals(vm); - } + check_signals(vm)?; + let instruction = self.fetch_instruction(); flame_guard!(format!("Frame::execute_instruction({:?})", instruction)); diff --git a/vm/src/stdlib/signal.rs b/vm/src/stdlib/signal.rs index 2950282b1..3473252b5 100644 --- a/vm/src/stdlib/signal.rs +++ b/vm/src/stdlib/signal.rs @@ -1,5 +1,5 @@ use crate::obj::objint::PyIntRef; -use crate::pyobject::{IdProtocol, PyObjectRef, PyResult}; +use crate::pyobject::{PyObjectRef, PyResult, TryFromObject}; use crate::vm::VirtualMachine; use std::sync::atomic::{AtomicBool, Ordering}; @@ -23,51 +23,64 @@ const SIG_IGN: libc::sighandler_t = 1; #[cfg(windows)] const SIG_ERR: libc::sighandler_t = !0; -const NSIG: usize = 64; +pub const NSIG: usize = 64; // We cannot use the NSIG const in the arr macro. This will fail compilation if NSIG is different. -static mut TRIGGERS: [AtomicBool; NSIG] = arr![AtomicBool::new(false); 64]; +static TRIGGERS: [AtomicBool; NSIG] = arr![AtomicBool::new(false); 64]; extern "C" fn run_signal(signum: i32) { - unsafe { - TRIGGERS[signum as usize].store(true, Ordering::Relaxed); + TRIGGERS[signum as usize].store(true, Ordering::Relaxed); +} + +fn assert_in_range(signum: i32, vm: &VirtualMachine) -> PyResult<()> { + if (1..=NSIG as i32).contains(&signum) { + Ok(()) + } else { + Err(vm.new_value_error("signal number out of range".to_owned())) } } -fn signal( - signalnum: PyIntRef, - handler: PyObjectRef, - vm: &VirtualMachine, -) -> PyResult> { - if !vm.isinstance(&handler, &vm.ctx.function_type())? - && !vm.isinstance(&handler, &vm.ctx.bound_method_type())? - && !vm.isinstance(&handler, &vm.ctx.builtin_function_or_method_type())? - { - return Err(vm.new_type_error("Hanlder must be callable".to_string())); - } - let signal_module = vm.import("signal", &vm.ctx.new_tuple(vec![]), 0)?; - let sig_dfl = vm.get_attribute(signal_module.clone(), "SIG_DFL")?; - let sig_ign = vm.get_attribute(signal_module, "SIG_IGN")?; - let signalnum = signalnum.as_bigint().to_i32().unwrap(); - check_signals(vm); - let sig_handler = if handler.is(&sig_dfl) { - SIG_DFL - } else if handler.is(&sig_ign) { - SIG_IGN - } else { - run_signal as libc::sighandler_t +fn signal(signalnum: i32, handler: PyObjectRef, vm: &VirtualMachine) -> PyResult { + assert_in_range(signalnum, vm)?; + + let sig_handler = match usize::try_from_object(vm, handler.clone()).ok() { + Some(SIG_DFL) => SIG_DFL, + Some(SIG_IGN) => SIG_IGN, + None if vm.is_callable(&handler) => run_signal as libc::sighandler_t, + _ => { + return Err(vm.new_type_error( + "signal handler must be signal.SIG_IGN, signal.SIG_DFL, or a callable object" + .to_owned(), + )) + } }; + check_signals(vm)?; + let old = unsafe { libc::signal(signalnum, sig_handler) }; if old == SIG_ERR { return Err(vm.new_os_error("Failed to set signal".to_string())); } - let old_handler = vm.signal_handlers.borrow_mut().insert(signalnum, handler); + #[cfg(unix)] + { + extern "C" { + fn siginterrupt(sig: i32, flag: i32); + } + unsafe { + siginterrupt(signalnum, 1); + } + } + + let mut old_handler = handler; + std::mem::swap( + &mut vm.signal_handlers.borrow_mut()[signalnum as usize], + &mut old_handler, + ); Ok(old_handler) } -fn getsignal(signalnum: PyIntRef, vm: &VirtualMachine) -> PyResult> { - let signalnum = signalnum.as_bigint().to_i32().unwrap(); - Ok(vm.signal_handlers.borrow_mut().get(&signalnum).cloned()) +fn getsignal(signalnum: i32, vm: &VirtualMachine) -> PyResult { + assert_in_range(signalnum, vm)?; + Ok(vm.signal_handlers.borrow()[signalnum as usize].clone()) } #[cfg(unix)] @@ -81,50 +94,68 @@ fn alarm(time: PyIntRef, _vm: &VirtualMachine) -> u32 { prev_time.unwrap_or(0) } -#[allow(clippy::needless_range_loop)] -pub fn check_signals(vm: &VirtualMachine) { - for signum in 1..NSIG { - let triggerd = unsafe { TRIGGERS[signum].swap(false, Ordering::Relaxed) }; +pub fn check_signals(vm: &VirtualMachine) -> PyResult<()> { + for (signum, trigger) in TRIGGERS.iter().enumerate().skip(1) { + let triggerd = trigger.swap(false, Ordering::Relaxed); if triggerd { - let handler = vm - .signal_handlers - .borrow() - .get(&(signum as i32)) - .expect("Handler should be set") - .clone(); - vm.invoke(&handler, vec![vm.new_int(signum), vm.get_none()]) - .expect("Test"); + let handler = &vm.signal_handlers.borrow()[signum]; + if vm.is_callable(handler) { + vm.invoke(handler, vec![vm.new_int(signum), vm.get_none()])?; + } } } + Ok(()) } -fn stub_func(_vm: &VirtualMachine) -> PyResult { - panic!("Do not use directly"); +fn default_int_handler(_signum: PyObjectRef, _arg: PyObjectRef, vm: &VirtualMachine) -> PyResult { + Err(vm.new_empty_exception(vm.ctx.exceptions.keyboard_interrupt.clone())?) } pub fn make_module(vm: &VirtualMachine) -> PyObjectRef { let ctx = &vm.ctx; - let sig_dfl = ctx.new_rustfunc(stub_func); - let sig_ign = ctx.new_rustfunc(stub_func); + let int_handler = ctx.new_rustfunc(default_int_handler); + + let sig_dfl = ctx.new_int(SIG_DFL as u8); + let sig_ign = ctx.new_int(SIG_IGN as u8); let module = py_module!(vm, "signal", { "signal" => ctx.new_rustfunc(signal), "getsignal" => ctx.new_rustfunc(getsignal), - "SIG_DFL" => sig_dfl, - "SIG_IGN" => sig_ign, + "SIG_DFL" => sig_dfl.clone(), + "SIG_IGN" => sig_ign.clone(), "SIGABRT" => ctx.new_int(libc::SIGABRT as u8), "SIGFPE" => ctx.new_int(libc::SIGFPE as u8), "SIGILL" => ctx.new_int(libc::SIGILL as u8), "SIGINT" => ctx.new_int(libc::SIGINT as u8), "SIGSEGV" => ctx.new_int(libc::SIGSEGV as u8), "SIGTERM" => ctx.new_int(libc::SIGTERM as u8), + "default_int_handler" => int_handler.clone(), }); - extend_module_platform_specific(vm, module) + extend_module_platform_specific(vm, &module); + + for signum in 1..NSIG { + let handler = unsafe { libc::signal(signum as i32, SIG_IGN) }; + if handler != SIG_ERR { + unsafe { libc::signal(signum as i32, handler) }; + } + let py_handler = if handler == SIG_DFL { + sig_dfl.clone() + } else if handler == SIG_IGN { + sig_ign.clone() + } else { + vm.get_none() + }; + vm.signal_handlers.borrow_mut()[signum] = py_handler; + } + + signal(libc::SIGINT, int_handler, vm).expect("Failed to set sigint handler"); + + module } #[cfg(unix)] -fn extend_module_platform_specific(vm: &VirtualMachine, module: PyObjectRef) -> PyObjectRef { +fn extend_module_platform_specific(vm: &VirtualMachine, module: &PyObjectRef) { let ctx = &vm.ctx; extend_module!(vm, module, { @@ -161,11 +192,7 @@ fn extend_module_platform_specific(vm: &VirtualMachine, module: PyObjectRef) -> "SIGSTKFLT" => ctx.new_int(libc::SIGSTKFLT as u8), }); } - - module } #[cfg(not(unix))] -fn extend_module_platform_specific(_vm: &VirtualMachine, module: PyObjectRef) -> PyObjectRef { - module -} +fn extend_module_platform_specific(_vm: &VirtualMachine, _module: &PyObjectRef) {} diff --git a/vm/src/stdlib/time_module.rs b/vm/src/stdlib/time_module.rs index dc327adbd..5d7205489 100644 --- a/vm/src/stdlib/time_module.rs +++ b/vm/src/stdlib/time_module.rs @@ -3,10 +3,10 @@ /// https://docs.python.org/3/library/time.html use std::fmt; use std::ops::Range; -use std::thread; use std::time::{Duration, SystemTime, UNIX_EPOCH}; use crate::function::{OptionalArg, PyFuncArgs}; +use crate::obj::objfloat::PyFloatRef; use crate::obj::objint::PyInt; use crate::obj::objsequence::get_sequence_index; use crate::obj::objsequence::PySliceableSequence; @@ -22,14 +22,35 @@ use num_traits::cast::ToPrimitive; use chrono::naive::NaiveDateTime; use chrono::{Datelike, Timelike}; -fn time_sleep(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult { - arg_check!(vm, args, required = [(seconds, Some(vm.ctx.float_type()))]); - let seconds = objfloat::get_value(seconds); +#[cfg(unix)] +fn time_sleep(seconds: PyFloatRef, vm: &VirtualMachine) -> PyResult<()> { + // this is basically std::thread::sleep, but that catches interrupts and we don't want to + let seconds = seconds.to_f64(); + let secs = seconds.trunc() as u64; + let nsecs = (seconds.fract() * 1e9) as i64; + + let mut ts = libc::timespec { + tv_sec: std::cmp::min(libc::time_t::max_value() as u64, secs) as libc::time_t, + tv_nsec: nsecs, + }; + let res = unsafe { libc::nanosleep(&ts, &mut ts) }; + let interrupted = res == -1 && nix::errno::errno() == libc::EINTR; + + if interrupted { + crate::stdlib::signal::check_signals(vm)?; + } + + Ok(()) +} + +#[cfg(not(unix))] +fn time_sleep(seconds: PyFloatRef, vm: &VirtualMachine) -> PyResult<()> { + let seconds = seconds.to_f64(); let secs: u64 = seconds.trunc() as u64; let nanos: u32 = (seconds.fract() * 1e9) as u32; let duration = Duration::new(secs, nanos); - thread::sleep(duration); - Ok(vm.get_none()) + std::thread::sleep(duration); + Ok(()) } fn duration_to_f64(d: Duration) -> f64 { diff --git a/vm/src/vm.rs b/vm/src/vm.rs index 751b0a582..714b4f443 100644 --- a/vm/src/vm.rs +++ b/vm/src/vm.rs @@ -39,6 +39,7 @@ use crate::pyobject::{ use crate::scope::Scope; use crate::stdlib; use crate::sysmodule; +use arr_macro::arr; use num_bigint::BigInt; #[cfg(feature = "rustpython-compiler")] use rustpython_compiler::{compile, error::CompileError}; @@ -63,7 +64,8 @@ pub struct VirtualMachine { pub trace_func: RefCell, pub use_tracing: RefCell, pub settings: PySettings, - pub signal_handlers: RefCell>, + #[cfg(not(target_arch = "wasm32"))] + pub signal_handlers: RefCell<[PyObjectRef; stdlib::signal::NSIG]>, } /// Struct containing all kind of settings for the python vm. @@ -166,7 +168,10 @@ impl VirtualMachine { let import_func = RefCell::new(ctx.none()); let profile_func = RefCell::new(ctx.none()); let trace_func = RefCell::new(ctx.none()); + let vm = VirtualMachine { + #[cfg(not(target_arch = "wasm32"))] + signal_handlers: RefCell::new(arr![ctx.none(); 64]), builtins: builtins.clone(), sys_module: sysmod.clone(), stdlib_inits, @@ -180,7 +185,6 @@ impl VirtualMachine { trace_func, use_tracing: RefCell::new(false), settings, - signal_handlers: Default::default(), }; objmodule::init_module_dict( @@ -198,6 +202,10 @@ impl VirtualMachine { builtins::make_module(&vm, builtins.clone()); sysmodule::make_module(&vm, sysmod, builtins); + + #[cfg(not(target_arch = "wasm32"))] + import::import_builtin(&vm, "signal").expect("Couldn't initialize signal module"); + vm } From 6faf2637b422d246263cafa236ea70f85c1d7dc3 Mon Sep 17 00:00:00 2001 From: coolreader18 <33094578+coolreader18@users.noreply.github.com> Date: Sun, 25 Aug 2019 12:50:05 -0500 Subject: [PATCH 2/6] Move NSIG, reorganize prompt stuff --- src/main.rs | 96 +++++++++++++++++++++++------------------ vm/src/stdlib/signal.rs | 6 +-- vm/src/vm.rs | 9 ++-- 3 files changed, 62 insertions(+), 49 deletions(-) diff --git a/src/main.rs b/src/main.rs index 221e2e26c..122fad187 100644 --- a/src/main.rs +++ b/src/main.rs @@ -11,7 +11,7 @@ use rustpython_vm::{ import, obj::objstr::PyStringRef, print_exception, - pyobject::{ItemProtocol, PyResult}, + pyobject::{ItemProtocol, PyObjectRef, PyResult}, scope::Scope, util, PySettings, VirtualMachine, }; @@ -434,40 +434,32 @@ fn test_run_script() { assert!(r.is_ok()); } -fn shell_exec(vm: &VirtualMachine, source: &str, scope: Scope) -> Result<(), CompileError> { +enum ShellExecResult { + Ok, + PyErr(PyObjectRef), + Continue, +} + +fn shell_exec(vm: &VirtualMachine, source: &str, scope: Scope) -> ShellExecResult { match vm.compile(source, compile::Mode::Single, "".to_string()) { Ok(code) => { match vm.run_code_obj(code, scope.clone()) { Ok(value) => { // Save non-None values as "_" - - use rustpython_vm::pyobject::IdProtocol; - - if !value.is(&vm.get_none()) { + if !vm.is_none(&value) { let key = "_"; scope.globals.set_item(key, value, vm).unwrap(); } + ShellExecResult::Ok } - - Err(err) => { - print_exception(vm, &err); - } + Err(err) => ShellExecResult::PyErr(err), } - - Ok(()) - } - // Don't inject syntax errors for line continuation - Err( - err @ CompileError { - error: CompileErrorType::Parse(ParseErrorType::EOF), - .. - }, - ) => Err(err), - Err(err) => { - let exc = vm.new_syntax_error(&err); - print_exception(vm, &exc); - Err(err) } + Err(CompileError { + error: CompileErrorType::Parse(ParseErrorType::EOF), + .. + }) => ShellExecResult::Continue, + Err(err) => ShellExecResult::PyErr(vm.new_syntax_error(&err)), } } @@ -519,16 +511,27 @@ fn run_shell(vm: &VirtualMachine, scope: Scope) -> PyResult<()> { } else { get_prompt(vm, "ps1") }; - let prompt = prompt.as_ref().map(|s| s.as_str()).unwrap_or(""); - match repl.readline(prompt) { + let prompt = match prompt { + Some(ref s) => s.as_str(), + None => "", + }; + let result = match repl.readline(prompt) { Ok(line) => { debug!("You entered {:?}", line); - input.push_str(&line); - input.push('\n'); + repl.add_history_entry(line.trim_end()); + let stop_continuing = line.is_empty(); + + if input.is_empty() { + input = line; + } else { + input.push_str(&line); + } + input.push_str("\n"); + if continuing { - if line.is_empty() { + if stop_continuing { continuing = false; } else { continue; @@ -536,31 +539,38 @@ fn run_shell(vm: &VirtualMachine, scope: Scope) -> PyResult<()> { } match shell_exec(vm, &input, scope.clone()) { - Err(CompileError { - error: CompileErrorType::Parse(ParseErrorType::EOF), - .. - }) => { - continuing = true; - } - _ => { + ShellExecResult::Ok => { input = String::new(); + Ok(()) + } + ShellExecResult::Continue => { + continuing = true; + Ok(()) + } + ShellExecResult::PyErr(err) => { + input = String::new(); + Err(err) } } } Err(ReadlineError::Interrupted) => { - let exc = vm + continuing = false; + let keyboard_interrupt = vm .new_empty_exception(vm.ctx.exceptions.keyboard_interrupt.clone()) .unwrap(); - print_exception(vm, &exc); - continuing = false; + Err(keyboard_interrupt) } Err(ReadlineError::Eof) => { break; } Err(err) => { - println!("Error: {:?}", err); + eprintln!("Readline error: {:?}", err); break; } + }; + + if let Err(exc) = result { + print_exception(vm, &exc); } } repl.save_history(repl_history_path_str).unwrap(); @@ -586,7 +596,11 @@ fn run_shell(vm: &VirtualMachine, scope: Scope) -> PyResult<()> { for line in stdin.lock().lines() { let mut line = line.expect("line failed"); line.push('\n'); - let _ = shell_exec(vm, &line, scope.clone()); + match shell_exec(vm, &line, scope.clone()) { + ShellExecResult::Ok => {} + ShellExecResult::Continue => println!("Unexpected EOF"), + ShellExecResult::PyErr(exc) => print_exception(vm, &exc), + } print!("{}", get_prompt(vm, "ps1")); stdout.flush().expect("flush failed"); } diff --git a/vm/src/stdlib/signal.rs b/vm/src/stdlib/signal.rs index 3473252b5..129f1bd9d 100644 --- a/vm/src/stdlib/signal.rs +++ b/vm/src/stdlib/signal.rs @@ -1,6 +1,6 @@ use crate::obj::objint::PyIntRef; use crate::pyobject::{PyObjectRef, PyResult, TryFromObject}; -use crate::vm::VirtualMachine; +use crate::vm::{VirtualMachine, NSIG}; use std::sync::atomic::{AtomicBool, Ordering}; @@ -23,8 +23,6 @@ const SIG_IGN: libc::sighandler_t = 1; #[cfg(windows)] const SIG_ERR: libc::sighandler_t = !0; -pub const NSIG: usize = 64; - // We cannot use the NSIG const in the arr macro. This will fail compilation if NSIG is different. static TRIGGERS: [AtomicBool; NSIG] = arr![AtomicBool::new(false); 64]; @@ -33,7 +31,7 @@ extern "C" fn run_signal(signum: i32) { } fn assert_in_range(signum: i32, vm: &VirtualMachine) -> PyResult<()> { - if (1..=NSIG as i32).contains(&signum) { + if (1..NSIG as i32).contains(&signum) { Ok(()) } else { Err(vm.new_value_error("signal number out of range".to_owned())) diff --git a/vm/src/vm.rs b/vm/src/vm.rs index 714b4f443..560e6df38 100644 --- a/vm/src/vm.rs +++ b/vm/src/vm.rs @@ -63,11 +63,12 @@ pub struct VirtualMachine { pub profile_func: RefCell, pub trace_func: RefCell, pub use_tracing: RefCell, + pub signal_handlers: RefCell<[PyObjectRef; NSIG]>, pub settings: PySettings, - #[cfg(not(target_arch = "wasm32"))] - pub signal_handlers: RefCell<[PyObjectRef; stdlib::signal::NSIG]>, } +pub const NSIG: usize = 64; + /// Struct containing all kind of settings for the python vm. pub struct PySettings { /// -d command line switch @@ -168,10 +169,9 @@ impl VirtualMachine { let import_func = RefCell::new(ctx.none()); let profile_func = RefCell::new(ctx.none()); let trace_func = RefCell::new(ctx.none()); + let signal_handlers = RefCell::new(arr![ctx.none(); 64]); let vm = VirtualMachine { - #[cfg(not(target_arch = "wasm32"))] - signal_handlers: RefCell::new(arr![ctx.none(); 64]), builtins: builtins.clone(), sys_module: sysmod.clone(), stdlib_inits, @@ -184,6 +184,7 @@ impl VirtualMachine { profile_func, trace_func, use_tracing: RefCell::new(false), + signal_handlers, settings, }; From 86535bbfbf04bd29d48056e45add4d4e1fe20b7f Mon Sep 17 00:00:00 2001 From: coolreader18 <33094578+coolreader18@users.noreply.github.com> Date: Sun, 25 Aug 2019 13:05:25 -0500 Subject: [PATCH 3/6] Add ANY_TRIGGERED shortcut --- vm/src/stdlib/signal.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/vm/src/stdlib/signal.rs b/vm/src/stdlib/signal.rs index 129f1bd9d..b14ba4f9c 100644 --- a/vm/src/stdlib/signal.rs +++ b/vm/src/stdlib/signal.rs @@ -26,7 +26,10 @@ const SIG_ERR: libc::sighandler_t = !0; // We cannot use the NSIG const in the arr macro. This will fail compilation if NSIG is different. static TRIGGERS: [AtomicBool; NSIG] = arr![AtomicBool::new(false); 64]; +static ANY_TRIGGERED: AtomicBool = AtomicBool::new(false); + extern "C" fn run_signal(signum: i32) { + ANY_TRIGGERED.store(true, Ordering::Relaxed); TRIGGERS[signum as usize].store(true, Ordering::Relaxed); } @@ -93,6 +96,9 @@ fn alarm(time: PyIntRef, _vm: &VirtualMachine) -> u32 { } pub fn check_signals(vm: &VirtualMachine) -> PyResult<()> { + if !ANY_TRIGGERED.swap(false, Ordering::Relaxed) { + return Ok(()); + } for (signum, trigger) in TRIGGERS.iter().enumerate().skip(1) { let triggerd = trigger.swap(false, Ordering::Relaxed); if triggerd { From 0c14b9be0666f0c51de0164eb8c1465a9c513972 Mon Sep 17 00:00:00 2001 From: coolreader18 <33094578+coolreader18@users.noreply.github.com> Date: Sun, 25 Aug 2019 13:29:48 -0500 Subject: [PATCH 4/6] Add flame attribute to check_signals --- vm/src/stdlib/signal.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/vm/src/stdlib/signal.rs b/vm/src/stdlib/signal.rs index b14ba4f9c..c293849ae 100644 --- a/vm/src/stdlib/signal.rs +++ b/vm/src/stdlib/signal.rs @@ -95,6 +95,7 @@ fn alarm(time: PyIntRef, _vm: &VirtualMachine) -> u32 { prev_time.unwrap_or(0) } +#[cfg_attr(feature = "flame-it", flame)] pub fn check_signals(vm: &VirtualMachine) -> PyResult<()> { if !ANY_TRIGGERED.swap(false, Ordering::Relaxed) { return Ok(()); From 13d7d636b6a8cc3bc8d0f15efd3c85ccec9183d4 Mon Sep 17 00:00:00 2001 From: coolreader18 <33094578+coolreader18@users.noreply.github.com> Date: Sun, 25 Aug 2019 23:27:47 -0500 Subject: [PATCH 5/6] Process prompt correctly on redox --- src/main.rs | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/src/main.rs b/src/main.rs index 122fad187..4bf0abb1e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -591,8 +591,17 @@ fn run_shell(vm: &VirtualMachine, scope: Scope) -> PyResult<()> { let stdout = io::stdout(); let mut stdout = stdout.lock(); - print!("{}", get_prompt(vm, "ps1")); - stdout.flush().expect("flush failed"); + let mut print_prompt = || { + let prompt = get_prompt(vm, "ps1"); + let prompt = match prompt { + Some(ref s) => s.as_str(), + None => "", + }; + print!("{}", prompt); + stdout.flush().expect("flush failed"); + }; + + print_prompt(); for line in stdin.lock().lines() { let mut line = line.expect("line failed"); line.push('\n'); @@ -601,8 +610,7 @@ fn run_shell(vm: &VirtualMachine, scope: Scope) -> PyResult<()> { ShellExecResult::Continue => println!("Unexpected EOF"), ShellExecResult::PyErr(exc) => print_exception(vm, &exc), } - print!("{}", get_prompt(vm, "ps1")); - stdout.flush().expect("flush failed"); + print_prompt(); } Ok(()) From 5da00de7693a31678901111cbeb3810d4a69b256 Mon Sep 17 00:00:00 2001 From: Noah <33094578+coolreader18@users.noreply.github.com> Date: Mon, 26 Aug 2019 13:24:23 -0500 Subject: [PATCH 6/6] Make print_prompt() a fn --- src/main.rs | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/src/main.rs b/src/main.rs index 4bf0abb1e..889fcc2d7 100644 --- a/src/main.rs +++ b/src/main.rs @@ -583,28 +583,26 @@ fn run_shell(vm: &VirtualMachine, scope: Scope) -> PyResult<()> { use std::io::{self, BufRead, Write}; println!( - "Welcome to the magnificent Rust Python {} interpreter \u{1f631} \u{1f596}", + "Welcome to the magnificent Rust Python {} interpreter!", crate_version!() ); - let stdin = io::stdin(); - let stdout = io::stdout(); - let mut stdout = stdout.lock(); - - let mut print_prompt = || { + fn print_prompt() { let prompt = get_prompt(vm, "ps1"); let prompt = match prompt { Some(ref s) => s.as_str(), None => "", }; print!("{}", prompt); - stdout.flush().expect("flush failed"); - }; + io::stdout().lock().flush().expect("flush failed"); + } + + let stdin = io::stdin(); print_prompt(); for line in stdin.lock().lines() { let mut line = line.expect("line failed"); - line.push('\n'); + line.push_str("\n"); match shell_exec(vm, &line, scope.clone()) { ShellExecResult::Ok => {} ShellExecResult::Continue => println!("Unexpected EOF"),