mirror of
https://github.com/asterinas/asterinas.git
synced 2025-06-29 04:13:24 +00:00
Add syscall nanosleep
This commit is contained in:
committed by
Tate, Hongliang Tian
parent
ee740020d0
commit
1435dd0896
99
kernel/aster-nix/src/syscall/nanosleep.rs
Normal file
99
kernel/aster-nix/src/syscall/nanosleep.rs
Normal file
@ -0,0 +1,99 @@
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
use core::time::Duration;
|
||||
|
||||
use super::{SyscallReturn, SYS_CLOCK_NANOSLEEP, SYS_NANOSLEEP};
|
||||
use crate::{
|
||||
log_syscall_entry,
|
||||
prelude::*,
|
||||
process::signal::Pauser,
|
||||
time::{clockid_t, now_as_duration, timespec_t, ClockID, TIMER_ABSTIME},
|
||||
util::{read_val_from_user, write_val_to_user},
|
||||
};
|
||||
|
||||
pub fn sys_nanosleep(
|
||||
request_timespec_addr: Vaddr,
|
||||
remain_timespec_addr: Vaddr,
|
||||
) -> Result<SyscallReturn> {
|
||||
log_syscall_entry!(SYS_NANOSLEEP);
|
||||
let clock_id = ClockID::CLOCK_MONOTONIC;
|
||||
|
||||
do_clock_nanosleep(clock_id, false, request_timespec_addr, remain_timespec_addr)
|
||||
}
|
||||
|
||||
pub fn sys_clock_nanosleep(
|
||||
clockid: clockid_t,
|
||||
flags: i32,
|
||||
request_timespec_addr: Vaddr,
|
||||
remain_timespec_addr: Vaddr,
|
||||
) -> Result<SyscallReturn> {
|
||||
log_syscall_entry!(SYS_CLOCK_NANOSLEEP);
|
||||
let clock_id = ClockID::try_from(clockid)?;
|
||||
let is_abs_time = if flags == 0 {
|
||||
false
|
||||
} else if flags == TIMER_ABSTIME {
|
||||
true
|
||||
} else {
|
||||
unreachable!()
|
||||
};
|
||||
|
||||
do_clock_nanosleep(
|
||||
clock_id,
|
||||
is_abs_time,
|
||||
request_timespec_addr,
|
||||
remain_timespec_addr,
|
||||
)
|
||||
}
|
||||
|
||||
fn do_clock_nanosleep(
|
||||
clock_id: ClockID,
|
||||
is_abs_time: bool,
|
||||
request_timespec_addr: Vaddr,
|
||||
remain_timespec_addr: Vaddr,
|
||||
) -> Result<SyscallReturn> {
|
||||
let request_time = {
|
||||
let timespec = read_val_from_user::<timespec_t>(request_timespec_addr)?;
|
||||
Duration::from(timespec)
|
||||
};
|
||||
|
||||
debug!(
|
||||
"clockid = {:?}, is_abs_time = {}, request_time = {:?}, remain_timespec_addr = 0x{:x}",
|
||||
clock_id, is_abs_time, request_time, remain_timespec_addr
|
||||
);
|
||||
|
||||
let start_time = now_as_duration(&clock_id)?;
|
||||
let timeout = if is_abs_time {
|
||||
if request_time < start_time {
|
||||
return Ok(SyscallReturn::Return(0));
|
||||
}
|
||||
|
||||
request_time - start_time
|
||||
} else {
|
||||
request_time
|
||||
};
|
||||
|
||||
// FIXME: sleeping thread can only be interrupted by signals that will call signal handler or terminate
|
||||
// current process. i.e., the signals that should be ignored will not interrupt sleeping thread.
|
||||
let pauser = Pauser::new();
|
||||
|
||||
let res = pauser.pause_until_or_timeout(|| None, &timeout);
|
||||
match res {
|
||||
Err(e) if e.error() == Errno::ETIME => Ok(SyscallReturn::Return(0)),
|
||||
Err(e) if e.error() == Errno::EINTR => {
|
||||
let end_time = now_as_duration(&clock_id)?;
|
||||
|
||||
if end_time >= start_time + timeout {
|
||||
return Ok(SyscallReturn::Return(0));
|
||||
}
|
||||
|
||||
if remain_timespec_addr != 0 && !is_abs_time {
|
||||
let remaining_duration = (start_time + timeout) - end_time;
|
||||
let remaining_timespec = timespec_t::from(remaining_duration);
|
||||
write_val_to_user(remain_timespec_addr, &remaining_timespec)?;
|
||||
}
|
||||
|
||||
return_errno_with_message!(Errno::EINTR, "sleep was interrupted");
|
||||
}
|
||||
Ok(()) | Err(_) => unreachable!(),
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user