Merge branch 'timer-fn' into 'master'
Implement POSIX timer functions See merge request redox-os/relibc!747
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
use crate::{
|
||||
header::time::{sigevent, timespec},
|
||||
header::{signal::sigevent, time::timespec},
|
||||
platform::types::*,
|
||||
};
|
||||
|
||||
|
||||
@@ -37,6 +37,10 @@ pub const SIG_SETMASK: c_int = 2;
|
||||
pub const SI_QUEUE: c_int = -1;
|
||||
pub const SI_USER: c_int = 0;
|
||||
|
||||
pub const SIGEV_SIGNAL: c_int = 0;
|
||||
pub const SIGEV_NONE: c_int = 1;
|
||||
pub const SIGEV_THREAD: c_int = 2;
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Debug)]
|
||||
/// cbindgen:ignore
|
||||
@@ -55,6 +59,16 @@ pub struct sigaltstack {
|
||||
pub ss_size: size_t,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Clone)]
|
||||
pub struct sigevent {
|
||||
pub sigev_value: sigval,
|
||||
pub sigev_signo: c_int,
|
||||
pub sigev_notify: c_int,
|
||||
pub sigev_notify_function: Option<extern "C" fn(sigval)>,
|
||||
pub sigev_notify_attributes: *mut pthread_attr_t,
|
||||
}
|
||||
|
||||
// FIXME: This struct is wrong on Linux
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy)]
|
||||
@@ -525,3 +539,6 @@ pub unsafe extern "C" fn psiginfo(info: *const siginfo_t, prefix: *const c_char)
|
||||
string.as_bytes().len(),
|
||||
);
|
||||
}
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
pub unsafe extern "C" fn cbindgen_stupid_struct_sigevent_for_timer(a: sigevent) {}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
sys_includes = ["sys/types.h", "stdint.h", "stddef.h", "features.h"]
|
||||
sys_includes = ["sys/types.h", "signal.h", "stdint.h", "stddef.h", "features.h"]
|
||||
include_guard = "_RELIBC_TIME_H"
|
||||
language = "C"
|
||||
style = "Tag"
|
||||
@@ -7,3 +7,6 @@ cpp_compat = true
|
||||
|
||||
[enum]
|
||||
prefix_with_name = true
|
||||
|
||||
[export.rename]
|
||||
"sigevent" = "struct sigevent"
|
||||
|
||||
+62
-15
@@ -6,7 +6,9 @@ use crate::{
|
||||
c_str::{CStr, CString},
|
||||
error::ResultExt,
|
||||
fs::File,
|
||||
header::{errno::EOVERFLOW, fcntl::O_RDONLY, stdlib::getenv, unistd::readlink},
|
||||
header::{
|
||||
errno::EOVERFLOW, fcntl::O_RDONLY, signal::sigevent, stdlib::getenv, unistd::readlink,
|
||||
},
|
||||
io::Read,
|
||||
out::Out,
|
||||
platform::{self, Pal, Sys, types::*},
|
||||
@@ -46,13 +48,29 @@ pub struct timespec {
|
||||
}
|
||||
|
||||
impl timespec {
|
||||
// TODO: Write test
|
||||
pub fn add(base: timespec, interval: timespec) -> Option<timespec> {
|
||||
let base_nsec = c_ulong::try_from(base.tv_nsec).ok()?;
|
||||
let interval_nsec = c_ulong::try_from(interval.tv_nsec).ok()?;
|
||||
|
||||
Some(if base_nsec.checked_add(interval_nsec)? < 1_000_000_000 {
|
||||
timespec {
|
||||
tv_sec: base.tv_sec.checked_add(interval.tv_sec)?,
|
||||
tv_nsec: (base_nsec + interval_nsec) as _,
|
||||
}
|
||||
} else {
|
||||
timespec {
|
||||
tv_sec: base.tv_sec.checked_add(interval.tv_sec)?.checked_add(1)?,
|
||||
tv_nsec: ((interval_nsec + base_nsec) - 1_000_000_000) as c_long,
|
||||
}
|
||||
})
|
||||
}
|
||||
// TODO: Write test
|
||||
pub fn subtract(later: timespec, earlier: timespec) -> Option<timespec> {
|
||||
// TODO: Can tv_nsec be negative?
|
||||
let later_nsec = c_ulong::try_from(later.tv_nsec).ok()?;
|
||||
let earlier_nsec = c_ulong::try_from(earlier.tv_nsec).ok()?;
|
||||
|
||||
Some(if later_nsec > earlier_nsec {
|
||||
let time = if later_nsec > earlier_nsec {
|
||||
timespec {
|
||||
tv_sec: later.tv_sec.checked_sub(earlier.tv_sec)?,
|
||||
tv_nsec: (later_nsec - earlier_nsec) as _,
|
||||
@@ -62,7 +80,18 @@ impl timespec {
|
||||
tv_sec: later.tv_sec.checked_sub(earlier.tv_sec)?.checked_sub(1)?,
|
||||
tv_nsec: 1_000_000_000 - (earlier_nsec - later_nsec) as c_long,
|
||||
}
|
||||
})
|
||||
};
|
||||
|
||||
if time.tv_sec < 0 {
|
||||
// https://man7.org/linux/man-pages/man2/settimeofday.2.html
|
||||
// caller should return EINVAL
|
||||
return None;
|
||||
}
|
||||
|
||||
Some(time)
|
||||
}
|
||||
pub fn is_default(&self) -> bool {
|
||||
return self.tv_nsec == 0 && self.tv_sec == 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -76,6 +105,20 @@ impl<'a> From<&'a timespec> for syscall::TimeSpec {
|
||||
}
|
||||
}
|
||||
|
||||
/// timer_t internal data, ABI unstable
|
||||
#[repr(C)]
|
||||
#[derive(Clone)]
|
||||
#[cfg(target_os = "redox")]
|
||||
pub(crate) struct timer_internal_t {
|
||||
pub clockid: clockid_t,
|
||||
pub timerfd: usize,
|
||||
pub eventfd: usize,
|
||||
pub evp: sigevent,
|
||||
pub thread: pthread_t,
|
||||
// relibc handles it_interval, not the kernel
|
||||
pub next_wake_time: itimerspec,
|
||||
}
|
||||
|
||||
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/basedefs/time.h.html>.
|
||||
#[repr(C)]
|
||||
pub struct tm {
|
||||
@@ -132,14 +175,12 @@ pub static mut getdate_err: c_int = 0;
|
||||
|
||||
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/basedefs/time.h.html>.
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Default)]
|
||||
pub struct itimerspec {
|
||||
pub it_interval: timespec,
|
||||
pub it_value: timespec,
|
||||
}
|
||||
|
||||
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/basedefs/time.h.html>.
|
||||
pub struct sigevent;
|
||||
|
||||
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/asctime.html>.
|
||||
///
|
||||
/// # Deprecation
|
||||
@@ -493,19 +534,21 @@ pub unsafe extern "C" fn timelocal(tm: *mut tm) -> time_t {
|
||||
}
|
||||
|
||||
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/timer_create.html>.
|
||||
// #[unsafe(no_mangle)]
|
||||
#[unsafe(no_mangle)]
|
||||
pub extern "C" fn timer_create(
|
||||
clock_id: clockid_t,
|
||||
evp: *mut sigevent,
|
||||
timerid: *mut timer_t,
|
||||
) -> c_int {
|
||||
unimplemented!();
|
||||
Sys::timer_create(clock_id, evp, timerid)
|
||||
.map(|()| 0)
|
||||
.or_minus_one_errno()
|
||||
}
|
||||
|
||||
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/timer_delete.html>.
|
||||
// #[unsafe(no_mangle)]
|
||||
#[unsafe(no_mangle)]
|
||||
pub extern "C" fn timer_delete(timerid: timer_t) -> c_int {
|
||||
unimplemented!();
|
||||
Sys::timer_delete(timerid).map(|()| 0).or_minus_one_errno()
|
||||
}
|
||||
|
||||
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/timer_getoverrun.html>.
|
||||
@@ -515,20 +558,24 @@ pub extern "C" fn timer_getoverrun(timerid: timer_t) -> c_int {
|
||||
}
|
||||
|
||||
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/timer_getoverrun.html>.
|
||||
// #[unsafe(no_mangle)]
|
||||
#[unsafe(no_mangle)]
|
||||
pub extern "C" fn timer_gettime(timerid: timer_t, value: *mut itimerspec) -> c_int {
|
||||
unimplemented!();
|
||||
Sys::timer_gettime(timerid, value)
|
||||
.map(|()| 0)
|
||||
.or_minus_one_errno()
|
||||
}
|
||||
|
||||
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/timer_getoverrun.html>.
|
||||
// #[unsafe(no_mangle)]
|
||||
#[unsafe(no_mangle)]
|
||||
pub extern "C" fn timer_settime(
|
||||
timerid: timer_t,
|
||||
flags: c_int,
|
||||
value: *const itimerspec,
|
||||
ovalue: *mut itimerspec,
|
||||
) -> c_int {
|
||||
unimplemented!();
|
||||
Sys::timer_settime(timerid, flags, value, ovalue)
|
||||
.map(|()| 0)
|
||||
.or_minus_one_errno()
|
||||
}
|
||||
|
||||
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/timespec_get.html>.
|
||||
|
||||
@@ -7,11 +7,12 @@ use crate::{
|
||||
dirent::dirent,
|
||||
errno::{EINVAL, EIO, EOPNOTSUPP},
|
||||
fcntl::{AT_EMPTY_PATH, AT_FDCWD, AT_REMOVEDIR, AT_SYMLINK_NOFOLLOW},
|
||||
signal::SIGCHLD,
|
||||
signal::{SIGCHLD, sigevent},
|
||||
sys_resource::{rlimit, rusage},
|
||||
sys_stat::{S_IFIFO, stat},
|
||||
sys_statvfs::statvfs,
|
||||
sys_time::{timeval, timezone},
|
||||
time::itimerspec,
|
||||
unistd::{SEEK_CUR, SEEK_SET},
|
||||
},
|
||||
io::Write,
|
||||
@@ -725,6 +726,27 @@ impl Pal for Sys {
|
||||
e_raw(unsafe { syscall!(SYNC) }).map(|_| ())
|
||||
}
|
||||
|
||||
fn timer_create(clock_id: clockid_t, evp: *mut sigevent, timerid: *mut timer_t) -> Result<()> {
|
||||
e_raw(unsafe { syscall!(TIMER_CREATE, clock_id, evp, timerid) }).map(|_| ())
|
||||
}
|
||||
|
||||
fn timer_delete(timerid: timer_t) -> Result<()> {
|
||||
e_raw(unsafe { syscall!(TIMER_DELETE, timerid) }).map(|_| ())
|
||||
}
|
||||
|
||||
fn timer_gettime(timerid: timer_t, value: *mut itimerspec) -> Result<()> {
|
||||
e_raw(unsafe { syscall!(TIMER_GETTIME, timerid, value) }).map(|_| ())
|
||||
}
|
||||
|
||||
fn timer_settime(
|
||||
timerid: timer_t,
|
||||
flags: c_int,
|
||||
value: *const itimerspec,
|
||||
ovalue: *mut itimerspec,
|
||||
) -> Result<()> {
|
||||
e_raw(unsafe { syscall!(TIMER_SETTIME, timerid, flags, value, ovalue) }).map(|_| ())
|
||||
}
|
||||
|
||||
fn umask(mask: mode_t) -> mode_t {
|
||||
unsafe { syscall!(UMASK, mask) as mode_t }
|
||||
}
|
||||
|
||||
+15
-1
@@ -3,12 +3,13 @@ use crate::{
|
||||
c_str::CStr,
|
||||
error::{Errno, Result},
|
||||
header::{
|
||||
signal::sigevent,
|
||||
sys_resource::{rlimit, rusage},
|
||||
sys_stat::stat,
|
||||
sys_statvfs::statvfs,
|
||||
sys_time::{timeval, timezone},
|
||||
sys_utsname::utsname,
|
||||
time::timespec,
|
||||
time::{itimerspec, timespec},
|
||||
},
|
||||
out::Out,
|
||||
pthread,
|
||||
@@ -252,6 +253,19 @@ pub trait Pal {
|
||||
|
||||
fn sync() -> Result<()>;
|
||||
|
||||
fn timer_create(clock_id: clockid_t, evp: *mut sigevent, timerid: *mut timer_t) -> Result<()>;
|
||||
|
||||
fn timer_delete(timerid: timer_t) -> Result<()>;
|
||||
|
||||
fn timer_gettime(timerid: timer_t, value: *mut itimerspec) -> Result<()>;
|
||||
|
||||
fn timer_settime(
|
||||
timerid: timer_t,
|
||||
flags: c_int,
|
||||
value: *const itimerspec,
|
||||
ovalue: *mut itimerspec,
|
||||
) -> Result<()>;
|
||||
|
||||
// Always successful
|
||||
fn umask(mask: mode_t) -> mode_t;
|
||||
|
||||
|
||||
+183
-3
@@ -21,11 +21,13 @@ use crate::{
|
||||
header::{
|
||||
dirent::dirent,
|
||||
errno::{
|
||||
EBADF, EBADFD, EBADR, EINTR, EINVAL, EIO, ENAMETOOLONG, ENOENT, ENOMEM, ENOSYS,
|
||||
EBADF, EBADFD, EBADR, EFAULT, EINTR, EINVAL, EIO, ENAMETOOLONG, ENOENT, ENOMEM, ENOSYS,
|
||||
EOPNOTSUPP, EPERM, ERANGE,
|
||||
},
|
||||
fcntl::{self, AT_FDCWD, O_RDONLY},
|
||||
fcntl::{self, AT_FDCWD, O_CREAT, O_RDONLY, O_RDWR},
|
||||
limits,
|
||||
pthread::{pthread_cancel, pthread_create},
|
||||
signal::{SIGEV_NONE, SIGEV_SIGNAL, SIGEV_THREAD, sigevent},
|
||||
sys_mman::{MAP_ANONYMOUS, MAP_FAILED, PROT_READ, PROT_WRITE},
|
||||
sys_random,
|
||||
sys_resource::{RLIM_INFINITY, rlimit, rusage},
|
||||
@@ -34,11 +36,15 @@ use crate::{
|
||||
sys_time::{timeval, timezone},
|
||||
sys_utsname::{UTSLENGTH, utsname},
|
||||
sys_wait,
|
||||
time::timespec,
|
||||
time::{itimerspec, timer_internal_t, timespec},
|
||||
unistd::{F_OK, R_OK, SEEK_CUR, SEEK_SET, W_OK, X_OK},
|
||||
},
|
||||
io::{self, BufReader, prelude::*},
|
||||
out::Out,
|
||||
platform::sys::{
|
||||
libredox::RawResult,
|
||||
timer::{timer_routine, timer_update_wake_time},
|
||||
},
|
||||
sync::rwlock::RwLock,
|
||||
};
|
||||
|
||||
@@ -73,6 +79,7 @@ pub(crate) mod path;
|
||||
mod ptrace;
|
||||
pub(crate) mod signal;
|
||||
mod socket;
|
||||
mod timer;
|
||||
|
||||
macro_rules! path_from_c_str {
|
||||
($c_str:expr) => {{
|
||||
@@ -863,6 +870,7 @@ impl Pal for Sys {
|
||||
let fd = usize::try_from(fd).map_err(|_| Errno(EBADF))?;
|
||||
Ok(redox_rt::sys::posix_read(fd, buf)?)
|
||||
}
|
||||
|
||||
fn pread(fd: c_int, buf: &mut [u8], offset: off_t) -> Result<usize> {
|
||||
unsafe {
|
||||
Ok(syscall::syscall5(
|
||||
@@ -1008,6 +1016,178 @@ impl Pal for Sys {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn timer_create(clock_id: clockid_t, evp: *mut sigevent, timerid: *mut timer_t) -> Result<()> {
|
||||
if timerid.is_null() || evp.is_null() {
|
||||
return Err(Errno(EFAULT));
|
||||
}
|
||||
let ev = unsafe { &*evp };
|
||||
if ev.sigev_notify == SIGEV_THREAD && ev.sigev_notify_function.is_none() {
|
||||
return Err(Errno(EINVAL));
|
||||
}
|
||||
|
||||
let path = format!("/scheme/time/{clock_id}");
|
||||
let timerfd = libredox::open(&path, O_RDWR, 0)?;
|
||||
|
||||
unsafe {
|
||||
let eventfd = Error::demux(event::redox_event_queue_create_v1(0)).map_err(|e| {
|
||||
let _ = syscall::close(timerfd);
|
||||
e
|
||||
})?;
|
||||
|
||||
let timer_buf = Self::mmap(
|
||||
ptr::null_mut(),
|
||||
size_of::<timer_internal_t>(),
|
||||
PROT_READ | PROT_WRITE,
|
||||
MAP_ANONYMOUS,
|
||||
0,
|
||||
0,
|
||||
)
|
||||
.map_err(|e| {
|
||||
let _ = syscall::close(timerfd);
|
||||
let _ = syscall::close(eventfd);
|
||||
e
|
||||
})?;
|
||||
|
||||
*timerid = timer_buf;
|
||||
|
||||
let timer_ptr = timer_buf as *mut timer_internal_t;
|
||||
let timer_st = (&mut *timer_ptr);
|
||||
|
||||
timer_st.clockid = clock_id;
|
||||
timer_st.timerfd = timerfd;
|
||||
timer_st.eventfd = eventfd;
|
||||
timer_st.evp = (*evp).clone();
|
||||
timer_st.next_wake_time = itimerspec::default();
|
||||
timer_st.thread = ptr::null_mut();
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn timer_delete(timerid: timer_t) -> Result<()> {
|
||||
if timerid.is_null() {
|
||||
return Err(Errno(EFAULT));
|
||||
}
|
||||
unsafe {
|
||||
let timer_ptr = timerid as *mut timer_internal_t;
|
||||
let timer_st = (&mut *timer_ptr);
|
||||
let _ = syscall::close(timer_st.timerfd);
|
||||
let _ = syscall::close(timer_st.eventfd);
|
||||
if !timer_st.thread.is_null() {
|
||||
let _ = pthread_cancel(timer_st.thread);
|
||||
}
|
||||
Self::munmap(timer_ptr as *mut c_void, size_of::<timer_internal_t>())?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn timer_gettime(timerid: timer_t, value: *mut itimerspec) -> Result<()> {
|
||||
if value.is_null() {
|
||||
return Err(Errno(EFAULT));
|
||||
}
|
||||
|
||||
let timer_st = unsafe { &mut *(timerid as *mut timer_internal_t) };
|
||||
let mut now = timespec::default();
|
||||
Self::clock_gettime(timer_st.clockid, Out::from_mut(&mut now))?;
|
||||
|
||||
if timer_st.evp.sigev_notify == SIGEV_NONE {
|
||||
if timespec::subtract(timer_st.next_wake_time.it_value, now).is_none() {
|
||||
// error here means the timer is disarmed
|
||||
let _ = timer_update_wake_time(timer_st);
|
||||
}
|
||||
}
|
||||
|
||||
unsafe {
|
||||
*value = if timer_st.next_wake_time.it_value.is_default() {
|
||||
// disarmed
|
||||
itimerspec::default()
|
||||
} else {
|
||||
itimerspec {
|
||||
it_interval: timer_st.next_wake_time.it_interval,
|
||||
it_value: timespec::subtract(timer_st.next_wake_time.it_value, now)
|
||||
.unwrap_or_default(),
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn timer_settime(
|
||||
timerid: timer_t,
|
||||
_flags: c_int,
|
||||
value: *const itimerspec,
|
||||
ovalue: *mut itimerspec,
|
||||
) -> Result<()> {
|
||||
if timerid.is_null() || value.is_null() {
|
||||
return Err(Errno(EFAULT));
|
||||
}
|
||||
|
||||
let timer_st = unsafe { &mut *(timerid as *mut timer_internal_t) };
|
||||
|
||||
if !ovalue.is_null() {
|
||||
Self::timer_gettime(timerid, ovalue)?;
|
||||
}
|
||||
|
||||
let mut now = timespec::default();
|
||||
Self::clock_gettime(timer_st.clockid, Out::from_mut(&mut now))?;
|
||||
|
||||
//FIXME: make these atomic?
|
||||
timer_st.next_wake_time = unsafe {
|
||||
let mut val = (*value).clone();
|
||||
val.it_value = timespec::add(now, val.it_value).ok_or((Errno(EINVAL)))?;
|
||||
val
|
||||
};
|
||||
|
||||
Error::demux(unsafe {
|
||||
event::redox_event_queue_ctl_v1(timer_st.eventfd, timer_st.timerfd, 1, 0)
|
||||
})?;
|
||||
|
||||
let buf_to_write = unsafe {
|
||||
slice::from_raw_parts(
|
||||
&timer_st.next_wake_time.it_value as *const _ as *const u8,
|
||||
mem::size_of::<timespec>(),
|
||||
)
|
||||
};
|
||||
|
||||
let bytes_written = redox_rt::sys::posix_write(timer_st.timerfd, buf_to_write)?;
|
||||
|
||||
if bytes_written < mem::size_of::<timespec>() {
|
||||
return Err(Errno(EIO));
|
||||
}
|
||||
|
||||
if timer_st.thread.is_null() {
|
||||
timer_st.thread = match timer_st.evp.sigev_notify {
|
||||
SIGEV_THREAD => {
|
||||
let mut tid = pthread_t::default();
|
||||
|
||||
let result = unsafe {
|
||||
pthread_create(
|
||||
&mut tid as *mut _,
|
||||
ptr::null(),
|
||||
timer_routine,
|
||||
timerid as *mut c_void,
|
||||
)
|
||||
};
|
||||
if result != 0 {
|
||||
return Err(Errno(result));
|
||||
}
|
||||
tid
|
||||
}
|
||||
//TODO
|
||||
SIGEV_SIGNAL => {
|
||||
return Err(Errno(ENOSYS));
|
||||
}
|
||||
SIGEV_NONE => ptr::null_mut(),
|
||||
_ => {
|
||||
return Err(Errno(EINVAL));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn umask(mask: mode_t) -> mode_t {
|
||||
let new_effective_mask = mask & mode_t::from(MODE_PERM) & !S_ISVTX;
|
||||
(redox_rt::sys::swap_umask(new_effective_mask as u32) as mode_t) & !S_ISVTX
|
||||
|
||||
@@ -0,0 +1,100 @@
|
||||
use ::event::raw::RawEventV1;
|
||||
use syscall::Error;
|
||||
|
||||
use crate::{
|
||||
error::{Errno, Result},
|
||||
header::{
|
||||
errno::EIO,
|
||||
signal::{sigevent, sigval},
|
||||
time::{timer_internal_t, timespec},
|
||||
},
|
||||
out::Out,
|
||||
platform::{
|
||||
Pal, Sys,
|
||||
sys::{event, libredox},
|
||||
types::c_void,
|
||||
},
|
||||
};
|
||||
use core::{
|
||||
mem::{MaybeUninit, size_of, transmute},
|
||||
ops::ControlFlow,
|
||||
ptr, slice,
|
||||
};
|
||||
|
||||
pub extern "C" fn timer_routine(arg: *mut c_void) -> *mut c_void {
|
||||
unsafe {
|
||||
let timer_st = &mut *(arg as *mut timer_internal_t);
|
||||
|
||||
loop {
|
||||
let mut buf = MaybeUninit::uninit();
|
||||
|
||||
unsafe {
|
||||
let res = Error::demux(event::redox_event_queue_get_events_v1(
|
||||
timer_st.eventfd,
|
||||
buf.as_mut_ptr(),
|
||||
1,
|
||||
0,
|
||||
core::ptr::null(),
|
||||
core::ptr::null(),
|
||||
));
|
||||
if let Ok(res) = res {
|
||||
assert_eq!(res, 1, "EOF is not yet well defined for event queues");
|
||||
} else {
|
||||
timer_st.thread = ptr::null_mut();
|
||||
break;
|
||||
}
|
||||
|
||||
if let Some(fun) = timer_st.evp.sigev_notify_function {
|
||||
fun(timer_st.evp.sigev_value);
|
||||
}
|
||||
|
||||
if timer_next_event(timer_st).is_err() {
|
||||
timer_st.thread = ptr::null_mut();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ptr::null_mut()
|
||||
}
|
||||
|
||||
fn timer_next_event(timer_st: &mut timer_internal_t) -> Result<()> {
|
||||
timer_update_wake_time(timer_st)?;
|
||||
|
||||
Error::demux(unsafe {
|
||||
event::redox_event_queue_ctl_v1(timer_st.eventfd, timer_st.timerfd, 1, 0)
|
||||
})?;
|
||||
|
||||
let buf_to_write = unsafe {
|
||||
slice::from_raw_parts(
|
||||
&timer_st.next_wake_time.it_value as *const _ as *const u8,
|
||||
size_of::<timespec>(),
|
||||
)
|
||||
};
|
||||
|
||||
let bytes_written = redox_rt::sys::posix_write(timer_st.timerfd, buf_to_write)?;
|
||||
if bytes_written < size_of::<timespec>() {
|
||||
return Err(Errno(EIO));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn timer_update_wake_time(timer_st: &mut timer_internal_t) -> Result<()> {
|
||||
timer_st.next_wake_time.it_value = if timer_st.next_wake_time.it_interval.is_default() {
|
||||
timespec::default()
|
||||
} else {
|
||||
let mut now = timespec::default();
|
||||
Sys::clock_gettime(timer_st.clockid, Out::from_mut(&mut now))?;
|
||||
let next_time = match timespec::add(now, timer_st.next_wake_time.it_interval) {
|
||||
Some(a) => a,
|
||||
None => timespec::default(),
|
||||
};
|
||||
|
||||
next_time
|
||||
};
|
||||
if timer_st.next_wake_time.it_value.is_default() {
|
||||
return Err(Errno(0));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
Reference in New Issue
Block a user