mirror of
https://github.com/asterinas/asterinas.git
synced 2025-06-22 17:03:23 +00:00
71 lines
2.3 KiB
Rust
71 lines
2.3 KiB
Rust
use core::time::Duration;
|
|
|
|
use super::SyscallReturn;
|
|
use super::SYS_CLOCK_NANOSLEEP;
|
|
use crate::log_syscall_entry;
|
|
use crate::prelude::*;
|
|
use crate::process::signal::sig_mask::SigMask;
|
|
use crate::process::signal::SigQueueObserver;
|
|
use crate::time::{clockid_t, now_as_duration, timespec_t, ClockID, TIMER_ABSTIME};
|
|
use crate::util::{read_val_from_user, write_val_to_user};
|
|
|
|
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 abs_time = if flags == 0 {
|
|
false
|
|
} else if flags == TIMER_ABSTIME {
|
|
true
|
|
} else {
|
|
unreachable!()
|
|
};
|
|
|
|
let duration = {
|
|
let timespec = read_val_from_user::<timespec_t>(request_timespec_addr)?;
|
|
if abs_time {
|
|
todo!("deal with abs time");
|
|
}
|
|
Duration::from(timespec)
|
|
};
|
|
|
|
debug!(
|
|
"clockid = {:?}, abs_time = {}, duration = {:?}, remain_timespec_addr = 0x{:x}",
|
|
clock_id, abs_time, duration, remain_timespec_addr
|
|
);
|
|
|
|
let start_time = now_as_duration(&clock_id)?;
|
|
|
|
let sigqueue_observer = {
|
|
// 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 sigmask = SigMask::new_full();
|
|
SigQueueObserver::new(sigmask)
|
|
};
|
|
|
|
let res = sigqueue_observer.wait_until_interruptible(|| None, Some(&duration));
|
|
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 + duration {
|
|
return Ok(SyscallReturn::Return(0));
|
|
}
|
|
|
|
if remain_timespec_addr != 0 {
|
|
let remaining_duration = (start_time + duration) - 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!(),
|
|
}
|
|
}
|