Support for timerfd-related syscalls

This commit is contained in:
Chen Chengjun
2025-04-25 16:16:46 +08:00
committed by Tate, Hongliang Tian
parent 34048c8cbc
commit 1775bb0861
10 changed files with 344 additions and 18 deletions

View File

@ -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);

View File

@ -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]);

View File

@ -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;

View File

@ -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)
}

View 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 _))
}

View 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))
}

View 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))
}