mirror of
https://github.com/asterinas/asterinas.git
synced 2025-06-20 13:06:33 +00:00
Support for timerfd-related syscalls
This commit is contained in:
committed by
Tate, Hongliang Tian
parent
34048c8cbc
commit
1775bb0861
@ -126,6 +126,9 @@ use crate::syscall::{
|
||||
tgkill::sys_tgkill,
|
||||
timer_create::{sys_timer_create, sys_timer_delete},
|
||||
timer_settime::{sys_timer_gettime, sys_timer_settime},
|
||||
timerfd_create::sys_timerfd_create,
|
||||
timerfd_gettime::sys_timerfd_gettime,
|
||||
timerfd_settime::sys_timerfd_settime,
|
||||
truncate::{sys_ftruncate, sys_truncate},
|
||||
umask::sys_umask,
|
||||
umount::sys_umount,
|
||||
@ -191,6 +194,7 @@ impl_syscall_nums_and_dispatch_fn! {
|
||||
SYS_SYNC = 81 => sys_sync(args[..0]);
|
||||
SYS_FSYNC = 82 => sys_fsync(args[..1]);
|
||||
SYS_FDATASYNC = 83 => sys_fdatasync(args[..1]);
|
||||
SYS_TIMERFD_CREATE = 85 => sys_timerfd_create(args[..2]);
|
||||
SYS_CAPGET = 90 => sys_capget(args[..2]);
|
||||
SYS_CAPSET = 91 => sys_capset(args[..2]);
|
||||
SYS_EXIT = 93 => sys_exit(args[..1]);
|
||||
@ -293,6 +297,8 @@ impl_syscall_nums_and_dispatch_fn! {
|
||||
SYS_CLOCK_NANOSLEEP = 407 => sys_clock_nanosleep(args[..4]);
|
||||
SYS_TIMER_GETTIME = 408 => sys_timer_gettime(args[..2]);
|
||||
SYS_TIMER_SETTIME = 409 => sys_timer_settime(args[..4]);
|
||||
SYS_TIMERFD_GETTIME = 410 => sys_timerfd_gettime(args[..2]);
|
||||
SYS_TIMERFD_SETTIME = 411 => sys_timerfd_settime(args[..4]);
|
||||
SYS_UTIMENSAT = 412 => sys_utimensat(args[..4]);
|
||||
SYS_SEMTIMEDOP = 420 => sys_semtimedop(args[..4]);
|
||||
SYS_CLONE3 = 435 => sys_clone3(args[..2], &user_ctx);
|
||||
|
@ -142,6 +142,9 @@ use crate::syscall::{
|
||||
time::sys_time,
|
||||
timer_create::{sys_timer_create, sys_timer_delete},
|
||||
timer_settime::{sys_timer_gettime, sys_timer_settime},
|
||||
timerfd_create::sys_timerfd_create,
|
||||
timerfd_gettime::sys_timerfd_gettime,
|
||||
timerfd_settime::sys_timerfd_settime,
|
||||
truncate::{sys_ftruncate, sys_truncate},
|
||||
umask::sys_umask,
|
||||
umount::sys_umount,
|
||||
@ -342,8 +345,11 @@ impl_syscall_nums_and_dispatch_fn! {
|
||||
SYS_UTIMENSAT = 280 => sys_utimensat(args[..4]);
|
||||
SYS_EPOLL_PWAIT = 281 => sys_epoll_pwait(args[..6]);
|
||||
SYS_SIGNALFD = 282 => sys_signalfd(args[..3]);
|
||||
SYS_TIMERFD_CREATE = 283 => sys_timerfd_create(args[..2]);
|
||||
SYS_EVENTFD = 284 => sys_eventfd(args[..1]);
|
||||
SYS_FALLOCATE = 285 => sys_fallocate(args[..4]);
|
||||
SYS_TIMERFD_SETTIME = 286 => sys_timerfd_settime(args[..4]);
|
||||
SYS_TIMERFD_GETTIME = 287 => sys_timerfd_gettime(args[..2]);
|
||||
SYS_ACCEPT4 = 288 => sys_accept4(args[..4]);
|
||||
SYS_SIGNALFD4 = 289 => sys_signalfd4(args[..4]);
|
||||
SYS_EVENTFD2 = 290 => sys_eventfd2(args[..2]);
|
||||
|
@ -4,6 +4,7 @@
|
||||
//! The each sub module contains functions that handle real syscall logic.
|
||||
pub use clock_gettime::ClockId;
|
||||
use ostd::cpu::context::UserContext;
|
||||
pub use timer_create::create_timer;
|
||||
|
||||
use crate::{context::Context, cpu::LinuxAbi, prelude::*};
|
||||
|
||||
@ -149,6 +150,9 @@ mod tgkill;
|
||||
mod time;
|
||||
mod timer_create;
|
||||
mod timer_settime;
|
||||
mod timerfd_create;
|
||||
mod timerfd_gettime;
|
||||
mod timerfd_settime;
|
||||
mod truncate;
|
||||
mod umask;
|
||||
mod umount;
|
||||
|
@ -21,6 +21,7 @@ use crate::{
|
||||
time::{
|
||||
clockid_t,
|
||||
clocks::{BootTimeClock, MonotonicClock, RealTimeClock},
|
||||
Timer,
|
||||
},
|
||||
};
|
||||
|
||||
@ -103,7 +104,31 @@ pub fn sys_timer_create(
|
||||
);
|
||||
};
|
||||
|
||||
let process_timer_manager = current_process.timer_manager();
|
||||
let timer = create_timer(clockid, func, ctx)?;
|
||||
|
||||
let timer_id = current_process.timer_manager().add_posix_timer(timer);
|
||||
ctx.user_space().write_val(timer_id_addr, &timer_id)?;
|
||||
Ok(SyscallReturn::Return(0))
|
||||
}
|
||||
|
||||
pub fn sys_timer_delete(timer_id: usize, _ctx: &Context) -> Result<SyscallReturn> {
|
||||
let current_process = current!();
|
||||
let Some(timer) = current_process.timer_manager().remove_posix_timer(timer_id) else {
|
||||
return_errno_with_message!(Errno::EINVAL, "invalid timer ID");
|
||||
};
|
||||
|
||||
timer.cancel();
|
||||
Ok(SyscallReturn::Return(0))
|
||||
}
|
||||
|
||||
/// Creates a timer associated with the specified clock ID.
|
||||
///
|
||||
/// This timer will invoke the given callback function (`func`) when it expires.
|
||||
pub fn create_timer<F>(clockid: clockid_t, func: F, ctx: &Context) -> Result<Arc<Timer>>
|
||||
where
|
||||
F: Fn() + Send + Sync + 'static,
|
||||
{
|
||||
let process_timer_manager = ctx.process.timer_manager();
|
||||
let timer = if clockid >= 0 {
|
||||
let clock_id = ClockId::try_from(clockid)?;
|
||||
match clock_id {
|
||||
@ -141,18 +166,5 @@ pub fn sys_timer_create(
|
||||
DynamicClockIdInfo::Fd(_) => unimplemented!(),
|
||||
}
|
||||
};
|
||||
|
||||
let timer_id = process_timer_manager.add_posix_timer(timer);
|
||||
ctx.user_space().write_val(timer_id_addr, &timer_id)?;
|
||||
Ok(SyscallReturn::Return(0))
|
||||
}
|
||||
|
||||
pub fn sys_timer_delete(timer_id: usize, _ctx: &Context) -> Result<SyscallReturn> {
|
||||
let current_process = current!();
|
||||
let Some(timer) = current_process.timer_manager().remove_posix_timer(timer_id) else {
|
||||
return_errno_with_message!(Errno::EINVAL, "invalid timer ID");
|
||||
};
|
||||
|
||||
timer.cancel();
|
||||
Ok(SyscallReturn::Return(0))
|
||||
Ok(timer)
|
||||
}
|
||||
|
31
kernel/src/syscall/timerfd_create.rs
Normal file
31
kernel/src/syscall/timerfd_create.rs
Normal file
@ -0,0 +1,31 @@
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
use super::SyscallReturn;
|
||||
use crate::{
|
||||
fs::file_table::FdFlags,
|
||||
prelude::*,
|
||||
time::{
|
||||
clockid_t,
|
||||
timerfd::{TFDFlags, TimerfdFile},
|
||||
},
|
||||
};
|
||||
|
||||
pub fn sys_timerfd_create(clockid: clockid_t, flags: i32, ctx: &Context) -> Result<SyscallReturn> {
|
||||
let flags = TFDFlags::from_bits(flags as u32)
|
||||
.ok_or_else(|| Error::with_message(Errno::EINVAL, "unknown flags"))?;
|
||||
|
||||
let timerfd_file = TimerfdFile::new(clockid, flags, ctx)?;
|
||||
|
||||
let fd = {
|
||||
let file_table = ctx.thread_local.borrow_file_table();
|
||||
let mut file_table_locked = file_table.unwrap().write();
|
||||
let fd_flags = if flags.contains(TFDFlags::TFD_CLOEXEC) {
|
||||
FdFlags::CLOEXEC
|
||||
} else {
|
||||
FdFlags::empty()
|
||||
};
|
||||
file_table_locked.insert(Arc::new(timerfd_file), fd_flags)
|
||||
};
|
||||
|
||||
Ok(SyscallReturn::Return(fd as _))
|
||||
}
|
35
kernel/src/syscall/timerfd_gettime.rs
Normal file
35
kernel/src/syscall/timerfd_gettime.rs
Normal file
@ -0,0 +1,35 @@
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
use super::SyscallReturn;
|
||||
use crate::{
|
||||
fs::file_table::FileDesc,
|
||||
prelude::*,
|
||||
time::{itimerspec_t, timerfd::TimerfdFile, timespec_t},
|
||||
};
|
||||
|
||||
pub fn sys_timerfd_gettime(
|
||||
fd: FileDesc,
|
||||
itimerspec_addr: Vaddr,
|
||||
ctx: &Context,
|
||||
) -> Result<SyscallReturn> {
|
||||
if itimerspec_addr == 0 {
|
||||
return_errno_with_message!(Errno::EINVAL, "invalid pointer to return value");
|
||||
}
|
||||
|
||||
let file_table = ctx.thread_local.borrow_file_table();
|
||||
let file_table_locked = file_table.unwrap().read();
|
||||
let timerfd_file = file_table_locked.get_file(fd as _)?;
|
||||
let timerfd_file = timerfd_file
|
||||
.downcast_ref::<TimerfdFile>()
|
||||
.ok_or_else(|| Error::with_message(Errno::EINVAL, "the fd is not a timerfd"))?;
|
||||
|
||||
let interval = timespec_t::from(timerfd_file.timer().interval());
|
||||
let remain = timespec_t::from(timerfd_file.timer().remain());
|
||||
let itimerspec = itimerspec_t {
|
||||
it_interval: interval,
|
||||
it_value: remain,
|
||||
};
|
||||
ctx.user_space().write_val(itimerspec_addr, &itimerspec)?;
|
||||
|
||||
Ok(SyscallReturn::Return(0))
|
||||
}
|
63
kernel/src/syscall/timerfd_settime.rs
Normal file
63
kernel/src/syscall/timerfd_settime.rs
Normal file
@ -0,0 +1,63 @@
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
use core::time::Duration;
|
||||
|
||||
use super::SyscallReturn;
|
||||
use crate::{
|
||||
fs::file_table::FileDesc,
|
||||
prelude::*,
|
||||
time::{itimerspec_t, timer::Timeout, timerfd::TimerfdFile, timespec_t, TIMER_ABSTIME},
|
||||
};
|
||||
|
||||
pub fn sys_timerfd_settime(
|
||||
fd: FileDesc,
|
||||
flags: i32,
|
||||
new_itimerspec_addr: Vaddr,
|
||||
old_itimerspec_addr: Vaddr,
|
||||
ctx: &Context,
|
||||
) -> Result<SyscallReturn> {
|
||||
let file_table = ctx.thread_local.borrow_file_table();
|
||||
let file_table_locked = file_table.unwrap().read();
|
||||
let timerfd_file = file_table_locked.get_file(fd as _)?;
|
||||
let timerfd_file = timerfd_file
|
||||
.downcast_ref::<TimerfdFile>()
|
||||
.ok_or_else(|| Error::with_message(Errno::EINVAL, "the fd is not a timerfd"))?;
|
||||
|
||||
let user_space = ctx.user_space();
|
||||
let new_itimerspec = user_space.read_val::<itimerspec_t>(new_itimerspec_addr)?;
|
||||
let interval = Duration::try_from(new_itimerspec.it_interval)?;
|
||||
let expire_time = Duration::try_from(new_itimerspec.it_value)?;
|
||||
|
||||
let timer = timerfd_file.timer();
|
||||
if old_itimerspec_addr > 0 {
|
||||
let old_interval = timespec_t::from(timer.interval());
|
||||
let remain = timespec_t::from(timer.remain());
|
||||
let old_itimerspec = itimerspec_t {
|
||||
it_interval: old_interval,
|
||||
it_value: remain,
|
||||
};
|
||||
user_space.write_val(old_itimerspec_addr, &old_itimerspec)?;
|
||||
}
|
||||
|
||||
timer.set_interval(interval);
|
||||
timer.cancel();
|
||||
// Clear `ticks` after cancel the timer to ensure that `ticks` is zero
|
||||
// when the timer is rearmed.
|
||||
timerfd_file.clear_ticks();
|
||||
|
||||
const TFD_TIMER_CANCEL_ON_SET: i32 = 2;
|
||||
if expire_time != Duration::ZERO {
|
||||
let timeout = if flags == 0 {
|
||||
Timeout::After(expire_time)
|
||||
} else if flags == TIMER_ABSTIME {
|
||||
Timeout::When(expire_time)
|
||||
} else if flags == TFD_TIMER_CANCEL_ON_SET {
|
||||
unimplemented!()
|
||||
} else {
|
||||
unreachable!()
|
||||
};
|
||||
timer.set_timeout(timeout);
|
||||
}
|
||||
|
||||
Ok(SyscallReturn::Return(0))
|
||||
}
|
Reference in New Issue
Block a user