-
Notifications
You must be signed in to change notification settings - Fork 1.4k
signal support #1189
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
signal support #1189
Changes from 1 commit
1b17926
5b670f8
f540d31
ca23c43
57cdae1
a7d96b7
e8001d7
c1e0799
7061f1c
a1af6b4
56b555b
785b5d8
61bf076
9470d75
48da527
f3b4b28
7cd5e89
52d204c
60b5d9d
25b9f35
3e07d61
075f2c9
23cba40
f24c6da
f600868
c5486a6
5e5d46d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
- Loading branch information
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,37 @@ | ||
| use crate::obj::objfunction::PyFunctionRef; | ||
| use crate::obj::objint::PyIntRef; | ||
| use crate::pyobject::PyObjectRef; | ||
| use crate::pyobject::PyResult; | ||
| use crate::vm::{VirtualMachine, TRIGGERS}; | ||
|
|
||
| use std::sync::atomic::Ordering; | ||
|
|
||
| use num_traits::cast::ToPrimitive; | ||
|
|
||
| use nix::sys::signal; | ||
|
|
||
| extern "C" fn run_signal(signum: i32) { | ||
| unsafe { | ||
| TRIGGERS[signum as usize].store(true, Ordering::Relaxed); | ||
| } | ||
| } | ||
|
|
||
| fn signal(signalnum: PyIntRef, handler: PyFunctionRef, vm: &VirtualMachine) -> PyResult<()> { | ||
| vm.signal_handlers.borrow_mut().insert( | ||
| signalnum.as_bigint().to_i32().unwrap(), | ||
| handler.into_object(), | ||
| ); | ||
| let handler = nix::sys::signal::SigHandler::Handler(run_signal); | ||
| let sig_action = | ||
| signal::SigAction::new(handler, signal::SaFlags::empty(), signal::SigSet::empty()); | ||
| unsafe { signal::sigaction(signal::SIGINT, &sig_action) }.unwrap(); | ||
| Ok(()) | ||
| } | ||
|
|
||
| pub fn make_module(vm: &VirtualMachine) -> PyObjectRef { | ||
| let ctx = &vm.ctx; | ||
|
|
||
| py_module!(vm, "_signal", { | ||
| "signal" => ctx.new_rustfunc(signal), | ||
| }) | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -9,6 +9,7 @@ use std::collections::hash_map::HashMap; | |
| use std::collections::hash_set::HashSet; | ||
| use std::fmt; | ||
| use std::rc::Rc; | ||
| use std::sync::atomic::{AtomicBool, Ordering}; | ||
| use std::sync::{Mutex, MutexGuard}; | ||
|
|
||
| use crate::builtins; | ||
|
|
@@ -42,6 +43,23 @@ use num_bigint::BigInt; | |
| #[cfg(feature = "rustpython-compiler")] | ||
| use rustpython_compiler::{compile, error::CompileError}; | ||
|
|
||
| // Signal triggers | ||
| // TODO: 64 | ||
| pub const NSIG: usize = 10; | ||
|
|
||
| pub static mut TRIGGERS: [AtomicBool; NSIG] = [ | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe you could use
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Did not work. I will create a procedural macro in the future to solve this duplication.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Having this variable as a static global would prevent multiple VirtualMachine instances. We can solve this, by moving the triggers struct into a RefCell. Place this RefCell into the signals.rs file. In the signals.rs file, create a global cell, with a trigger list. Each vm then can register a trigger list to. Okay, my explanation is poor. Lets see how this evolves further :). |
||
| AtomicBool::new(false), | ||
| AtomicBool::new(false), | ||
| AtomicBool::new(false), | ||
| AtomicBool::new(false), | ||
| AtomicBool::new(false), | ||
| AtomicBool::new(false), | ||
| AtomicBool::new(false), | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should this be a boolean flag, or a queue of events? Each event triggers a callback, so if we have multiple events happening in a short time, the boolean flag was already true, so it was not handled. I propose to create a queue of events per signal.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This will be different from the |
||
| AtomicBool::new(false), | ||
| AtomicBool::new(false), | ||
| AtomicBool::new(false), | ||
| ]; | ||
|
|
||
| // use objects::objects; | ||
|
|
||
| // Objects are live when they are on stack, or referenced by a name (for now) | ||
|
|
@@ -62,6 +80,7 @@ pub struct VirtualMachine { | |
| pub trace_func: RefCell<PyObjectRef>, | ||
| pub use_tracing: RefCell<bool>, | ||
| pub settings: PySettings, | ||
| pub signal_handlers: RefCell<HashMap<i32, PyObjectRef>>, | ||
| } | ||
|
|
||
| /// Struct containing all kind of settings for the python vm. | ||
|
|
@@ -160,6 +179,7 @@ impl VirtualMachine { | |
| trace_func, | ||
| use_tracing: RefCell::new(false), | ||
| settings, | ||
| signal_handlers: RefCell::new(HashMap::new()), | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You could use |
||
| }; | ||
|
|
||
| builtins::make_module(&vm, builtins.clone()); | ||
|
|
@@ -1143,6 +1163,21 @@ impl VirtualMachine { | |
| pub fn current_exception(&self) -> Option<PyObjectRef> { | ||
| self.exceptions.borrow().last().cloned() | ||
| } | ||
|
|
||
| pub fn check_signals(&self) { | ||
| for (signum, handler) in self.signal_handlers.borrow().iter() { | ||
| if *signum as usize >= NSIG { | ||
| panic!("Signum bigger then NSIG"); | ||
| } | ||
| let triggerd; | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This can just be |
||
| unsafe { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please move this unsafe code into the signal module. This function should just loop over the list of triggered events. Also, you probably want to guard this for loop with some sort of lock. Another solution would be to use the
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There is not problem that the an event will be added while I process the list. I will just process it in the next run. |
||
| triggerd = TRIGGERS[*signum as usize].swap(false, Ordering::Relaxed); | ||
| } | ||
| if triggerd { | ||
| self.invoke(handler.clone(), vec![]).expect("Test"); | ||
| } | ||
| } | ||
| } | ||
| } | ||
|
|
||
| impl Default for VirtualMachine { | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this contraption makes sense, it inserts signals nicely at a defined point of time.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you think this is a good point?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think so, we would have to wait for builtin functions to finish, but then again, we do not face threading issues.