mirror of
https://github.com/asterinas/asterinas.git
synced 2025-06-22 17:03:23 +00:00
Add itimer-related syscalls
This commit is contained in:
committed by
Tate, Hongliang Tian
parent
13fd173b24
commit
c5ec2e181e
@ -1,7 +1,7 @@
|
|||||||
// SPDX-License-Identifier: MPL-2.0
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
#![allow(non_camel_case_types)]
|
#![allow(non_camel_case_types)]
|
||||||
use core::mem;
|
use core::mem::{self, size_of};
|
||||||
|
|
||||||
use aster_frame::cpu::GeneralRegs;
|
use aster_frame::cpu::GeneralRegs;
|
||||||
use aster_util::{read_union_fields, union_read_ptr::UnionReadPtr};
|
use aster_util::{read_union_fields, union_read_ptr::UnionReadPtr};
|
||||||
@ -116,6 +116,16 @@ pub union sigval_t {
|
|||||||
sigval_ptr: Vaddr, //*mut c_void
|
sigval_ptr: Vaddr, //*mut c_void
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl sigval_t {
|
||||||
|
pub fn read_int(&self) -> i32 {
|
||||||
|
read_union_fields!(self.sigval_int)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn read_ptr(&self) -> Vaddr {
|
||||||
|
read_union_fields!(self.sigval_ptr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Pod)]
|
#[derive(Clone, Copy, Pod)]
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
union siginfo_sigchild_t {
|
union siginfo_sigchild_t {
|
||||||
@ -198,3 +208,55 @@ pub struct SignalCpuContext {
|
|||||||
pub fpregs_on_heap: u64,
|
pub fpregs_on_heap: u64,
|
||||||
pub fpregs: Vaddr, // *mut FpRegs,
|
pub fpregs: Vaddr, // *mut FpRegs,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Pod)]
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct _sigev_thread {
|
||||||
|
pub function: Vaddr,
|
||||||
|
pub attribute: Vaddr,
|
||||||
|
}
|
||||||
|
|
||||||
|
const SIGEV_MAX_SIZE: usize = 64;
|
||||||
|
/// The total size of the fields `sigev_value`, `sigev_signo` and `sigev_notify`.
|
||||||
|
const SIGEV_PREAMBLE_SIZE: usize = size_of::<i32>() * 2 + size_of::<sigval_t>();
|
||||||
|
const SIGEV_PAD_SIZE: usize = (SIGEV_MAX_SIZE - SIGEV_PREAMBLE_SIZE) / size_of::<i32>();
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Pod)]
|
||||||
|
#[repr(C)]
|
||||||
|
pub union _sigev_un {
|
||||||
|
pub _pad: [i32; SIGEV_PAD_SIZE],
|
||||||
|
pub _tid: i32,
|
||||||
|
pub _sigev_thread: _sigev_thread,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl _sigev_un {
|
||||||
|
pub fn read_tid(&self) -> i32 {
|
||||||
|
read_union_fields!(self._tid)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn read_function(&self) -> Vaddr {
|
||||||
|
read_union_fields!(self._sigev_thread.function)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn read_attribute(&self) -> Vaddr {
|
||||||
|
read_union_fields!(self._sigev_thread.attribute)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Copy, Clone, TryFromInt, PartialEq)]
|
||||||
|
#[repr(i32)]
|
||||||
|
pub enum SigNotify {
|
||||||
|
SIGEV_SIGNAL = 0,
|
||||||
|
SIGEV_NONE = 1,
|
||||||
|
SIGEV_THREAD = 2,
|
||||||
|
SIGEV_THREAD_ID = 4,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Pod)]
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct sigevent_t {
|
||||||
|
pub sigev_value: sigval_t,
|
||||||
|
pub sigev_signo: i32,
|
||||||
|
pub sigev_notify: i32,
|
||||||
|
pub sigev_un: _sigev_un,
|
||||||
|
}
|
||||||
|
@ -85,6 +85,7 @@ use crate::syscall::{
|
|||||||
setfsuid::sys_setfsuid,
|
setfsuid::sys_setfsuid,
|
||||||
setgid::sys_setgid,
|
setgid::sys_setgid,
|
||||||
setgroups::sys_setgroups,
|
setgroups::sys_setgroups,
|
||||||
|
setitimer::{sys_getitimer, sys_setitimer},
|
||||||
setpgid::sys_setpgid,
|
setpgid::sys_setpgid,
|
||||||
setregid::sys_setregid,
|
setregid::sys_setregid,
|
||||||
setresgid::sys_setresgid,
|
setresgid::sys_setresgid,
|
||||||
@ -103,6 +104,8 @@ use crate::syscall::{
|
|||||||
sync::sys_sync,
|
sync::sys_sync,
|
||||||
tgkill::sys_tgkill,
|
tgkill::sys_tgkill,
|
||||||
time::sys_time,
|
time::sys_time,
|
||||||
|
timer_create::{sys_timer_create, sys_timer_delete},
|
||||||
|
timer_settime::{sys_timer_gettime, sys_timer_settime},
|
||||||
truncate::{sys_ftruncate, sys_truncate},
|
truncate::{sys_ftruncate, sys_truncate},
|
||||||
umask::sys_umask,
|
umask::sys_umask,
|
||||||
uname::sys_uname,
|
uname::sys_uname,
|
||||||
@ -143,7 +146,9 @@ impl_syscall_nums_and_dispatch_fn! {
|
|||||||
SYS_DUP2 = 33 => sys_dup2(args[..2]);
|
SYS_DUP2 = 33 => sys_dup2(args[..2]);
|
||||||
SYS_PAUSE = 34 => sys_pause(args[..0]);
|
SYS_PAUSE = 34 => sys_pause(args[..0]);
|
||||||
SYS_NANOSLEEP = 35 => sys_nanosleep(args[..2]);
|
SYS_NANOSLEEP = 35 => sys_nanosleep(args[..2]);
|
||||||
|
SYS_GETITIMER = 36 => sys_getitimer(args[..2]);
|
||||||
SYS_ALARM = 37 => sys_alarm(args[..1]);
|
SYS_ALARM = 37 => sys_alarm(args[..1]);
|
||||||
|
SYS_SETITIMER = 38 => sys_setitimer(args[..3]);
|
||||||
SYS_GETPID = 39 => sys_getpid(args[..0]);
|
SYS_GETPID = 39 => sys_getpid(args[..0]);
|
||||||
SYS_SENDFILE = 40 => sys_sendfile(args[..4]);
|
SYS_SENDFILE = 40 => sys_sendfile(args[..4]);
|
||||||
SYS_SOCKET = 41 => sys_socket(args[..3]);
|
SYS_SOCKET = 41 => sys_socket(args[..3]);
|
||||||
@ -227,6 +232,10 @@ impl_syscall_nums_and_dispatch_fn! {
|
|||||||
SYS_EPOLL_CREATE = 213 => sys_epoll_create(args[..1]);
|
SYS_EPOLL_CREATE = 213 => sys_epoll_create(args[..1]);
|
||||||
SYS_GETDENTS64 = 217 => sys_getdents64(args[..3]);
|
SYS_GETDENTS64 = 217 => sys_getdents64(args[..3]);
|
||||||
SYS_SET_TID_ADDRESS = 218 => sys_set_tid_address(args[..1]);
|
SYS_SET_TID_ADDRESS = 218 => sys_set_tid_address(args[..1]);
|
||||||
|
SYS_TIMER_CREATE = 222 => sys_timer_create(args[..3]);
|
||||||
|
SYS_TIMER_SETTIME = 223 => sys_timer_settime(args[..4]);
|
||||||
|
SYS_TIMER_GETTIME = 224 => sys_timer_gettime(args[..2]);
|
||||||
|
SYS_TIMER_DELETE = 226 => sys_timer_delete(args[..1]);
|
||||||
SYS_CLOCK_GETTIME = 228 => sys_clock_gettime(args[..2]);
|
SYS_CLOCK_GETTIME = 228 => sys_clock_gettime(args[..2]);
|
||||||
SYS_CLOCK_NANOSLEEP = 230 => sys_clock_nanosleep(args[..4]);
|
SYS_CLOCK_NANOSLEEP = 230 => sys_clock_nanosleep(args[..4]);
|
||||||
SYS_EXIT_GROUP = 231 => sys_exit_group(args[..1]);
|
SYS_EXIT_GROUP = 231 => sys_exit_group(args[..1]);
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
//! Read the Cpu context content then dispatch syscall to corrsponding handler
|
//! Read the Cpu context content then dispatch syscall to corrsponding handler
|
||||||
//! The each sub module contains functions that handle real syscall logic.
|
//! The each sub module contains functions that handle real syscall logic.
|
||||||
use aster_frame::cpu::UserContext;
|
use aster_frame::cpu::UserContext;
|
||||||
pub use clock_gettime::ClockID;
|
pub use clock_gettime::ClockId;
|
||||||
|
|
||||||
use crate::{cpu::LinuxAbi, prelude::*};
|
use crate::{cpu::LinuxAbi, prelude::*};
|
||||||
|
|
||||||
@ -92,6 +92,7 @@ mod setfsgid;
|
|||||||
mod setfsuid;
|
mod setfsuid;
|
||||||
mod setgid;
|
mod setgid;
|
||||||
mod setgroups;
|
mod setgroups;
|
||||||
|
mod setitimer;
|
||||||
mod setpgid;
|
mod setpgid;
|
||||||
mod setregid;
|
mod setregid;
|
||||||
mod setresgid;
|
mod setresgid;
|
||||||
@ -110,6 +111,8 @@ mod symlink;
|
|||||||
mod sync;
|
mod sync;
|
||||||
mod tgkill;
|
mod tgkill;
|
||||||
mod time;
|
mod time;
|
||||||
|
mod timer_create;
|
||||||
|
mod timer_settime;
|
||||||
mod truncate;
|
mod truncate;
|
||||||
mod umask;
|
mod umask;
|
||||||
mod uname;
|
mod uname;
|
||||||
|
95
kernel/aster-nix/src/syscall/setitimer.rs
Normal file
95
kernel/aster-nix/src/syscall/setitimer.rs
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
|
#![allow(non_camel_case_types)]
|
||||||
|
use core::time::Duration;
|
||||||
|
|
||||||
|
use super::SyscallReturn;
|
||||||
|
use crate::{
|
||||||
|
prelude::*,
|
||||||
|
time::{itimerval_t, timer::Timeout, timeval_t},
|
||||||
|
util::{read_val_from_user, write_val_to_user},
|
||||||
|
};
|
||||||
|
|
||||||
|
/// `ItimerType` is used to differ the target timer for some timer-related syscalls.
|
||||||
|
#[derive(Debug, Copy, Clone, TryFromInt, PartialEq)]
|
||||||
|
#[repr(i32)]
|
||||||
|
pub(super) enum ItimerType {
|
||||||
|
ITIMER_REAL = 0,
|
||||||
|
ITIMER_VIRTUAL = 1,
|
||||||
|
ITIMER_PROF = 2,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn sys_setitimer(
|
||||||
|
itimer_type: i32,
|
||||||
|
new_itimerval_addr: Vaddr,
|
||||||
|
old_itimerval_addr: Vaddr,
|
||||||
|
) -> Result<SyscallReturn> {
|
||||||
|
debug!(
|
||||||
|
"itimer_type = {}, new_itimerval_addr = 0x{:x}, old_itimerval_addr = 0x{:x}, ",
|
||||||
|
itimer_type, new_itimerval_addr, old_itimerval_addr
|
||||||
|
);
|
||||||
|
|
||||||
|
if new_itimerval_addr == 0 {
|
||||||
|
return_errno_with_message!(Errno::EINVAL, "invalid pointer to new value");
|
||||||
|
}
|
||||||
|
let current = current!();
|
||||||
|
let new_itimerval = read_val_from_user::<itimerval_t>(new_itimerval_addr)?;
|
||||||
|
let interval = Duration::from(new_itimerval.it_interval);
|
||||||
|
let expire_time = Duration::from(new_itimerval.it_value);
|
||||||
|
|
||||||
|
let process_timer_manager = current.timer_manager();
|
||||||
|
let timer = match ItimerType::try_from(itimer_type)? {
|
||||||
|
ItimerType::ITIMER_REAL => process_timer_manager.alarm_timer(),
|
||||||
|
ItimerType::ITIMER_VIRTUAL => process_timer_manager.virtual_timer(),
|
||||||
|
ItimerType::ITIMER_PROF => process_timer_manager.prof_timer(),
|
||||||
|
};
|
||||||
|
|
||||||
|
if old_itimerval_addr > 0 {
|
||||||
|
let old_interval = timeval_t::from(timer.interval());
|
||||||
|
let remain = timeval_t::from(timer.remain());
|
||||||
|
let old_itimerval = itimerval_t {
|
||||||
|
it_interval: old_interval,
|
||||||
|
it_value: remain,
|
||||||
|
};
|
||||||
|
write_val_to_user(old_itimerval_addr, &old_itimerval)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
timer.set_interval(interval);
|
||||||
|
if expire_time == Duration::ZERO {
|
||||||
|
// Clear previous timer
|
||||||
|
timer.cancel();
|
||||||
|
} else {
|
||||||
|
timer.set_timeout(Timeout::After(expire_time));
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(SyscallReturn::Return(0))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn sys_getitimer(itimer_type: i32, itimerval_addr: Vaddr) -> Result<SyscallReturn> {
|
||||||
|
debug!(
|
||||||
|
"itimer_type = {}, itimerval_addr = 0x{:x}",
|
||||||
|
itimer_type, itimerval_addr
|
||||||
|
);
|
||||||
|
|
||||||
|
if itimerval_addr == 0 {
|
||||||
|
return_errno_with_message!(Errno::EINVAL, "invalid pointer to itimerval");
|
||||||
|
}
|
||||||
|
|
||||||
|
let current = current!();
|
||||||
|
let process_timer_manager = current.timer_manager();
|
||||||
|
let timer = match ItimerType::try_from(itimer_type)? {
|
||||||
|
ItimerType::ITIMER_REAL => process_timer_manager.alarm_timer(),
|
||||||
|
ItimerType::ITIMER_VIRTUAL => process_timer_manager.virtual_timer(),
|
||||||
|
ItimerType::ITIMER_PROF => process_timer_manager.prof_timer(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let interval = timeval_t::from(timer.interval());
|
||||||
|
let remain = timeval_t::from(timer.remain());
|
||||||
|
let itimerval = itimerval_t {
|
||||||
|
it_interval: interval,
|
||||||
|
it_value: remain,
|
||||||
|
};
|
||||||
|
write_val_to_user(itimerval_addr, &itimerval)?;
|
||||||
|
|
||||||
|
Ok(SyscallReturn::Return(0))
|
||||||
|
}
|
168
kernel/aster-nix/src/syscall/timer_create.rs
Normal file
168
kernel/aster-nix/src/syscall/timer_create.rs
Normal file
@ -0,0 +1,168 @@
|
|||||||
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
|
use super::{
|
||||||
|
clock_gettime::{DynamicClockIdInfo, DynamicClockType},
|
||||||
|
SyscallReturn,
|
||||||
|
};
|
||||||
|
use crate::{
|
||||||
|
prelude::*,
|
||||||
|
process::{
|
||||||
|
posix_thread::PosixThreadExt,
|
||||||
|
process_table,
|
||||||
|
signal::{
|
||||||
|
c_types::{sigevent_t, SigNotify},
|
||||||
|
constants::SIGALRM,
|
||||||
|
sig_num::SigNum,
|
||||||
|
signals::kernel::KernelSignal,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
syscall::ClockId,
|
||||||
|
thread::{
|
||||||
|
thread_table,
|
||||||
|
work_queue::{submit_work_item, work_item::WorkItem},
|
||||||
|
Thread,
|
||||||
|
},
|
||||||
|
time::{
|
||||||
|
clockid_t,
|
||||||
|
clocks::{BootTimeClock, MonotonicClock, RealTimeClock},
|
||||||
|
},
|
||||||
|
util::{read_val_from_user, write_val_to_user},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn sys_timer_create(
|
||||||
|
clockid: clockid_t,
|
||||||
|
sigevent_addr: Vaddr,
|
||||||
|
timer_id_addr: Vaddr,
|
||||||
|
) -> Result<SyscallReturn> {
|
||||||
|
if timer_id_addr == 0 {
|
||||||
|
return_errno_with_message!(
|
||||||
|
Errno::EINVAL,
|
||||||
|
"the address of timer_id_addr should be valid"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
let current_process = current!();
|
||||||
|
let sent_signal: Box<dyn Fn() + Send + Sync + 'static> = {
|
||||||
|
// If `sigevent_addr` is NULL, use the default method (like `sys_alarm`) to send signal.
|
||||||
|
if sigevent_addr == 0 {
|
||||||
|
let process = current_process.clone();
|
||||||
|
let signal = KernelSignal::new(SIGALRM);
|
||||||
|
Box::new(move || {
|
||||||
|
process.enqueue_signal(signal);
|
||||||
|
})
|
||||||
|
// Determine the timeout action through `sigevent`.
|
||||||
|
} else {
|
||||||
|
let sig_event = read_val_from_user::<sigevent_t>(sigevent_addr)?;
|
||||||
|
let sigev_notify = SigNotify::try_from(sig_event.sigev_notify)?;
|
||||||
|
let signo = sig_event.sigev_signo;
|
||||||
|
match sigev_notify {
|
||||||
|
// Do nothing when the timer is expired.
|
||||||
|
SigNotify::SIGEV_NONE => Box::new(|| {}),
|
||||||
|
// Send a signal to the current process when the timer is expired.
|
||||||
|
SigNotify::SIGEV_SIGNAL => {
|
||||||
|
let process = current_process.clone();
|
||||||
|
let signal = KernelSignal::new(SigNum::try_from(signo as u8)?);
|
||||||
|
Box::new(move || {
|
||||||
|
process.enqueue_signal(signal);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
// Spawn a posix thread to run the `sigev_function`, which is stored in
|
||||||
|
// `sig_event.sigev_un._sigev_thread`.
|
||||||
|
//
|
||||||
|
// TODO: enable this instructions. Currently the system does not provide an API to spawn
|
||||||
|
// a posix thread to run a specified function.
|
||||||
|
SigNotify::SIGEV_THREAD => {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
// Send a signal to the specified thread when the timer is expired.
|
||||||
|
SigNotify::SIGEV_THREAD_ID => {
|
||||||
|
let tid = sig_event.sigev_un.read_tid() as u32;
|
||||||
|
let thread = thread_table::get_thread(tid).ok_or_else(|| {
|
||||||
|
Error::with_message(Errno::EINVAL, "target thread does not exist")
|
||||||
|
})?;
|
||||||
|
let posix_thread = thread.as_posix_thread().unwrap();
|
||||||
|
if posix_thread.process().pid() != current_process.pid() {
|
||||||
|
return_errno_with_message!(
|
||||||
|
Errno::EINVAL,
|
||||||
|
"target thread should belong to current process"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
let signal = KernelSignal::new(SigNum::try_from(signo as u8)?);
|
||||||
|
Box::new(move || {
|
||||||
|
if let Some(thread) = thread.as_posix_thread() {
|
||||||
|
thread.enqueue_signal(Box::new(signal));
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let work_func = sent_signal;
|
||||||
|
let work_item = Arc::new(WorkItem::new(work_func));
|
||||||
|
let func = move || {
|
||||||
|
submit_work_item(
|
||||||
|
work_item.clone(),
|
||||||
|
crate::thread::work_queue::WorkPriority::High,
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
let process_timer_manager = current_process.timer_manager();
|
||||||
|
let timer = if clockid >= 0 {
|
||||||
|
let clock_id = ClockId::try_from(clockid)?;
|
||||||
|
match clock_id {
|
||||||
|
ClockId::CLOCK_PROCESS_CPUTIME_ID => process_timer_manager.create_prof_timer(func),
|
||||||
|
ClockId::CLOCK_THREAD_CPUTIME_ID => {
|
||||||
|
let current_thread = Thread::current();
|
||||||
|
current_thread
|
||||||
|
.as_posix_thread()
|
||||||
|
.unwrap()
|
||||||
|
.create_prof_timer(func)
|
||||||
|
}
|
||||||
|
ClockId::CLOCK_REALTIME => RealTimeClock::timer_manager().create_timer(func),
|
||||||
|
ClockId::CLOCK_MONOTONIC => MonotonicClock::timer_manager().create_timer(func),
|
||||||
|
ClockId::CLOCK_BOOTTIME => BootTimeClock::timer_manager().create_timer(func),
|
||||||
|
_ => return_errno_with_message!(Errno::EINVAL, "invalid clock ID"),
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let dynamic_clockid_info = DynamicClockIdInfo::try_from(clockid)?;
|
||||||
|
match dynamic_clockid_info {
|
||||||
|
DynamicClockIdInfo::Pid(pid, clock_type) => {
|
||||||
|
let process = process_table::get_process(pid)
|
||||||
|
.ok_or_else(|| crate::Error::with_message(Errno::EINVAL, "invalid clock id"))?;
|
||||||
|
let process_timer_manager = process.timer_manager();
|
||||||
|
match clock_type {
|
||||||
|
DynamicClockType::Profiling => process_timer_manager.create_prof_timer(func),
|
||||||
|
DynamicClockType::Virtual => process_timer_manager.create_virtual_timer(func),
|
||||||
|
// TODO: support scheduling clock and fd clock.
|
||||||
|
_ => unimplemented!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
DynamicClockIdInfo::Tid(tid, clock_type) => {
|
||||||
|
let thread = thread_table::get_thread(tid)
|
||||||
|
.ok_or_else(|| Error::with_message(Errno::EINVAL, "invalid clock id"))?;
|
||||||
|
let posix_thread = thread.as_posix_thread().unwrap();
|
||||||
|
match clock_type {
|
||||||
|
DynamicClockType::Profiling => posix_thread.create_prof_timer(func),
|
||||||
|
DynamicClockType::Virtual => posix_thread.create_virtual_timer(func),
|
||||||
|
_ => unimplemented!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
DynamicClockIdInfo::Fd(_) => unimplemented!(),
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let timer_id = process_timer_manager.add_posix_timer(timer);
|
||||||
|
write_val_to_user(timer_id_addr, &timer_id)?;
|
||||||
|
Ok(SyscallReturn::Return(0))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn sys_timer_delete(timer_id: usize) -> 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))
|
||||||
|
}
|
77
kernel/aster-nix/src/syscall/timer_settime.rs
Normal file
77
kernel/aster-nix/src/syscall/timer_settime.rs
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
|
use core::time::Duration;
|
||||||
|
|
||||||
|
use super::SyscallReturn;
|
||||||
|
use crate::{
|
||||||
|
prelude::*,
|
||||||
|
time::{itimerspec_t, timer::Timeout, timespec_t, TIMER_ABSTIME},
|
||||||
|
util::{read_val_from_user, write_val_to_user},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn sys_timer_settime(
|
||||||
|
timer_id: usize,
|
||||||
|
flags: i32,
|
||||||
|
new_itimerspec_addr: Vaddr,
|
||||||
|
old_itimerspec_addr: Vaddr,
|
||||||
|
) -> Result<SyscallReturn> {
|
||||||
|
if new_itimerspec_addr == 0 {
|
||||||
|
return_errno_with_message!(Errno::EINVAL, "invalid pointer to new value");
|
||||||
|
}
|
||||||
|
|
||||||
|
let new_itimerspec = read_val_from_user::<itimerspec_t>(new_itimerspec_addr)?;
|
||||||
|
let interval = Duration::from(new_itimerspec.it_interval);
|
||||||
|
let expire_time = Duration::from(new_itimerspec.it_value);
|
||||||
|
|
||||||
|
let current_process = current!();
|
||||||
|
let Some(timer) = current_process.timer_manager().find_posix_timer(timer_id) else {
|
||||||
|
return_errno_with_message!(Errno::EINVAL, "invalid timer ID");
|
||||||
|
};
|
||||||
|
|
||||||
|
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,
|
||||||
|
};
|
||||||
|
write_val_to_user(old_itimerspec_addr, &old_itimerspec)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
timer.set_interval(interval);
|
||||||
|
if expire_time == Duration::ZERO {
|
||||||
|
// Clear previous timer
|
||||||
|
timer.cancel();
|
||||||
|
} else {
|
||||||
|
let timeout = if flags == 0 {
|
||||||
|
Timeout::After(expire_time)
|
||||||
|
} else if flags == TIMER_ABSTIME {
|
||||||
|
Timeout::When(expire_time)
|
||||||
|
} else {
|
||||||
|
unreachable!()
|
||||||
|
};
|
||||||
|
timer.set_timeout(timeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(SyscallReturn::Return(0))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn sys_timer_gettime(timer_id: usize, itimerspec_addr: Vaddr) -> Result<SyscallReturn> {
|
||||||
|
if itimerspec_addr == 0 {
|
||||||
|
return_errno_with_message!(Errno::EINVAL, "invalid pointer to return value");
|
||||||
|
}
|
||||||
|
let current_process = current!();
|
||||||
|
let Some(timer) = current_process.timer_manager().find_posix_timer(timer_id) else {
|
||||||
|
return_errno_with_message!(Errno::EINVAL, "invalid timer ID");
|
||||||
|
};
|
||||||
|
|
||||||
|
let interval = timespec_t::from(timer.interval());
|
||||||
|
let remain = timespec_t::from(timer.remain());
|
||||||
|
let itimerspec = itimerspec_t {
|
||||||
|
it_interval: interval,
|
||||||
|
it_value: remain,
|
||||||
|
};
|
||||||
|
write_val_to_user(itimerspec_addr, &itimerspec)?;
|
||||||
|
|
||||||
|
Ok(SyscallReturn::Return(0))
|
||||||
|
}
|
@ -95,3 +95,19 @@ impl From<UnixTime> for Duration {
|
|||||||
Duration::from_secs(time.sec as _)
|
Duration::from_secs(time.sec as _)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// This struct is corresponding to the `itimerval` struct in Linux.
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Debug, Default, Copy, Clone, Pod)]
|
||||||
|
pub struct itimerval_t {
|
||||||
|
pub it_interval: timeval_t,
|
||||||
|
pub it_value: timeval_t,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// This struct is corresponding to the `itimerspec` struct in Linux.
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Debug, Default, Copy, Clone, Pod)]
|
||||||
|
pub struct itimerspec_t {
|
||||||
|
pub it_interval: timespec_t,
|
||||||
|
pub it_value: timespec_t,
|
||||||
|
}
|
||||||
|
Reference in New Issue
Block a user