@@ -19,6 +19,11 @@ pub(crate) mod _signal {
1919 convert:: { IntoPyException , TryFromBorrowedObject } ,
2020 } ;
2121 use crate :: { PyObjectRef , PyResult , VirtualMachine , signal} ;
22+ #[ cfg( unix) ]
23+ use crate :: {
24+ builtins:: PyTypeRef ,
25+ function:: { ArgIntoFloat , OptionalArg } ,
26+ } ;
2227 use std:: sync:: atomic:: { self , Ordering } ;
2328
2429 #[ cfg( any( unix, windows) ) ]
@@ -89,6 +94,18 @@ pub(crate) mod _signal {
8994 fn siginterrupt ( sig : i32 , flag : i32 ) -> i32 ;
9095 }
9196
97+ #[ cfg( any( target_os = "linux" , target_os = "android" ) ) ]
98+ mod ffi {
99+ unsafe extern "C" {
100+ pub fn getitimer ( which : libc:: c_int , curr_value : * mut libc:: itimerval ) -> libc:: c_int ;
101+ pub fn setitimer (
102+ which : libc:: c_int ,
103+ new_value : * const libc:: itimerval ,
104+ old_value : * mut libc:: itimerval ,
105+ ) -> libc:: c_int ;
106+ }
107+ }
108+
92109 #[ pyattr]
93110 use crate :: signal:: NSIG ;
94111
@@ -114,6 +131,31 @@ pub(crate) mod _signal {
114131 #[ pyattr]
115132 use libc:: { SIGPWR , SIGSTKFLT } ;
116133
134+ // Interval timer constants
135+ #[ cfg( all( unix, not( target_os = "android" ) ) ) ]
136+ #[ pyattr]
137+ use libc:: { ITIMER_PROF , ITIMER_REAL , ITIMER_VIRTUAL } ;
138+
139+ #[ cfg( target_os = "android" ) ]
140+ #[ pyattr]
141+ const ITIMER_REAL : libc:: c_int = 0 ;
142+ #[ cfg( target_os = "android" ) ]
143+ #[ pyattr]
144+ const ITIMER_VIRTUAL : libc:: c_int = 1 ;
145+ #[ cfg( target_os = "android" ) ]
146+ #[ pyattr]
147+ const ITIMER_PROF : libc:: c_int = 2 ;
148+
149+ #[ cfg( unix) ]
150+ #[ pyattr( name = "ItimerError" , once) ]
151+ fn itimer_error ( vm : & VirtualMachine ) -> PyTypeRef {
152+ vm. ctx . new_exception_type (
153+ "signal" ,
154+ "ItimerError" ,
155+ Some ( vec ! [ vm. ctx. exceptions. os_error. to_owned( ) ] ) ,
156+ )
157+ }
158+
117159 #[ cfg( any( unix, windows) ) ]
118160 pub ( super ) fn init_signal_handlers (
119161 module : & Py < crate :: builtins:: PyModule > ,
@@ -216,6 +258,80 @@ pub(crate) mod _signal {
216258 prev_time. unwrap_or ( 0 )
217259 }
218260
261+ #[ cfg( unix) ]
262+ #[ pyfunction]
263+ fn pause ( vm : & VirtualMachine ) -> PyResult < ( ) > {
264+ unsafe { libc:: pause ( ) } ;
265+ signal:: check_signals ( vm) ?;
266+ Ok ( ( ) )
267+ }
268+
269+ #[ cfg( unix) ]
270+ fn timeval_to_double ( tv : & libc:: timeval ) -> f64 {
271+ tv. tv_sec as f64 + ( tv. tv_usec as f64 / 1_000_000.0 )
272+ }
273+
274+ #[ cfg( unix) ]
275+ fn double_to_timeval ( val : f64 ) -> libc:: timeval {
276+ libc:: timeval {
277+ tv_sec : val. trunc ( ) as _ ,
278+ tv_usec : ( ( val. fract ( ) ) * 1_000_000.0 ) as _ ,
279+ }
280+ }
281+
282+ #[ cfg( unix) ]
283+ fn itimerval_to_tuple ( it : & libc:: itimerval ) -> ( f64 , f64 ) {
284+ (
285+ timeval_to_double ( & it. it_value ) ,
286+ timeval_to_double ( & it. it_interval ) ,
287+ )
288+ }
289+
290+ #[ cfg( unix) ]
291+ #[ pyfunction]
292+ fn setitimer (
293+ which : i32 ,
294+ seconds : ArgIntoFloat ,
295+ interval : OptionalArg < ArgIntoFloat > ,
296+ vm : & VirtualMachine ,
297+ ) -> PyResult < ( f64 , f64 ) > {
298+ let seconds: f64 = seconds. into ( ) ;
299+ let interval: f64 = interval. map ( |v| v. into ( ) ) . unwrap_or ( 0.0 ) ;
300+ let new = libc:: itimerval {
301+ it_value : double_to_timeval ( seconds) ,
302+ it_interval : double_to_timeval ( interval) ,
303+ } ;
304+ let mut old = std:: mem:: MaybeUninit :: < libc:: itimerval > :: uninit ( ) ;
305+ #[ cfg( any( target_os = "linux" , target_os = "android" ) ) ]
306+ let ret = unsafe { ffi:: setitimer ( which, & new, old. as_mut_ptr ( ) ) } ;
307+ #[ cfg( not( any( target_os = "linux" , target_os = "android" ) ) ) ]
308+ let ret = unsafe { libc:: setitimer ( which, & new, old. as_mut_ptr ( ) ) } ;
309+ if ret != 0 {
310+ let err = std:: io:: Error :: last_os_error ( ) ;
311+ let itimer_error = itimer_error ( vm) ;
312+ return Err ( vm. new_exception_msg ( itimer_error, err. to_string ( ) ) ) ;
313+ }
314+ let old = unsafe { old. assume_init ( ) } ;
315+ Ok ( itimerval_to_tuple ( & old) )
316+ }
317+
318+ #[ cfg( unix) ]
319+ #[ pyfunction]
320+ fn getitimer ( which : i32 , vm : & VirtualMachine ) -> PyResult < ( f64 , f64 ) > {
321+ let mut old = std:: mem:: MaybeUninit :: < libc:: itimerval > :: uninit ( ) ;
322+ #[ cfg( any( target_os = "linux" , target_os = "android" ) ) ]
323+ let ret = unsafe { ffi:: getitimer ( which, old. as_mut_ptr ( ) ) } ;
324+ #[ cfg( not( any( target_os = "linux" , target_os = "android" ) ) ) ]
325+ let ret = unsafe { libc:: getitimer ( which, old. as_mut_ptr ( ) ) } ;
326+ if ret != 0 {
327+ let err = std:: io:: Error :: last_os_error ( ) ;
328+ let itimer_error = itimer_error ( vm) ;
329+ return Err ( vm. new_exception_msg ( itimer_error, err. to_string ( ) ) ) ;
330+ }
331+ let old = unsafe { old. assume_init ( ) } ;
332+ Ok ( itimerval_to_tuple ( & old) )
333+ }
334+
219335 #[ pyfunction]
220336 fn default_int_handler (
221337 _signum : PyObjectRef ,
0 commit comments