Skip to content

Commit dc00419

Browse files
committed
signal timer
1 parent ae63092 commit dc00419

File tree

2 files changed

+89
-11
lines changed

2 files changed

+89
-11
lines changed

Lib/test/test_signal.py

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -826,8 +826,6 @@ def sig_prof(self, *args):
826826
self.hndl_called = True
827827
signal.setitimer(signal.ITIMER_PROF, 0)
828828

829-
# TODO: RUSTPYTHON
830-
@unittest.expectedFailure
831829
def test_itimer_exc(self):
832830
# XXX I'm assuming -1 is an invalid itimer, but maybe some platform
833831
# defines it ?
@@ -837,16 +835,12 @@ def test_itimer_exc(self):
837835
self.assertRaises(signal.ItimerError,
838836
signal.setitimer, signal.ITIMER_REAL, -1)
839837

840-
# TODO: RUSTPYTHON
841-
@unittest.expectedFailure
842838
def test_itimer_real(self):
843839
self.itimer = signal.ITIMER_REAL
844840
signal.setitimer(self.itimer, 1.0)
845841
signal.pause()
846842
self.assertEqual(self.hndl_called, True)
847843

848-
# TODO: RUSTPYTHON
849-
@unittest.expectedFailure
850844
# Issue 3864, unknown if this affects earlier versions of freebsd also
851845
@unittest.skipIf(sys.platform in ('netbsd5',),
852846
'itimer not reliable (does not mix well with threading) on some BSDs.')
@@ -867,8 +861,6 @@ def test_itimer_virtual(self):
867861
# and the handler should have been called
868862
self.assertEqual(self.hndl_called, True)
869863

870-
# TODO: RUSTPYTHON
871-
@unittest.expectedFailure
872864
def test_itimer_prof(self):
873865
self.itimer = signal.ITIMER_PROF
874866
signal.signal(signal.SIGPROF, self.sig_prof)
@@ -886,8 +878,6 @@ def test_itimer_prof(self):
886878
# and the handler should have been called
887879
self.assertEqual(self.hndl_called, True)
888880

889-
# TODO: RUSTPYTHON
890-
@unittest.expectedFailure
891881
def test_setitimer_tiny(self):
892882
# bpo-30807: C setitimer() takes a microsecond-resolution interval.
893883
# Check that float -> timeval conversion doesn't round

crates/vm/src/stdlib/signal.rs

Lines changed: 89 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,12 @@ pub(crate) mod _signal {
1818
Py,
1919
convert::{IntoPyException, TryFromBorrowedObject},
2020
};
21-
use crate::{PyObjectRef, PyResult, VirtualMachine, signal};
21+
use crate::{
22+
PyObjectRef, PyResult, VirtualMachine,
23+
builtins::PyTypeRef,
24+
function::{ArgIntoFloat, OptionalArg},
25+
signal,
26+
};
2227
use std::sync::atomic::{self, Ordering};
2328

2429
#[cfg(any(unix, windows))]
@@ -114,6 +119,21 @@ pub(crate) mod _signal {
114119
#[pyattr]
115120
use libc::{SIGPWR, SIGSTKFLT};
116121

122+
// Interval timer constants
123+
#[cfg(unix)]
124+
#[pyattr]
125+
use libc::{ITIMER_PROF, ITIMER_REAL, ITIMER_VIRTUAL};
126+
127+
#[cfg(unix)]
128+
#[pyattr(name = "ItimerError", once)]
129+
fn itimer_error(vm: &VirtualMachine) -> PyTypeRef {
130+
vm.ctx.new_exception_type(
131+
"signal",
132+
"ItimerError",
133+
Some(vec![vm.ctx.exceptions.os_error.to_owned()]),
134+
)
135+
}
136+
117137
#[cfg(any(unix, windows))]
118138
pub(super) fn init_signal_handlers(
119139
module: &Py<crate::builtins::PyModule>,
@@ -216,6 +236,74 @@ pub(crate) mod _signal {
216236
prev_time.unwrap_or(0)
217237
}
218238

239+
#[cfg(unix)]
240+
#[pyfunction]
241+
fn pause(vm: &VirtualMachine) -> PyResult<()> {
242+
unsafe { libc::pause() };
243+
signal::check_signals(vm)?;
244+
Ok(())
245+
}
246+
247+
#[cfg(unix)]
248+
fn timeval_to_double(tv: &libc::timeval) -> f64 {
249+
tv.tv_sec as f64 + (tv.tv_usec as f64 / 1_000_000.0)
250+
}
251+
252+
#[cfg(unix)]
253+
fn double_to_timeval(val: f64) -> libc::timeval {
254+
libc::timeval {
255+
tv_sec: val.trunc() as _,
256+
tv_usec: ((val.fract()) * 1_000_000.0) as _,
257+
}
258+
}
259+
260+
#[cfg(unix)]
261+
fn itimerval_to_tuple(it: &libc::itimerval) -> (f64, f64) {
262+
(
263+
timeval_to_double(&it.it_value),
264+
timeval_to_double(&it.it_interval),
265+
)
266+
}
267+
268+
#[cfg(unix)]
269+
#[pyfunction]
270+
fn setitimer(
271+
which: i32,
272+
seconds: ArgIntoFloat,
273+
interval: OptionalArg<ArgIntoFloat>,
274+
vm: &VirtualMachine,
275+
) -> PyResult<(f64, f64)> {
276+
let seconds: f64 = seconds.into();
277+
let interval: f64 = interval.map(|v| v.into()).unwrap_or(0.0);
278+
let new = libc::itimerval {
279+
it_value: double_to_timeval(seconds),
280+
it_interval: double_to_timeval(interval),
281+
};
282+
let mut old = std::mem::MaybeUninit::<libc::itimerval>::uninit();
283+
let ret = unsafe { libc::setitimer(which, &new, old.as_mut_ptr()) };
284+
if ret != 0 {
285+
let err = std::io::Error::last_os_error();
286+
let itimer_error = itimer_error(vm);
287+
return Err(vm.new_exception_msg(itimer_error, err.to_string()));
288+
}
289+
let old = unsafe { old.assume_init() };
290+
Ok(itimerval_to_tuple(&old))
291+
}
292+
293+
#[cfg(unix)]
294+
#[pyfunction]
295+
fn getitimer(which: i32, vm: &VirtualMachine) -> PyResult<(f64, f64)> {
296+
let mut old = std::mem::MaybeUninit::<libc::itimerval>::uninit();
297+
let ret = unsafe { libc::getitimer(which, old.as_mut_ptr()) };
298+
if ret != 0 {
299+
let err = std::io::Error::last_os_error();
300+
let itimer_error = itimer_error(vm);
301+
return Err(vm.new_exception_msg(itimer_error, err.to_string()));
302+
}
303+
let old = unsafe { old.assume_init() };
304+
Ok(itimerval_to_tuple(&old))
305+
}
306+
219307
#[pyfunction]
220308
fn default_int_handler(
221309
_signum: PyObjectRef,

0 commit comments

Comments
 (0)