mirror of
https://github.com/asterinas/asterinas.git
synced 2025-06-22 17:03:23 +00:00
Add syscall alarm
This commit is contained in:
committed by
Tate, Hongliang Tian
parent
286a3514b3
commit
3f402d2d88
@ -58,7 +58,7 @@ impl Timer {
|
||||
///
|
||||
/// If a timeout value is already set, the timeout value will be refreshed.
|
||||
///
|
||||
pub fn set(self: Arc<Self>, timeout: Duration) {
|
||||
pub fn set(self: &Arc<Self>, timeout: Duration) {
|
||||
let mut lock = self.inner.lock_irq_disabled();
|
||||
match &lock.timer_callback {
|
||||
Some(callback) => {
|
||||
|
@ -2,15 +2,18 @@
|
||||
|
||||
use aster_frame::user::UserSpace;
|
||||
|
||||
use super::PosixThread;
|
||||
use super::{PosixThread, PosixThreadExt, RealTimer};
|
||||
use crate::{
|
||||
prelude::*,
|
||||
process::{
|
||||
posix_thread::name::ThreadName,
|
||||
signal::{sig_mask::SigMask, sig_queues::SigQueues},
|
||||
signal::{
|
||||
constants::SIGALRM, sig_mask::SigMask, sig_queues::SigQueues,
|
||||
signals::kernel::KernelSignal,
|
||||
},
|
||||
Credentials, Process,
|
||||
},
|
||||
thread::{status::ThreadStatus, task::create_new_user_task, thread_table, Thread, Tid},
|
||||
thread::{status::ThreadStatus, task, thread_table, Thread, Tid},
|
||||
};
|
||||
|
||||
/// The builder to build a posix thread
|
||||
@ -90,8 +93,23 @@ impl PosixThreadBuilder {
|
||||
sig_queues,
|
||||
is_main_thread,
|
||||
} = self;
|
||||
|
||||
let real_timer = RealTimer::new(move || {
|
||||
let process = {
|
||||
let Some(current_thread) = thread_table::get_thread(tid) else {
|
||||
return;
|
||||
};
|
||||
let posix_thread = current_thread.as_posix_thread().unwrap();
|
||||
posix_thread.process()
|
||||
};
|
||||
|
||||
let signal = KernelSignal::new(SIGALRM);
|
||||
process.enqueue_signal(signal);
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
let thread = Arc::new_cyclic(|thread_ref| {
|
||||
let task = create_new_user_task(user_space, thread_ref.clone());
|
||||
let task = task::create_new_user_task(user_space, thread_ref.clone());
|
||||
let status = ThreadStatus::Init;
|
||||
let posix_thread = PosixThread {
|
||||
process,
|
||||
@ -100,6 +118,7 @@ impl PosixThreadBuilder {
|
||||
set_child_tid: Mutex::new(set_child_tid),
|
||||
clear_child_tid: Mutex::new(clear_child_tid),
|
||||
credentials,
|
||||
real_timer: Mutex::new(real_timer),
|
||||
sig_mask: Mutex::new(sig_mask),
|
||||
sig_queues: Mutex::new(sig_queues),
|
||||
sig_context: Mutex::new(None),
|
||||
|
@ -26,11 +26,13 @@ pub mod futex;
|
||||
mod name;
|
||||
mod posix_thread_ext;
|
||||
mod robust_list;
|
||||
mod timer;
|
||||
|
||||
pub use builder::PosixThreadBuilder;
|
||||
pub use name::{ThreadName, MAX_THREAD_NAME_LEN};
|
||||
pub use posix_thread_ext::PosixThreadExt;
|
||||
pub use robust_list::RobustListHead;
|
||||
pub use timer::RealTimer;
|
||||
|
||||
pub struct PosixThread {
|
||||
// Immutable part
|
||||
@ -50,10 +52,13 @@ pub struct PosixThread {
|
||||
/// Process credentials. At the kernel level, credentials are a per-thread attribute.
|
||||
credentials: Credentials,
|
||||
|
||||
// signal
|
||||
/// blocked signals
|
||||
/// The timer counts down in real (i.e., wall clock) time
|
||||
real_timer: Mutex<RealTimer>,
|
||||
|
||||
// Signal
|
||||
/// Blocked signals
|
||||
sig_mask: Mutex<SigMask>,
|
||||
/// thread-directed sigqueue
|
||||
/// Thread-directed sigqueue
|
||||
sig_queues: Mutex<SigQueues>,
|
||||
/// Signal handler ucontext address
|
||||
/// FIXME: This field may be removed. For glibc applications with RESTORER flag set, the sig_context is always equals with rsp.
|
||||
@ -114,13 +119,13 @@ impl PosixThread {
|
||||
let receiver_sid = self.process().session().unwrap().sid();
|
||||
if receiver_sid == sender.sid() {
|
||||
return Ok(());
|
||||
} else {
|
||||
}
|
||||
|
||||
return_errno_with_message!(
|
||||
Errno::EPERM,
|
||||
"sigcont requires that sender and receiver belongs to the same session"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
let (receiver_ruid, receiver_suid) = {
|
||||
let credentials = self.credentials();
|
||||
@ -141,6 +146,10 @@ impl PosixThread {
|
||||
return_errno_with_message!(Errno::EPERM, "sending signal to the thread is not allowed.");
|
||||
}
|
||||
|
||||
pub fn real_timer(&self) -> &Mutex<RealTimer> {
|
||||
&self.real_timer
|
||||
}
|
||||
|
||||
pub(in crate::process) fn enqueue_signal(&self, signal: Box<dyn Signal>) {
|
||||
self.sig_queues.lock().enqueue(signal);
|
||||
}
|
||||
@ -233,6 +242,8 @@ impl PosixThread {
|
||||
thread_table::remove_thread(tid);
|
||||
}
|
||||
|
||||
self.real_timer.lock().clear();
|
||||
|
||||
if self.is_main_thread() || self.is_last_thread() {
|
||||
// exit current process.
|
||||
debug!("self is main thread or last thread");
|
||||
|
111
kernel/aster-nix/src/process/posix_thread/timer.rs
Normal file
111
kernel/aster-nix/src/process/posix_thread/timer.rs
Normal file
@ -0,0 +1,111 @@
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
use core::time::Duration;
|
||||
|
||||
use crate::{
|
||||
prelude::*,
|
||||
thread::work_queue::{submit_work_item, work_item::WorkItem, WorkPriority},
|
||||
time::SystemTime,
|
||||
};
|
||||
|
||||
/// A timer that counts down in real (wall clock) time to run delayed callbacks in process context.
|
||||
///
|
||||
/// Unlike the `Timer` in `aster-frame`, the callbacks of this `RealTimer` will be executed in process
|
||||
/// context instead of interrupt context. This leads to two differences:
|
||||
///
|
||||
/// 1. The callbacks of this `RealTimer` can sleep, whereas the callbacks of `Timer` in `aster-frame` cannot.
|
||||
/// 2. The callbacks of this `RealTimer` may be delayed by an arbitrary amount of time due to scheduler strategy.
|
||||
///
|
||||
/// Note that the callbacks may not be executed in the process context of the timer's creator, so macros such
|
||||
/// as `current` and `current_thread` should **NOT** be used in the callback.
|
||||
///
|
||||
/// # Example
|
||||
/// ```rust
|
||||
/// let current_tid = current_thread!().tid();
|
||||
/// let timer = RealTimer::new(move || {
|
||||
/// let current_thread = thread_table::get_thread(current_tid);
|
||||
/// let posix_thread = current_thread.as_posix_thread().unwrap();
|
||||
/// let process = posix_thread.process();
|
||||
/// println!("Task executed for PID: {}", process.pid());
|
||||
/// }, Duration::from_secs(1));
|
||||
pub struct RealTimer {
|
||||
timer: Arc<aster_frame::timer::Timer>,
|
||||
expired_time: Option<SystemTime>,
|
||||
}
|
||||
|
||||
impl RealTimer {
|
||||
/// Creates a new `RealTimer`. The `callback` parameter will be called once the timeout is reached.
|
||||
pub fn new(callback: impl Fn() + Send + Sync + Copy + 'static) -> Result<Self> {
|
||||
let timer = {
|
||||
aster_frame::timer::Timer::new(move |timer| {
|
||||
let work_func = Box::new(callback);
|
||||
let work_item = { Arc::new(WorkItem::new(work_func)) };
|
||||
// FIXME: set a higher priority like `WorkPriority::Alarm`.
|
||||
submit_work_item(work_item, WorkPriority::High);
|
||||
})?
|
||||
};
|
||||
|
||||
Ok(Self {
|
||||
timer,
|
||||
expired_time: None,
|
||||
})
|
||||
}
|
||||
|
||||
/// Sets a new timeout value. If the old timeout is already set, the timeout will be refreshed.
|
||||
pub fn set(&mut self, timeout: Duration) -> Result<()> {
|
||||
assert_ne!(timeout, ZERO_DURATION);
|
||||
|
||||
let new_expired_time = {
|
||||
let now = SystemTime::now();
|
||||
now.checked_add(timeout)
|
||||
.ok_or_else(|| Error::with_message(Errno::EINVAL, "Invalid duration"))?
|
||||
};
|
||||
|
||||
self.expired_time = Some(new_expired_time);
|
||||
|
||||
self.timer.set(timeout);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Returns the remaining time until the task is executed. If the `timer` is expired or cleared,
|
||||
/// this method will return zero.
|
||||
pub fn remain(&self) -> Duration {
|
||||
let Some(expired_time) = &self.expired_time else {
|
||||
return ZERO_DURATION;
|
||||
};
|
||||
|
||||
let now = SystemTime::now();
|
||||
match expired_time.duration_since(&now) {
|
||||
Ok(duration) => duration,
|
||||
Err(_) => ZERO_DURATION,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns whether the timer has expired.
|
||||
pub fn is_expired(&self) -> bool {
|
||||
self.remain() == ZERO_DURATION
|
||||
}
|
||||
|
||||
/// Clears the timer.
|
||||
pub fn clear(&mut self) {
|
||||
self.timer.clear();
|
||||
self.expired_time = None;
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for RealTimer {
|
||||
fn drop(&mut self) {
|
||||
self.timer.clear();
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq for RealTimer {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.expired_time == other.expired_time
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for RealTimer {}
|
||||
|
||||
const ZERO_DURATION: Duration = Duration::new(0, 0);
|
29
kernel/aster-nix/src/syscall/alarm.rs
Normal file
29
kernel/aster-nix/src/syscall/alarm.rs
Normal file
@ -0,0 +1,29 @@
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
use core::time::Duration;
|
||||
|
||||
use super::{SyscallReturn, SYS_ALARM};
|
||||
use crate::{log_syscall_entry, prelude::*, process::posix_thread::PosixThreadExt};
|
||||
|
||||
pub fn sys_alarm(seconds: u32) -> Result<SyscallReturn> {
|
||||
log_syscall_entry!(SYS_ALARM);
|
||||
debug!("seconds = {}", seconds);
|
||||
|
||||
let current_thread = current_thread!();
|
||||
let mut real_timer = {
|
||||
let posix_thread = current_thread.as_posix_thread().unwrap();
|
||||
posix_thread.real_timer().lock()
|
||||
};
|
||||
|
||||
let remaining_secs = real_timer.remain().as_secs();
|
||||
|
||||
if seconds == 0 {
|
||||
// Clear previous timer
|
||||
real_timer.clear();
|
||||
return Ok(SyscallReturn::Return(remaining_secs as _));
|
||||
}
|
||||
|
||||
real_timer.set(Duration::from_secs(seconds as u64))?;
|
||||
|
||||
Ok(SyscallReturn::Return(remaining_secs as _))
|
||||
}
|
@ -5,15 +5,16 @@
|
||||
use aster_frame::cpu::UserContext;
|
||||
|
||||
use self::{
|
||||
accept::sys_accept, bind::sys_bind, connect::sys_connect, execve::sys_execveat,
|
||||
getgroups::sys_getgroups, getpeername::sys_getpeername, getrandom::sys_getrandom,
|
||||
getresgid::sys_getresgid, getresuid::sys_getresuid, getsid::sys_getsid,
|
||||
getsockname::sys_getsockname, getsockopt::sys_getsockopt, listen::sys_listen,
|
||||
pread64::sys_pread64, recvfrom::sys_recvfrom, sendto::sys_sendto, setfsgid::sys_setfsgid,
|
||||
setfsuid::sys_setfsuid, setgid::sys_setgid, setgroups::sys_setgroups, setregid::sys_setregid,
|
||||
setresgid::sys_setresgid, setresuid::sys_setresuid, setreuid::sys_setreuid, setsid::sys_setsid,
|
||||
setsockopt::sys_setsockopt, setuid::sys_setuid, shutdown::sys_shutdown,
|
||||
sigaltstack::sys_sigaltstack, socket::sys_socket, socketpair::sys_socketpair,
|
||||
accept::sys_accept, alarm::sys_alarm, bind::sys_bind, connect::sys_connect,
|
||||
execve::sys_execveat, getgroups::sys_getgroups, getpeername::sys_getpeername,
|
||||
getrandom::sys_getrandom, getresgid::sys_getresgid, getresuid::sys_getresuid,
|
||||
getsid::sys_getsid, getsockname::sys_getsockname, getsockopt::sys_getsockopt,
|
||||
listen::sys_listen, pread64::sys_pread64, recvfrom::sys_recvfrom, sendto::sys_sendto,
|
||||
setfsgid::sys_setfsgid, setfsuid::sys_setfsuid, setgid::sys_setgid, setgroups::sys_setgroups,
|
||||
setregid::sys_setregid, setresgid::sys_setresgid, setresuid::sys_setresuid,
|
||||
setreuid::sys_setreuid, setsid::sys_setsid, setsockopt::sys_setsockopt, setuid::sys_setuid,
|
||||
shutdown::sys_shutdown, sigaltstack::sys_sigaltstack, socket::sys_socket,
|
||||
socketpair::sys_socketpair,
|
||||
};
|
||||
use crate::{
|
||||
prelude::*,
|
||||
@ -96,6 +97,7 @@ use crate::{
|
||||
|
||||
mod accept;
|
||||
mod access;
|
||||
mod alarm;
|
||||
mod arch_prctl;
|
||||
mod bind;
|
||||
mod brk;
|
||||
@ -257,6 +259,7 @@ define_syscall_nums!(
|
||||
SYS_DUP = 32,
|
||||
SYS_DUP2 = 33,
|
||||
SYS_PAUSE = 34,
|
||||
SYS_ALARM = 37,
|
||||
SYS_GETPID = 39,
|
||||
SYS_SOCKET = 41,
|
||||
SYS_CONNECT = 42,
|
||||
@ -443,6 +446,7 @@ pub fn syscall_dispatch(
|
||||
SYS_DUP => syscall_handler!(1, sys_dup, args),
|
||||
SYS_DUP2 => syscall_handler!(2, sys_dup2, args),
|
||||
SYS_PAUSE => syscall_handler!(0, sys_pause),
|
||||
SYS_ALARM => syscall_handler!(1, sys_alarm, args),
|
||||
SYS_GETPID => syscall_handler!(0, sys_getpid),
|
||||
SYS_SOCKET => syscall_handler!(3, sys_socket, args),
|
||||
SYS_CONNECT => syscall_handler!(3, sys_connect, args),
|
||||
|
@ -3,7 +3,7 @@
|
||||
TESTS ?= chmod_test chown_test fsync_test getdents_test link_test lseek_test mkdir_test \
|
||||
open_create_test open_test pty_test read_test rename_test stat_test \
|
||||
statfs_test symlink_test sync_test truncate_test uidgid_test unlink_test \
|
||||
vdso_clock_gettime_test write_test
|
||||
vdso_clock_gettime_test write_test alarm_test
|
||||
|
||||
MKFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST)))
|
||||
CUR_DIR := $(patsubst %/,%,$(dir $(MKFILE_PATH)))
|
||||
|
2
regression/syscall_test/blocklists/alarm_test
Normal file
2
regression/syscall_test/blocklists/alarm_test
Normal file
@ -0,0 +1,2 @@
|
||||
AlarmTest.UserModeSpinning
|
||||
AlarmTest.Restart_NoRandomSave
|
Reference in New Issue
Block a user