From a8e5aed62fe2bb22564002afb6be6d5503ded78c Mon Sep 17 00:00:00 2001 From: AuYang261 <459461160@qq.com> Date: Tue, 10 Oct 2023 17:54:39 +0800 Subject: [PATCH] support signal and compelte setitimer, alarm, etc --- Makefile | 2 +- api/arceos_posix_api/Cargo.toml | 1 + api/arceos_posix_api/build.rs | 6 + api/arceos_posix_api/ctypes.h | 5 +- api/arceos_posix_api/src/imp/mod.rs | 2 + api/arceos_posix_api/src/imp/signal.rs | 24 ++++ api/arceos_posix_api/src/imp/time.rs | 41 +++++++ api/arceos_posix_api/src/lib.rs | 4 + api/axfeat/Cargo.toml | 3 + api/axfeat/src/lib.rs | 1 + modules/axruntime/Cargo.toml | 1 + modules/axruntime/src/lib.rs | 38 ++++++ modules/axruntime/src/signal.rs | 156 +++++++++++++++++++++++++ scripts/make/features.mk | 2 +- ulib/axlibc/Cargo.toml | 3 + ulib/axlibc/c/signal.c | 16 +-- ulib/axlibc/c/time.c | 7 -- ulib/axlibc/include/ksigaction.h | 16 +++ ulib/axlibc/include/signal.h | 4 + ulib/axlibc/include/unistd.h | 1 + ulib/axlibc/src/lib.rs | 6 + ulib/axlibc/src/signal.rs | 73 ++++++++++++ ulib/axlibc/src/time.rs | 38 ++++++ ulib/axlibc/src/unistd.rs | 52 +++++++++ 24 files changed, 479 insertions(+), 23 deletions(-) create mode 100644 api/arceos_posix_api/src/imp/signal.rs create mode 100644 modules/axruntime/src/signal.rs create mode 100644 ulib/axlibc/include/ksigaction.h create mode 100644 ulib/axlibc/src/signal.rs diff --git a/Makefile b/Makefile index 52480cde8..6420a9558 100644 --- a/Makefile +++ b/Makefile @@ -10,7 +10,7 @@ # - `ENVS`: Environment variables, separated by comma between key value pairs. Only available when feature `alloc` is enabled. # * App options: # - `A` or `APP`: Path to the application -# - `FEATURES`: Features os ArceOS modules to be enabled. +# - `FEATURES`: Features of ArceOS modules to be enabled. # - `APP_FEATURES`: Features of (rust) apps to be enabled. # * QEMU options: # - `BLK`: Enable storage devices (virtio-blk) diff --git a/api/arceos_posix_api/Cargo.toml b/api/arceos_posix_api/Cargo.toml index b15b620b5..e89c7dbd4 100644 --- a/api/arceos_posix_api/Cargo.toml +++ b/api/arceos_posix_api/Cargo.toml @@ -23,6 +23,7 @@ multitask = ["axtask/multitask", "axfeat/multitask", "axsync/multitask"] fd = ["alloc"] fs = ["dep:axfs", "axfeat/fs", "fd"] net = ["dep:axnet", "axfeat/net", "fd"] +signal = ["axfeat/signal"] pipe = ["fd"] select = ["fd"] epoll = ["fd"] diff --git a/api/arceos_posix_api/build.rs b/api/arceos_posix_api/build.rs index 8ca85fa36..cf9fd062f 100644 --- a/api/arceos_posix_api/build.rs +++ b/api/arceos_posix_api/build.rs @@ -80,6 +80,7 @@ typedef struct {{ "sock.*", "fd_set", "timeval", + "itimerval", "pthread_t", "pthread_attr_t", "pthread_mutex_t", @@ -95,6 +96,8 @@ typedef struct {{ "pthread_cond_t", "pthread_condattr_t", "sysinfo", + "sigaction", + "k_sigaction", ]; let allow_vars = [ "O_.*", @@ -109,6 +112,9 @@ typedef struct {{ "RLIMIT_.*", "EAI_.*", "MAXADDRS", + "ITIMER_.*", + "SIG.*", + "EINVAL", ]; #[derive(Debug)] diff --git a/api/arceos_posix_api/ctypes.h b/api/arceos_posix_api/ctypes.h index 7016e9ed5..e5ca8a68e 100644 --- a/api/arceos_posix_api/ctypes.h +++ b/api/arceos_posix_api/ctypes.h @@ -7,12 +7,15 @@ * See the Mulan PSL v2 for more details. */ +#include #include +#include #include #include +#include #include +#include #include -#include #include #include #include diff --git a/api/arceos_posix_api/src/imp/mod.rs b/api/arceos_posix_api/src/imp/mod.rs index adc7da948..da0d8d064 100644 --- a/api/arceos_posix_api/src/imp/mod.rs +++ b/api/arceos_posix_api/src/imp/mod.rs @@ -11,6 +11,8 @@ mod stdio; pub mod io; pub mod resources; +#[cfg(feature = "signal")] +pub mod signal; pub mod sys; pub mod task; pub mod time; diff --git a/api/arceos_posix_api/src/imp/signal.rs b/api/arceos_posix_api/src/imp/signal.rs new file mode 100644 index 000000000..a9bb3cb9d --- /dev/null +++ b/api/arceos_posix_api/src/imp/signal.rs @@ -0,0 +1,24 @@ +/* Copyright (c) [2023] [Syswonder Community] + * [Rukos] is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * http://license.coscl.org.cn/MulanPSL2 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ + +use crate::ctypes::k_sigaction; +use axruntime::{rx_sigaction, Signal}; + +/// Set signal handler +pub fn sys_sigaction( + signum: u8, + sigaction: Option<&k_sigaction>, + oldact: Option<&mut k_sigaction>, +) { + Signal::sigaction( + signum, + sigaction.map(|act| act as *const k_sigaction as *const rx_sigaction), + oldact.map(|old| old as *mut k_sigaction as *mut rx_sigaction), + ); +} diff --git a/api/arceos_posix_api/src/imp/time.rs b/api/arceos_posix_api/src/imp/time.rs index 221728f43..d3b24b754 100644 --- a/api/arceos_posix_api/src/imp/time.rs +++ b/api/arceos_posix_api/src/imp/time.rs @@ -8,6 +8,8 @@ */ use axerrno::LinuxError; +#[cfg(feature = "signal")] +use axruntime::Signal; use core::ffi::{c_int, c_long}; use core::time::Duration; @@ -108,3 +110,42 @@ pub unsafe fn sys_nanosleep(req: *const ctypes::timespec, rem: *mut ctypes::time Ok(0) }) } + +#[cfg(feature = "signal")] +/// Set a timer to send a signal to the current process after a specified time +pub unsafe fn sys_setitimer(which: c_int, new: *const ctypes::itimerval) -> c_int { + syscall_body!(sys_setitimer, { + let which = which as usize; + let new_interval = Duration::from((*new).it_interval).as_nanos() as u64; + Signal::timer_interval(which, Some(new_interval)); + + let new_ddl = + axhal::time::current_time_nanos() + Duration::from((*new).it_value).as_nanos() as u64; + Signal::timer_deadline(which, Some(new_ddl)); + Ok(0) + }) +} + +#[cfg(feature = "signal")] +/// Get timer to send signal after some time +pub unsafe fn sys_getitimer(which: c_int, curr_value: *mut ctypes::itimerval) -> c_int { + syscall_body!(sys_getitimer, { + let ddl = Duration::from_nanos(Signal::timer_deadline(which as usize, None).unwrap()); + if ddl.as_nanos() == 0 { + return Err(LinuxError::EINVAL); + } + let mut now: ctypes::timespec = ctypes::timespec::default(); + unsafe { + sys_clock_gettime(0, &mut now); + } + let now = Duration::from(now); + if ddl > now { + (*curr_value).it_value = ctypes::timeval::from(ddl - now); + } else { + (*curr_value).it_value = ctypes::timeval::from(Duration::new(0, 0)); + } + (*curr_value).it_interval = + Duration::from_nanos(Signal::timer_interval(which as usize, None).unwrap()).into(); + Ok(0) + }) +} diff --git a/api/arceos_posix_api/src/lib.rs b/api/arceos_posix_api/src/lib.rs index c78e95713..a2a4f3c93 100644 --- a/api/arceos_posix_api/src/lib.rs +++ b/api/arceos_posix_api/src/lib.rs @@ -47,9 +47,13 @@ pub mod ctypes; pub use imp::io::{sys_read, sys_write, sys_writev}; pub use imp::resources::{sys_getrlimit, sys_setrlimit}; +#[cfg(feature = "signal")] +pub use imp::signal::sys_sigaction; pub use imp::sys::sys_sysinfo; pub use imp::task::{sys_exit, sys_getpid, sys_sched_yield}; pub use imp::time::{sys_clock_gettime, sys_clock_settime, sys_nanosleep}; +#[cfg(feature = "signal")] +pub use imp::time::{sys_getitimer, sys_setitimer}; #[cfg(feature = "fd")] pub use imp::fd_ops::{sys_close, sys_dup, sys_dup2, sys_fcntl}; diff --git a/api/axfeat/Cargo.toml b/api/axfeat/Cargo.toml index e05e521c0..81ca243e8 100644 --- a/api/axfeat/Cargo.toml +++ b/api/axfeat/Cargo.toml @@ -48,6 +48,9 @@ net = ["alloc", "paging", "axdriver/virtio-net", "dep:axnet", "axruntime/net"] # Display display = ["alloc", "paging", "axdriver/virtio-gpu", "dep:axdisplay", "axruntime/display"] +# Signal +signal = ["axruntime/signal"] + # Device drivers bus-mmio = ["axdriver?/bus-mmio"] bus-pci = ["axdriver?/bus-pci"] diff --git a/api/axfeat/src/lib.rs b/api/axfeat/src/lib.rs index 98a54dce9..b805070df 100644 --- a/api/axfeat/src/lib.rs +++ b/api/axfeat/src/lib.rs @@ -33,6 +33,7 @@ //! - `myfs`: Allow users to define their custom filesystems to override the default. //! - `net`: Enable networking support. //! - `display`: Enable graphics support. +//! - `signal`: Enable signal support. //! - Device drivers //! - `bus-mmio`: Use device tree to probe all MMIO devices. //! - `bus-pci`: Use PCI bus to probe all PCI devices. diff --git a/modules/axruntime/Cargo.toml b/modules/axruntime/Cargo.toml index 1fe3b3254..a86490675 100644 --- a/modules/axruntime/Cargo.toml +++ b/modules/axruntime/Cargo.toml @@ -23,6 +23,7 @@ multitask = ["axtask/multitask"] fs = ["axdriver", "axfs"] net = ["axdriver", "axnet"] display = ["axdriver", "axdisplay"] +signal = [] [dependencies] cfg-if = "1.0" diff --git a/modules/axruntime/src/lib.rs b/modules/axruntime/src/lib.rs index a10d92ec1..f157499b8 100644 --- a/modules/axruntime/src/lib.rs +++ b/modules/axruntime/src/lib.rs @@ -33,6 +33,8 @@ extern crate axlog; #[cfg(all(target_os = "none", not(test)))] mod lang_items; +#[cfg(feature = "signal")] +mod signal; mod trap; #[cfg(feature = "smp")] @@ -41,6 +43,9 @@ mod mp; #[cfg(feature = "smp")] pub use self::mp::rust_main_secondary; +#[cfg(feature = "signal")] +pub use self::signal::{rx_sigaction, Signal}; + #[cfg(feature = "alloc")] extern crate alloc; #[cfg(feature = "alloc")] @@ -355,8 +360,41 @@ fn init_interrupt() { axhal::time::set_oneshot_timer(deadline); } + #[cfg(feature = "signal")] + fn do_signal() { + let now_ns = axhal::time::current_time_nanos(); + // timer signal num + let timers = [14, 26, 27]; + for (which, timer) in timers.iter().enumerate() { + let mut ddl = Signal::timer_deadline(which, None).unwrap(); + let interval = Signal::timer_interval(which, None).unwrap(); + if ddl != 0 && now_ns >= ddl { + Signal::signal(*timer, true); + if interval == 0 { + ddl = 0; + } else { + ddl += interval; + } + Signal::timer_deadline(which, Some(ddl)); + } + } + let signal = Signal::signal(-1, true).unwrap(); + for signum in 0..32 { + if signal & (1 << signum) != 0 + /* TODO: && support mask */ + { + Signal::sigaction(signum as u8, None, None); + Signal::signal(signum as i8, false); + } + } + } + axhal::irq::register_handler(TIMER_IRQ_NUM, || { update_timer(); + #[cfg(feature = "signal")] + if axhal::cpu::this_cpu_is_bsp() { + do_signal(); + } #[cfg(feature = "multitask")] axtask::on_timer_tick(); }); diff --git a/modules/axruntime/src/signal.rs b/modules/axruntime/src/signal.rs new file mode 100644 index 000000000..e7866df2c --- /dev/null +++ b/modules/axruntime/src/signal.rs @@ -0,0 +1,156 @@ +/* Copyright (c) [2023] [Syswonder Community] + * [Rukos] is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * http://license.coscl.org.cn/MulanPSL2 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ + +#[cfg(feature = "irq")] +use core::sync::atomic::AtomicI64; +use core::{ + ffi::{c_int, c_uint, c_ulong}, + time::Duration, +}; + +/// sigaction in kernel +#[allow(non_camel_case_types)] +#[allow(dead_code)] +#[derive(Copy, Clone, Debug)] +pub struct rx_sigaction { + /// signal handler + pub sa_handler: Option, + /// signal flags + pub sa_flags: c_ulong, + /// signal restorer + pub sa_restorer: Option, + /// signal mask + pub sa_mask: [c_uint; 2usize], +} + +impl rx_sigaction { + const fn new() -> Self { + rx_sigaction { + sa_handler: Some(default_handler), + sa_flags: 0, + sa_restorer: None, + sa_mask: [0, 0], + } + } +} + +/// Signal struct +pub struct Signal { + #[cfg(feature = "irq")] + signal: AtomicI64, + sigaction: [rx_sigaction; 32], + timer_value: [Duration; 3], + timer_interval: [Duration; 3], +} + +unsafe extern "C" fn default_handler(signum: c_int) { + panic!("default_handler, signum: {}", signum); +} + +static mut SIGNAL_IF: Signal = Signal { + #[cfg(feature = "irq")] + signal: AtomicI64::new(0), + sigaction: [rx_sigaction::new(); 32], + // Default::default() is not const + timer_value: [Duration::from_nanos(0); 3], + timer_interval: [Duration::from_nanos(0); 3], +}; + +impl Signal { + /// Set signal + /// signum: signal number, if signum < 0, just return current signal + /// on: true: enable signal, false: disable signal + #[cfg(feature = "irq")] + pub fn signal(signum: i8, on: bool) -> Option { + use core::sync::atomic::Ordering; + if signum >= 32 { + return None; + } + let mut old = unsafe { SIGNAL_IF.signal.load(Ordering::Acquire) }; + if signum >= 0 { + loop { + let new = if on { + old | (1 << signum) + } else { + old & !(1 << signum) + }; + + match unsafe { + SIGNAL_IF.signal.compare_exchange_weak( + old, + new, + Ordering::AcqRel, + Ordering::Acquire, + ) + } { + Ok(_) => break, + Err(x) => old = x, + } + } + } + Some(old.try_into().unwrap()) + } + /// Set signal action + /// signum: signal number + /// sigaction: signal action, if sigaction == None, call the handler + pub fn sigaction( + signum: u8, + sigaction: Option<*const rx_sigaction>, + oldact: Option<*mut rx_sigaction>, + ) { + if signum >= unsafe { SIGNAL_IF.sigaction }.len() as u8 { + return; + } + if let Some(oldact) = oldact { + unsafe { + *oldact = SIGNAL_IF.sigaction[signum as usize]; + } + } + match sigaction { + Some(s) => unsafe { + SIGNAL_IF.sigaction[signum as usize] = *s; + }, + None => unsafe { + SIGNAL_IF.sigaction[signum as usize].sa_handler.unwrap()(signum as c_int) + }, + } + } + /// Set timer + /// which: timer type + /// new_value: new timer value + /// old_value: old timer value + pub fn timer_deadline(which: usize, new_deadline: Option) -> Option { + if which >= unsafe { SIGNAL_IF.timer_value }.len() { + return None; + } + let old = unsafe { SIGNAL_IF.timer_value }[which]; + if let Some(s) = new_deadline { + unsafe { + SIGNAL_IF.timer_value[which] = Duration::from_nanos(s); + } + } + Some(old.as_nanos() as u64) + } + /// Set timer interval + /// which: timer type + /// new_interval: new timer interval + /// old_interval: old timer interval + pub fn timer_interval(which: usize, new_interval: Option) -> Option { + if which >= unsafe { SIGNAL_IF.timer_interval }.len() { + return None; + } + let old = unsafe { SIGNAL_IF.timer_interval }[which]; + if let Some(s) = new_interval { + unsafe { + SIGNAL_IF.timer_interval[which] = Duration::from_nanos(s); + } + } + Some(old.as_nanos() as u64) + } +} diff --git a/scripts/make/features.mk b/scripts/make/features.mk index 0b250d7cd..db11632f8 100644 --- a/scripts/make/features.mk +++ b/scripts/make/features.mk @@ -14,7 +14,7 @@ ifeq ($(APP_TYPE),c) ax_feat_prefix := axfeat/ lib_feat_prefix := axlibc/ - lib_features := fp_simd alloc multitask fs net fd pipe select poll epoll random-hw + lib_features := fp_simd alloc multitask fs net fd pipe select poll epoll random-hw signal else # TODO: it's better to use `axfeat/` as `ax_feat_prefix`, but all apps need to have `axfeat` as a dependency ax_feat_prefix := axstd/ diff --git a/ulib/axlibc/Cargo.toml b/ulib/axlibc/Cargo.toml index b3eb705c9..e52584de2 100644 --- a/ulib/axlibc/Cargo.toml +++ b/ulib/axlibc/Cargo.toml @@ -41,6 +41,9 @@ fs = ["arceos_posix_api/fs", "fd"] # Networking net = ["arceos_posix_api/net", "fd"] +# Signal +signal = ["arceos_posix_api/signal"] + # Libc features fd = [] pipe = ["arceos_posix_api/pipe"] diff --git a/ulib/axlibc/c/signal.c b/ulib/axlibc/c/signal.c index 94fd0a6c3..961ad99f8 100644 --- a/ulib/axlibc/c/signal.c +++ b/ulib/axlibc/c/signal.c @@ -12,17 +12,7 @@ #include #include -int sigaction_helper(int signum, const struct sigaction *act, struct sigaction *oldact, - size_t sigsetsize) -{ - if (signum == SIGKILL || signum == SIGSTOP) - return -EINVAL; - - if (oldact) - *oldact = (struct sigaction){0}; - - return 0; -} +extern int sigaction_inner(int, const struct sigaction *, struct sigaction *); void (*signal(int signum, void (*handler)(int)))(int) { @@ -31,7 +21,7 @@ void (*signal(int signum, void (*handler)(int)))(int) .sa_handler = handler, .sa_flags = SA_RESTART, /* BSD signal semantics */ }; - if (sigaction_helper(signum, &act, &old, sizeof(sigset_t)) < 0) + if (sigaction_inner(signum, &act, &old) < 0) return SIG_ERR; return (old.sa_flags & SA_SIGINFO) ? NULL : old.sa_handler; @@ -39,7 +29,7 @@ void (*signal(int signum, void (*handler)(int)))(int) int sigaction(int sig, const struct sigaction *restrict act, struct sigaction *restrict oact) { - return sigaction_helper(sig, act, oact, sizeof(sigset_t)); + return sigaction_inner(sig, act, oact); } // TODO diff --git a/ulib/axlibc/c/time.c b/ulib/axlibc/c/time.c index 519bd90bf..896ec5161 100644 --- a/ulib/axlibc/c/time.c +++ b/ulib/axlibc/c/time.c @@ -194,13 +194,6 @@ void tzset() return; } -// TODO -int setitimer(int _which, const struct itimerval *restrict _new, struct itimerval *restrict _old) -{ - unimplemented(); - return 0; -} - // TODO char *ctime_r(const time_t *t, char *buf) { diff --git a/ulib/axlibc/include/ksigaction.h b/ulib/axlibc/include/ksigaction.h new file mode 100644 index 000000000..0e4b74fc8 --- /dev/null +++ b/ulib/axlibc/include/ksigaction.h @@ -0,0 +1,16 @@ +/* Copyright (c) [2023] [Syswonder Community] + * [Rukos] is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * http://license.coscl.org.cn/MulanPSL2 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ + + +struct k_sigaction { + void (*handler)(int); + unsigned long flags; + void (*restorer)(void); + unsigned mask[2]; +}; diff --git a/ulib/axlibc/include/signal.h b/ulib/axlibc/include/signal.h index d28864856..cda590492 100644 --- a/ulib/axlibc/include/signal.h +++ b/ulib/axlibc/include/signal.h @@ -154,6 +154,10 @@ typedef void (*sighandler_t)(int); #define SIG_ERR ((void (*)(int)) - 1) #define SIG_DFL ((void (*)(int))0) #define SIG_IGN ((void (*)(int))1) +// Macros above cannot convert to rust variables by build.rs with type-converter +#define SIGERR -1l +#define SIGDFL 0l +#define SIGIGN 1l typedef struct __sigset_t { unsigned long __bits[128 / sizeof(long)]; diff --git a/ulib/axlibc/include/unistd.h b/ulib/axlibc/include/unistd.h index b428bf423..288f4a91b 100644 --- a/ulib/axlibc/include/unistd.h +++ b/ulib/axlibc/include/unistd.h @@ -70,6 +70,7 @@ int fchdir(int); char *getcwd(char *, size_t); unsigned alarm(unsigned); +unsigned ualarm(unsigned, unsigned); unsigned sleep(unsigned); int pause(void); int usleep(unsigned); diff --git a/ulib/axlibc/src/lib.rs b/ulib/axlibc/src/lib.rs index 2aaaf7ce0..66056ca3c 100644 --- a/ulib/axlibc/src/lib.rs +++ b/ulib/axlibc/src/lib.rs @@ -24,6 +24,7 @@ //! - Upperlayer stacks //! - `fs`: Enable file system support. //! - `net`: Enable networking support. +//! - `signal`: Enable signal support. //! - Lib C functions //! - `fd`: Enable file descriptor table. //! - `pipe`: Enable pipe support. @@ -84,6 +85,7 @@ mod mktime; mod rand; mod resource; mod setjmp; +mod signal; mod string; mod sys; mod time; @@ -101,7 +103,11 @@ pub use self::setjmp::{longjmp, setjmp}; pub use self::string::{strlen, strnlen}; pub use self::sys::sysconf; pub use self::time::{clock_gettime, nanosleep}; +#[cfg(feature = "signal")] +pub use self::time::{getitimer, setitimer}; pub use self::unistd::{abort, exit, getpid}; +#[cfg(feature = "signal")] +pub use self::unistd::{alarm, ualarm}; #[cfg(feature = "alloc")] pub use self::env::{getenv, setenv, unsetenv}; diff --git a/ulib/axlibc/src/signal.rs b/ulib/axlibc/src/signal.rs new file mode 100644 index 000000000..b747e3951 --- /dev/null +++ b/ulib/axlibc/src/signal.rs @@ -0,0 +1,73 @@ +/* Copyright (c) [2023] [Syswonder Community] + * [Rukos] is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * http://license.coscl.org.cn/MulanPSL2 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ + +use core::ffi::c_int; + +#[cfg(feature = "signal")] +use crate::ctypes::k_sigaction; +use crate::ctypes::{sigaction, EINVAL, SIGKILL, SIGSTOP}; +#[cfg(feature = "signal")] +use arceos_posix_api::sys_sigaction; + +#[cfg(feature = "signal")] +unsafe extern "C" fn ignore_handler(_: c_int) {} + +#[no_mangle] +pub unsafe extern "C" fn sigaction_inner( + signum: c_int, + _act: *const sigaction, + oldact: *mut sigaction, +) -> c_int { + if signum >= 32 || signum == SIGKILL as _ || signum == SIGSTOP as _ { + return -(EINVAL as c_int); + } + #[cfg(feature = "signal")] + { + let mut sh = (*_act).__sa_handler.sa_handler; + if let Some(h) = sh { + if h as usize == crate::ctypes::SIGIGN as usize { + sh = Some(ignore_handler as unsafe extern "C" fn(c_int)); + } + } + let k_act = k_sigaction { + handler: sh, + flags: (*_act).sa_flags as _, + restorer: (*_act).sa_restorer, + mask: Default::default(), + }; + let mut k_oldact = k_sigaction::default(); + sys_sigaction( + signum as u8, + Some(&k_act), + if oldact.is_null() { + None + } else { + Some(&mut k_oldact) + }, + ); + if !oldact.is_null() { + (*oldact).__sa_handler.sa_handler = k_oldact.handler; + (*oldact).sa_flags = k_oldact.flags as _; + (*oldact).sa_restorer = k_oldact.restorer; + // Not support mask + // (*oldact).sa_mask = k_oldact.mask; + } + } + #[cfg(not(feature = "signal"))] + { + if !oldact.is_null() { + // set to 0 + (*oldact).__sa_handler.sa_handler = None; + (*oldact).sa_flags = 0; + (*oldact).sa_restorer = None; + (*oldact).sa_mask = Default::default(); + } + } + 0 +} diff --git a/ulib/axlibc/src/time.rs b/ulib/axlibc/src/time.rs index fc5b19ccd..f1a54b502 100644 --- a/ulib/axlibc/src/time.rs +++ b/ulib/axlibc/src/time.rs @@ -8,6 +8,8 @@ */ use arceos_posix_api::{sys_clock_gettime, sys_clock_settime, sys_nanosleep}; +#[cfg(feature = "signal")] +use arceos_posix_api::{sys_getitimer, sys_setitimer}; use core::ffi::c_int; use crate::{ctypes, utils::e}; @@ -34,3 +36,39 @@ pub unsafe extern "C" fn nanosleep( ) -> c_int { e(sys_nanosleep(req, rem)) } + +/// Set timer to send signal after some time +#[no_mangle] +pub unsafe extern "C" fn setitimer( + _which: c_int, + _new: *const ctypes::itimerval, + _old: *mut ctypes::itimerval, +) -> c_int { + #[cfg(feature = "signal")] + { + if !_old.is_null() { + let res = e(sys_getitimer(_which, _old)); + if res != 0 { + return res; + } + } + e(sys_setitimer(_which, _new)) + } + #[cfg(not(feature = "signal"))] + { + e(0) + } +} + +/// Set timer to send signal after some time +#[no_mangle] +pub unsafe extern "C" fn getitimer(_which: c_int, _curr_value: *mut ctypes::itimerval) -> c_int { + #[cfg(feature = "signal")] + { + e(sys_getitimer(_which, _curr_value)) + } + #[cfg(not(feature = "signal"))] + { + e(0) + } +} diff --git a/ulib/axlibc/src/unistd.rs b/ulib/axlibc/src/unistd.rs index c2d97986f..bc2f1352e 100644 --- a/ulib/axlibc/src/unistd.rs +++ b/ulib/axlibc/src/unistd.rs @@ -9,6 +9,13 @@ use arceos_posix_api::{sys_exit, sys_getpid}; use core::ffi::c_int; +#[cfg(feature = "signal")] +use { + crate::getitimer, + crate::{ctypes, utils::e}, + arceos_posix_api::sys_setitimer, + core::ffi::c_uint, +}; /// Get current thread ID. #[no_mangle] @@ -27,3 +34,48 @@ pub unsafe extern "C" fn abort() -> ! { pub unsafe extern "C" fn exit(exit_code: c_int) -> ! { sys_exit(exit_code) } + +/// Set an alarm clock for delivery of a signal +#[cfg(feature = "signal")] +#[no_mangle] +pub unsafe extern "C" fn alarm(seconds: c_uint) -> c_uint { + let it = ctypes::itimerval { + it_interval: ctypes::timeval { + tv_sec: 0, + tv_usec: 0, + }, + it_value: ctypes::timeval { + tv_sec: seconds as i64, + tv_usec: 0, + }, + }; + let mut old = ctypes::itimerval::default(); + if getitimer(ctypes::ITIMER_REAL as c_int, &mut old) < 0 { + e(sys_setitimer(ctypes::ITIMER_REAL as c_int, &it)) as c_uint + } else { + old.it_value.tv_sec as c_uint + } +} + +/// Schedule signal after given number of microseconds +#[cfg(feature = "signal")] +#[no_mangle] +pub unsafe extern "C" fn ualarm(useconds: c_uint, interval: c_uint) -> c_uint { + let it = ctypes::itimerval { + it_interval: ctypes::timeval { + tv_sec: 0, + tv_usec: interval as i64, + }, + it_value: ctypes::timeval { + tv_sec: 0, + tv_usec: useconds as i64, + }, + }; + let mut old = ctypes::itimerval::default(); + if getitimer(ctypes::ITIMER_REAL as i32, &mut old) < 0 { + e(sys_setitimer(ctypes::ITIMER_REAL as i32, &it)); + 0 + } else { + core::time::Duration::from(old.it_value).as_micros() as c_uint + } +}