mirror of
https://github.com/RustPython/RustPython.git
synced 2026-10-28 18:59:04 +08:00
Newtype SigalNum (#8096)
* Newtype SigalNum * impl Index<SigalNum> for SignalHandlersInner
This commit is contained in:
1 parent
c3e1f0fa37
commit
d758d60eb1
5 files changed
+210
-113
No files matched your search
Vendored
+8
@@ -93,6 +93,7 @@ class PosixTests(unittest.TestCase):
|
||||
self.assertRaises(TypeError, signal.signal,
|
||||
signal.SIGUSR1, None)
|
||||
|
||||
@unittest.expectedFailureIf(sys.platform == "android", "TODO: RUSTPYTHON; AssertionError: None is not an instance of <enum 'Handlers'>")
|
||||
def test_getsignal(self):
|
||||
hup = signal.signal(signal.SIGHUP, self.trivial_signal_handler)
|
||||
self.assertIsInstance(hup, signal.Handlers)
|
||||
@@ -101,6 +102,7 @@ class PosixTests(unittest.TestCase):
|
||||
signal.signal(signal.SIGHUP, hup)
|
||||
self.assertEqual(signal.getsignal(signal.SIGHUP), hup)
|
||||
|
||||
@unittest.expectedFailureIf(sys.platform == "android", "TODO: RUSTPYTHON")
|
||||
def test_no_repr_is_called_on_signal_handler(self):
|
||||
# See https://github.com/python/cpython/issues/112559.
|
||||
|
||||
@@ -778,6 +780,7 @@ class SiginterruptTest(unittest.TestCase):
|
||||
self.assertFalse(interrupted)
|
||||
|
||||
|
||||
@unittest.skipIf(sys.platform == "android", "TODO: RUSTPYTHON; Error during teardown")
|
||||
@unittest.skipIf(sys.platform == "win32", "Not valid on Windows")
|
||||
@unittest.skipUnless(hasattr(signal, 'getitimer') and hasattr(signal, 'setitimer'),
|
||||
"needs signal.getitimer() and signal.setitimer()")
|
||||
@@ -1264,6 +1267,7 @@ class StressTest(unittest.TestCase):
|
||||
"(> 10 ms.) on this platform (or system too busy)"
|
||||
% (reso,))
|
||||
|
||||
@unittest.skipIf(sys.platform == "android", "TODO: RUSTPYTHON; TypeError: signal handler must be signal.SIG_IGN, signal.SIG_DFL, or a callable object")
|
||||
@unittest.skipUnless(hasattr(signal, "setitimer"),
|
||||
"test needs setitimer()")
|
||||
def test_stress_delivery_dependent(self):
|
||||
@@ -1310,6 +1314,7 @@ class StressTest(unittest.TestCase):
|
||||
# Python handler
|
||||
self.assertEqual(len(sigs), N, "Some signals were lost")
|
||||
|
||||
@unittest.skipIf(sys.platform == "android", "TODO: RUSTPYTHON; TypeError: signal handler must be signal.SIG_IGN, signal.SIG_DFL, or a callable object")
|
||||
@unittest.skipUnless(hasattr(signal, "setitimer"),
|
||||
"test needs setitimer()")
|
||||
def test_stress_delivery_simultaneous(self):
|
||||
@@ -1409,6 +1414,7 @@ class StressTest(unittest.TestCase):
|
||||
|
||||
class RaiseSignalTest(unittest.TestCase):
|
||||
|
||||
@unittest.expectedFailureIf(sys.platform == "android", "TODO: RUSTPYTHON; AssertionError: KeyboardInterrupt not raised")
|
||||
def test_sigint(self):
|
||||
with self.assertRaises(KeyboardInterrupt):
|
||||
signal.raise_signal(signal.SIGINT)
|
||||
@@ -1425,6 +1431,7 @@ class RaiseSignalTest(unittest.TestCase):
|
||||
else:
|
||||
raise
|
||||
|
||||
@unittest.skipIf(sys.platform == "android", "TODO: RUSTPYTHON; TypeError: signal handler must be signal.SIG_IGN, signal.SIG_DFL, or a callable object")
|
||||
def test_handler(self):
|
||||
is_ok = False
|
||||
def handler(a, b):
|
||||
@@ -1455,6 +1462,7 @@ class RaiseSignalTest(unittest.TestCase):
|
||||
|
||||
class PidfdSignalTest(unittest.TestCase):
|
||||
|
||||
@unittest.expectedFailureIf(sys.platform == "android", "TODO: RUSTPYTHON; AssertionError: KeyboardInterrupt not raised")
|
||||
@unittest.skipUnless(
|
||||
hasattr(signal, "pidfd_send_signal"),
|
||||
"pidfd support not built in",
|
||||
|
||||
@@ -55,10 +55,10 @@ mod ffi {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(unix, windows))]
|
||||
/// # Safety
|
||||
///
|
||||
/// The caller must ensure `signalnum` is a valid platform signal number.
|
||||
#[cfg(any(unix, windows))]
|
||||
pub unsafe fn probe_handler(signalnum: i32) -> Option<sighandler_t> {
|
||||
let handler = unsafe { libc::signal(signalnum, libc::SIG_IGN) };
|
||||
if handler == libc::SIG_ERR as sighandler_t {
|
||||
@@ -69,11 +69,11 @@ pub unsafe fn probe_handler(signalnum: i32) -> Option<sighandler_t> {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(unix, windows))]
|
||||
/// # Safety
|
||||
///
|
||||
/// The caller must ensure `signalnum` is a valid platform signal number and
|
||||
/// `handler` is accepted by the platform signal ABI.
|
||||
#[cfg(any(unix, windows))]
|
||||
pub unsafe fn install_handler(signalnum: i32, handler: sighandler_t) -> io::Result<sighandler_t> {
|
||||
let old = unsafe { libc::signal(signalnum, handler) };
|
||||
if old == libc::SIG_ERR as sighandler_t {
|
||||
@@ -158,7 +158,7 @@ pub fn pthread_sigmask(how: i32, set: &libc::sigset_t) -> io::Result<libc::sigse
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
#[cfg(any(target_os = "android", target_os = "linux"))]
|
||||
pub fn pidfd_send_signal(pidfd: i32, sig: i32, flags: u32) -> io::Result<()> {
|
||||
let ret = unsafe {
|
||||
libc::syscall(
|
||||
@@ -199,11 +199,6 @@ pub const CTRL_BREAK_EVENT: u32 = 1;
|
||||
#[cfg(windows)]
|
||||
pub const INVALID_SOCKET: libc::SOCKET = windows_sys::Win32::Networking::WinSock::INVALID_SOCKET;
|
||||
|
||||
#[cfg(windows)]
|
||||
pub fn is_valid_signal(signalnum: i32) -> bool {
|
||||
VALID_SIGNALS.contains(&signalnum)
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
fn init_winsock() {
|
||||
static WSA_INIT: Once = Once::new();
|
||||
|
||||
+118
-19
@@ -1,8 +1,7 @@
|
||||
use crate::{PyObjectRef, PyResult, VirtualMachine};
|
||||
use core::{
|
||||
cell::{Cell, RefCell},
|
||||
fmt,
|
||||
ops::{Deref, DerefMut},
|
||||
ops::{Deref, DerefMut, Index, IndexMut, Range},
|
||||
sync::atomic::{AtomicBool, Ordering},
|
||||
};
|
||||
use std::sync::mpsc;
|
||||
@@ -10,10 +9,12 @@ use std::sync::mpsc;
|
||||
#[cfg(windows)]
|
||||
use core::sync::atomic::AtomicIsize;
|
||||
|
||||
static ANY_TRIGGERED: AtomicBool = AtomicBool::new(false);
|
||||
use crate::{PyObjectRef, PyResult, TryFromBorrowedObject, TryFromObject, VirtualMachine};
|
||||
|
||||
pub(crate) const NSIG: usize = 64;
|
||||
|
||||
static ANY_TRIGGERED: AtomicBool = AtomicBool::new(false);
|
||||
|
||||
#[expect(
|
||||
clippy::declare_interior_mutable_const,
|
||||
reason = "workaround for const array repeat limitation (rust issue #79270)"
|
||||
@@ -70,22 +71,32 @@ fn trigger_signals(vm: &VirtualMachine) -> PyResult<()> {
|
||||
}
|
||||
let _guard = SignalHandlerGuard;
|
||||
|
||||
// unwrap should never fail since we check above
|
||||
let signal_handlers = vm.signal_handlers.get().unwrap().borrow();
|
||||
let signal_handlers = vm
|
||||
.signal_handlers
|
||||
.get()
|
||||
.expect("should never fail since we check above")
|
||||
.borrow();
|
||||
|
||||
for (signum, trigger) in TRIGGERS.iter().enumerate().skip(1) {
|
||||
let triggered = trigger.swap(false, Ordering::Relaxed);
|
||||
|
||||
// SAFETY: TRIGGERS has the same length as the signal_handlers
|
||||
let signum = unsafe { SignalNum::new_unchecked(signum as i32) };
|
||||
|
||||
if triggered
|
||||
&& let Some(handler) = &signal_handlers[signum]
|
||||
&& let Some(callable) = handler.to_callable()
|
||||
{
|
||||
callable.invoke((signum, vm.ctx.none()), vm)?;
|
||||
callable.invoke((signum.as_i32(), vm.ctx.none()), vm)?;
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(signal_rx) = &vm.signal_rx {
|
||||
for f in signal_rx.rx.try_iter() {
|
||||
f(vm)?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -109,28 +120,94 @@ pub(crate) fn clear_after_fork() {
|
||||
}
|
||||
}
|
||||
|
||||
pub 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"))
|
||||
/// A valid signal number.
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq, PartialOrd, Ord)]
|
||||
pub struct SignalNum(i32);
|
||||
|
||||
impl SignalNum {
|
||||
pub(crate) const VALID_RANGE: Range<i32> = 1..NSIG as i32;
|
||||
|
||||
/// Alias for:
|
||||
/// ```rust
|
||||
/// # use rustpython_vm::signal::SignalNum;
|
||||
///
|
||||
/// unsafe { SignalNum::new_unchecked(libc::SIGINT) };
|
||||
/// ```
|
||||
#[cfg(any(unix, windows))]
|
||||
#[allow(dead_code, reason = "Not used on all platforms")]
|
||||
pub(crate) const SIGINT: Self = Self(libc::SIGINT);
|
||||
|
||||
/// Construct [`Self`] without any validation on the signalnum value.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// Caller's responsibility to ensure the signal num is valid.
|
||||
#[must_use]
|
||||
pub const unsafe fn new_unchecked(value: i32) -> Self {
|
||||
Self(value)
|
||||
}
|
||||
|
||||
/// Get the self as an [`i32`].
|
||||
#[must_use]
|
||||
pub const fn as_i32(&self) -> i32 {
|
||||
self.0
|
||||
}
|
||||
|
||||
/// Get the self as an [`usize`].
|
||||
#[must_use]
|
||||
pub const fn as_usize(&self) -> usize {
|
||||
self.0 as usize
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for SignalNum {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
fmt::Display::fmt(&self.0, f)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<SignalNum> for i32 {
|
||||
fn from(signalnum: SignalNum) -> Self {
|
||||
signalnum.as_i32()
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<i32> for SignalNum {
|
||||
type Error = String;
|
||||
|
||||
fn try_from(value: i32) -> Result<Self, Self::Error> {
|
||||
let bounds = cfg_select! {
|
||||
all(windows, feature = "host_env") => rustpython_host_env::signal::VALID_SIGNALS,
|
||||
_ => Self::VALID_RANGE,
|
||||
};
|
||||
|
||||
if bounds.contains(&value) {
|
||||
Ok(Self(value))
|
||||
} else {
|
||||
Err("signal number out of range".into())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFromObject for SignalNum {
|
||||
fn try_from_object(vm: &VirtualMachine, obj: PyObjectRef) -> PyResult<Self> {
|
||||
Self::try_from(i32::try_from_borrowed_object(vm, &obj)?)
|
||||
.map_err(|msg| vm.new_value_error(msg))
|
||||
}
|
||||
}
|
||||
|
||||
/// Similar to `PyErr_SetInterruptEx` in CPython
|
||||
///
|
||||
/// Missing signal handler for the given signal number is silently ignored.
|
||||
#[allow(dead_code)]
|
||||
#[cfg(all(not(target_arch = "wasm32"), feature = "host_env"))]
|
||||
pub fn set_interrupt_ex(signum: i32, vm: &VirtualMachine) -> PyResult<()> {
|
||||
pub fn set_interrupt_ex(signum: SignalNum) -> PyResult<()> {
|
||||
use crate::stdlib::_signal::_signal::{SIG_DFL, SIG_IGN, run_signal};
|
||||
assert_in_range(signum, vm)?;
|
||||
|
||||
match signum as usize {
|
||||
match signum.as_usize() {
|
||||
SIG_DFL | SIG_IGN => Ok(()),
|
||||
_ => {
|
||||
// interrupt the main thread with given signal number
|
||||
run_signal(signum);
|
||||
run_signal(signum.into());
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -190,16 +267,38 @@ pub fn get_sigint_event() -> Option<isize> {
|
||||
if handle == 0 { None } else { Some(handle) }
|
||||
}
|
||||
|
||||
pub struct SignalHandlers(Box<RefCell<[Option<PyObjectRef>; NSIG]>>);
|
||||
pub struct SignalHandlersInner([Option<PyObjectRef>; NSIG]);
|
||||
|
||||
impl Default for SignalHandlersInner {
|
||||
fn default() -> Self {
|
||||
Self([const { None }; NSIG])
|
||||
}
|
||||
}
|
||||
|
||||
impl Index<SignalNum> for SignalHandlersInner {
|
||||
type Output = Option<PyObjectRef>;
|
||||
|
||||
fn index(&self, index: SignalNum) -> &Self::Output {
|
||||
&self.0[index.as_usize()]
|
||||
}
|
||||
}
|
||||
|
||||
impl IndexMut<SignalNum> for SignalHandlersInner {
|
||||
fn index_mut(&mut self, index: SignalNum) -> &mut Self::Output {
|
||||
&mut self.0[index.as_usize()]
|
||||
}
|
||||
}
|
||||
|
||||
pub struct SignalHandlers(Box<RefCell<SignalHandlersInner>>);
|
||||
|
||||
impl Default for SignalHandlers {
|
||||
fn default() -> Self {
|
||||
Self(Box::new(const { RefCell::new([const { None }; NSIG]) }))
|
||||
Self(Box::new(RefCell::new(SignalHandlersInner::default())))
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for SignalHandlers {
|
||||
type Target = Box<RefCell<[Option<PyObjectRef>; NSIG]>>;
|
||||
type Target = Box<RefCell<SignalHandlersInner>>;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.0
|
||||
|
||||
@@ -8,12 +8,9 @@ pub(crate) mod _signal {
|
||||
|
||||
use crate::{
|
||||
Py, PyObjectRef, PyResult, VirtualMachine,
|
||||
signal::{self, SignalHandlers},
|
||||
};
|
||||
use core::{
|
||||
ops::Range,
|
||||
sync::atomic::{self, Ordering},
|
||||
signal::{self, SignalHandlers, SignalNum},
|
||||
};
|
||||
use core::sync::atomic::{self, Ordering};
|
||||
|
||||
cfg_select! {
|
||||
any(unix, windows) => {
|
||||
@@ -42,8 +39,6 @@ pub(crate) mod _signal {
|
||||
_ => usize,
|
||||
};
|
||||
|
||||
const SIGNUM_RANGE: Range<i32> = 1..signal::NSIG as i32;
|
||||
|
||||
cfg_select! {
|
||||
windows => {
|
||||
type WakeupFdRaw = libc::SOCKET;
|
||||
@@ -94,9 +89,11 @@ pub(crate) mod _signal {
|
||||
#[cfg(not(unix))]
|
||||
#[pyattr]
|
||||
pub const SIG_DFL: sighandler_t = 0;
|
||||
|
||||
#[cfg(not(unix))]
|
||||
#[pyattr]
|
||||
pub const SIG_IGN: sighandler_t = 1;
|
||||
|
||||
#[cfg(not(unix))]
|
||||
#[allow(dead_code)]
|
||||
pub const SIG_ERR: sighandler_t = -1 as _;
|
||||
@@ -168,11 +165,12 @@ pub(crate) mod _signal {
|
||||
|
||||
#[cfg(unix)]
|
||||
fn new_itimer_error(msg: &str, vm: &VirtualMachine) -> PyBaseExceptionRef {
|
||||
vm.new_exception_msg(itimer_error(vm), msg.into())
|
||||
vm.new_os_subtype_error(itimer_error(vm), None, msg)
|
||||
.upcast()
|
||||
}
|
||||
|
||||
const _: () = assert!(SIGNUM_RANGE.start.is_positive());
|
||||
const _: () = assert!(SIGNUM_RANGE.end.is_positive());
|
||||
const _: () = assert!(SignalNum::VALID_RANGE.start.is_positive());
|
||||
const _: () = assert!(SignalNum::VALID_RANGE.end.is_positive());
|
||||
|
||||
#[cfg(any(unix, windows))]
|
||||
pub(super) fn init_signal_handlers(
|
||||
@@ -183,7 +181,7 @@ pub(crate) mod _signal {
|
||||
let sig_dfl = vm.new_pyobj(SIG_DFL as u8);
|
||||
let sig_ign = vm.new_pyobj(SIG_IGN as u8);
|
||||
|
||||
for signum in SIGNUM_RANGE {
|
||||
for signum in SignalNum::VALID_RANGE {
|
||||
let Some(handler) = (unsafe { host_signal::probe_handler(signum) }) else {
|
||||
continue;
|
||||
};
|
||||
@@ -195,15 +193,19 @@ pub(crate) mod _signal {
|
||||
None
|
||||
};
|
||||
|
||||
// SAFETY: Trust `SignalNum::VALID_RANGE`
|
||||
let signum = unsafe { SignalNum::new_unchecked(signum) };
|
||||
|
||||
vm.signal_handlers
|
||||
.get_or_init(SignalHandlers::default)
|
||||
.borrow_mut()[signum as usize] = py_handler;
|
||||
.borrow_mut()[signum] = py_handler;
|
||||
}
|
||||
|
||||
let int_handler = module
|
||||
.get_attr("default_int_handler", vm)
|
||||
.expect("_signal does not have this attr?");
|
||||
signal(libc::SIGINT, int_handler, vm).expect("Failed to set sigint handler");
|
||||
|
||||
signal(SignalNum::SIGINT, int_handler, vm).expect("Failed to set sigint handler");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -220,49 +222,44 @@ pub(crate) mod _signal {
|
||||
#[cfg(any(unix, windows))]
|
||||
#[pyfunction]
|
||||
pub fn signal(
|
||||
signalnum: i32,
|
||||
signalnum: SignalNum,
|
||||
handler: PyObjectRef,
|
||||
vm: &VirtualMachine,
|
||||
) -> PyResult<Option<PyObjectRef>> {
|
||||
signal::assert_in_range(signalnum, vm)?;
|
||||
|
||||
#[cfg(windows)]
|
||||
if !host_signal::is_valid_signal(signalnum) {
|
||||
return Err(vm.new_value_error(format!("signal number {signalnum} out of range")));
|
||||
}
|
||||
|
||||
if !vm.is_main_thread() {
|
||||
return Err(vm.new_value_error("signal only works in main thread"));
|
||||
return Err(
|
||||
vm.new_value_error("signal only works in main thread of the main interpreter")
|
||||
);
|
||||
}
|
||||
|
||||
let sig_handler =
|
||||
match usize::try_from_borrowed_object(vm, &handler).ok() {
|
||||
Some(SIG_DFL) => SIG_DFL,
|
||||
Some(SIG_IGN) => SIG_IGN,
|
||||
None if handler.is_callable() => run_signal as *const () as sighandler_t,
|
||||
_ => return Err(vm.new_type_error(
|
||||
"signal handler must be signal.SIG_IGN, signal.SIG_DFL, or a callable object",
|
||||
)),
|
||||
};
|
||||
let sig_handler = if handler.is_callable() {
|
||||
run_signal as *const () as sighandler_t
|
||||
} else {
|
||||
const MSG: &str =
|
||||
"signal handler must be signal.SIG_IGN, signal.SIG_DFL, or a callable object";
|
||||
|
||||
usize::try_from_borrowed_object(vm, &handler)
|
||||
.ok()
|
||||
.filter(|&v| matches!(v, SIG_DFL | SIG_IGN))
|
||||
.ok_or_else(|| vm.new_type_error(MSG))?
|
||||
};
|
||||
|
||||
signal::check_signals(vm)?;
|
||||
|
||||
unsafe { host_signal::install_handler(signalnum, sig_handler) }
|
||||
unsafe { host_signal::install_handler(signalnum.into(), sig_handler) }
|
||||
.map_err(|_| vm.new_os_error("Failed to set signal"))?;
|
||||
|
||||
let signal_handlers = vm.signal_handlers.get_or_init(SignalHandlers::default);
|
||||
let old_handler = signal_handlers.borrow_mut()[signalnum as usize].replace(handler);
|
||||
let old_handler = signal_handlers.borrow_mut()[signalnum].replace(handler);
|
||||
Ok(old_handler)
|
||||
}
|
||||
|
||||
#[pyfunction]
|
||||
fn getsignal(signalnum: i32, vm: &VirtualMachine) -> PyResult {
|
||||
signal::assert_in_range(signalnum, vm)?;
|
||||
fn getsignal(signalnum: SignalNum, vm: &VirtualMachine) -> PyObjectRef {
|
||||
let signal_handlers = vm.signal_handlers.get_or_init(SignalHandlers::default);
|
||||
let handler = signal_handlers.borrow()[signalnum as usize]
|
||||
signal_handlers.borrow()[signalnum]
|
||||
.clone()
|
||||
.unwrap_or_else(|| vm.ctx.none());
|
||||
Ok(handler)
|
||||
.unwrap_or_else(|| vm.ctx.none())
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
@@ -274,7 +271,7 @@ pub(crate) mod _signal {
|
||||
#[cfg(unix)]
|
||||
#[pyfunction]
|
||||
fn pause(vm: &VirtualMachine) -> PyResult<()> {
|
||||
host_signal::pause();
|
||||
vm.allow_threads(host_signal::pause);
|
||||
signal::check_signals(vm)?;
|
||||
Ok(())
|
||||
}
|
||||
@@ -332,7 +329,9 @@ pub(crate) mod _signal {
|
||||
};
|
||||
|
||||
if !vm.is_main_thread() {
|
||||
return Err(vm.new_value_error("set_wakeup_fd only works in main thread"));
|
||||
return Err(vm.new_value_error(
|
||||
"set_wakeup_fd only works in main thread of the main interpreter",
|
||||
));
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
@@ -371,16 +370,15 @@ pub(crate) mod _signal {
|
||||
Ok(old_fd as i64)
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
#[cfg(any(target_os = "android", target_os = "linux"))]
|
||||
#[pyfunction]
|
||||
fn pidfd_send_signal(
|
||||
pidfd: i32,
|
||||
sig: i32,
|
||||
sig: SignalNum,
|
||||
siginfo: OptionalArg<PyObjectRef>,
|
||||
flags: OptionalArg<u32>,
|
||||
vm: &VirtualMachine,
|
||||
) -> PyResult<()> {
|
||||
signal::assert_in_range(sig, vm)?;
|
||||
if let OptionalArg::Present(obj) = siginfo
|
||||
&& !vm.is_none(&obj)
|
||||
{
|
||||
@@ -388,33 +386,33 @@ pub(crate) mod _signal {
|
||||
}
|
||||
|
||||
let flags = flags.unwrap_or(0);
|
||||
host_signal::pidfd_send_signal(pidfd, sig, flags).map_err(|_| vm.new_last_errno_error())
|
||||
host_signal::pidfd_send_signal(pidfd, sig.into(), flags)
|
||||
.map_err(|_| vm.new_last_errno_error())
|
||||
}
|
||||
|
||||
#[cfg(all(unix, not(target_os = "redox")))]
|
||||
#[pyfunction(name = "siginterrupt")]
|
||||
fn py_siginterrupt(signum: i32, flag: i32, vm: &VirtualMachine) -> PyResult<()> {
|
||||
signal::assert_in_range(signum, vm)?;
|
||||
host_signal::siginterrupt(signum, flag).map_err(|_| vm.new_last_errno_error())
|
||||
fn py_siginterrupt(signum: SignalNum, flag: i32, vm: &VirtualMachine) -> PyResult<()> {
|
||||
host_signal::siginterrupt(signum.into(), flag).map_err(|_| vm.new_last_errno_error())
|
||||
}
|
||||
|
||||
#[cfg(any(unix, windows))]
|
||||
#[pyfunction]
|
||||
fn raise_signal(signalnum: i32, vm: &VirtualMachine) -> PyResult<()> {
|
||||
signal::assert_in_range(signalnum, vm)?;
|
||||
let signalnum = SignalNum::try_from(signalnum).map_err(cfg_select! {
|
||||
windows => {
|
||||
|_| vm.new_errno_error(libc::EINVAL, "Invalid argument").upcast()
|
||||
},
|
||||
_ => {
|
||||
|msg| vm.new_value_error(msg)
|
||||
}
|
||||
})?;
|
||||
|
||||
// On Windows, only certain signals are supported
|
||||
#[cfg(windows)]
|
||||
if !host_signal::is_valid_signal(signalnum) {
|
||||
return Err(vm
|
||||
.new_errno_error(libc::EINVAL, "Invalid argument")
|
||||
.upcast());
|
||||
}
|
||||
|
||||
host_signal::raise_signal(signalnum)
|
||||
vm.allow_threads(|| host_signal::raise_signal(signalnum.into()))
|
||||
.map_err(|_| vm.new_os_error(format!("raise_signal failed for signal {signalnum}")))?;
|
||||
|
||||
// Check if a signal was triggered and handle it
|
||||
|
||||
signal::check_signals(vm)?;
|
||||
|
||||
Ok(())
|
||||
@@ -422,12 +420,8 @@ pub(crate) mod _signal {
|
||||
|
||||
#[cfg(any(unix, windows))]
|
||||
#[pyfunction]
|
||||
fn strsignal(signalnum: i32, vm: &VirtualMachine) -> PyResult<Option<String>> {
|
||||
if !SIGNUM_RANGE.contains(&signalnum) {
|
||||
return Err(vm.new_value_error(format!("signal number {signalnum} out of range")));
|
||||
}
|
||||
|
||||
Ok(host_signal::strsignal(signalnum))
|
||||
fn strsignal(signalnum: SignalNum) -> Option<String> {
|
||||
host_signal::strsignal(signalnum.into())
|
||||
}
|
||||
|
||||
#[pyfunction]
|
||||
@@ -452,7 +446,7 @@ pub(crate) mod _signal {
|
||||
use crate::PyPayload;
|
||||
use crate::builtins::PySet;
|
||||
let set = PySet::default().into_ref(&vm.ctx);
|
||||
for signum in SIGNUM_RANGE {
|
||||
for signum in SignalNum::VALID_RANGE {
|
||||
if host_signal::sigset_contains(mask, signum) {
|
||||
set.add(vm.ctx.new_int(signum).into(), vm)?;
|
||||
}
|
||||
@@ -467,8 +461,6 @@ pub(crate) mod _signal {
|
||||
mask: crate::function::ArgIterable,
|
||||
vm: &VirtualMachine,
|
||||
) -> PyResult {
|
||||
use crate::convert::IntoPyException;
|
||||
|
||||
// Initialize sigset
|
||||
let mut sigset = host_signal::sigemptyset().map_err(|e| e.into_pyexception(vm))?;
|
||||
|
||||
@@ -481,11 +473,11 @@ pub(crate) mod _signal {
|
||||
let signum = sig
|
||||
.try_to_value::<i32>(vm)
|
||||
.ok()
|
||||
.filter(|v| SIGNUM_RANGE.contains(v))
|
||||
.filter(|v| SignalNum::VALID_RANGE.contains(v))
|
||||
.ok_or_else(|| {
|
||||
vm.new_value_error(format!(
|
||||
"signal number out of range [1, {}]",
|
||||
SIGNUM_RANGE.end - 1
|
||||
SignalNum::VALID_RANGE.end - 1
|
||||
))
|
||||
})?;
|
||||
|
||||
|
||||
@@ -13,6 +13,11 @@ pub(crate) use _thread::{
|
||||
|
||||
#[pymodule]
|
||||
pub(crate) mod _thread {
|
||||
use parking_lot::{
|
||||
RawMutex, RawThreadId,
|
||||
lock_api::{RawMutex as RawMutexT, RawMutexTimed, RawReentrantMutex},
|
||||
};
|
||||
|
||||
use crate::{
|
||||
AsObject, Py, PyPayload, PyRef, PyResult, VirtualMachine,
|
||||
builtins::{PyDictRef, PyIntRef, PyStr, PyTupleRef, PyType, PyTypeRef, PyUtf8StrRef},
|
||||
@@ -21,19 +26,17 @@ pub(crate) mod _thread {
|
||||
function::{ArgCallable, FuncArgs, KwArgs, OptionalArg, PySetterValue, TimeoutSeconds},
|
||||
types::{Constructor, GetAttr, Representable, SetAttr},
|
||||
};
|
||||
use alloc::{
|
||||
fmt,
|
||||
sync::{Arc, Weak},
|
||||
};
|
||||
use core::{cell::RefCell, time::Duration};
|
||||
use parking_lot::{
|
||||
RawMutex, RawThreadId,
|
||||
lock_api::{RawMutex as RawMutexT, RawMutexTimed, RawReentrantMutex},
|
||||
};
|
||||
|
||||
use alloc::sync::{Arc, Weak};
|
||||
use core::{cell::RefCell, fmt, time::Duration};
|
||||
use std::thread;
|
||||
|
||||
use rustpython_common::str::levenshtein::{MOVE_COST, levenshtein_distance};
|
||||
#[cfg(any(unix, windows))]
|
||||
use rustpython_host_env::thread as host_thread;
|
||||
use std::thread;
|
||||
|
||||
#[cfg(all(not(target_arch = "wasm32"), feature = "host_env"))]
|
||||
use crate::signal::SignalNum;
|
||||
|
||||
// PYTHREAD_NAME: show current thread name
|
||||
pub(crate) const PYTHREAD_NAME: Option<&str> = cfg_select! {
|
||||
@@ -43,12 +46,11 @@ pub(crate) mod _thread {
|
||||
_ => None,
|
||||
};
|
||||
|
||||
// TIMEOUT_MAX_IN_MICROSECONDS is a value in microseconds
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
const TIMEOUT_MAX_IN_MICROSECONDS: i64 = i64::MAX / 1_000;
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
const TIMEOUT_MAX_IN_MICROSECONDS: i64 = 0xffffffff * 1_000;
|
||||
const TIMEOUT_MAX_IN_MICROSECONDS: i64 = if cfg!(target_os = "windows") {
|
||||
0xffffffff * 1_000
|
||||
} else {
|
||||
i64::MAX / 1_000
|
||||
};
|
||||
|
||||
/// [CPython `SYSTEM_PAGE_SIZE`](https://github.com/python/cpython/blob/v3.14.5/Include/internal/pycore_obmalloc.h#L170)
|
||||
const SYSTEM_PAGE_SIZE: usize = 4 * 1024;
|
||||
@@ -614,8 +616,9 @@ pub(crate) mod _thread {
|
||||
|
||||
#[cfg(all(not(target_arch = "wasm32"), feature = "host_env"))]
|
||||
#[pyfunction]
|
||||
fn interrupt_main(signum: OptionalArg<i32>, vm: &VirtualMachine) -> PyResult<()> {
|
||||
crate::signal::set_interrupt_ex(signum.unwrap_or(libc::SIGINT), vm)
|
||||
fn interrupt_main(signum: OptionalArg<SignalNum>) -> PyResult<()> {
|
||||
let sig = signum.unwrap_or(SignalNum::SIGINT);
|
||||
crate::signal::set_interrupt_ex(sig)
|
||||
}
|
||||
|
||||
#[pyfunction]
|
||||
|
||||
Reference in new issue
Block a user