Implement POSIX timer functions

authored by Wildan Mubarok and committed by Jeremy Soller 2efcd20f 6acf1856

Changed files
+405 -22
src
header
_aio
signal
time
platform
linux
pal
redox
+1 -1
src/header/_aio/mod.rs
··· 1 1 use crate::{ 2 - header::time::{sigevent, timespec}, 2 + header::{signal::sigevent, time::timespec}, 3 3 platform::types::*, 4 4 }; 5 5
+17
src/header/signal/mod.rs
··· 37 37 pub const SI_QUEUE: c_int = -1; 38 38 pub const SI_USER: c_int = 0; 39 39 40 + pub const SIGEV_SIGNAL: c_int = 0; 41 + pub const SIGEV_NONE: c_int = 1; 42 + pub const SIGEV_THREAD: c_int = 2; 43 + 40 44 #[repr(C)] 41 45 #[derive(Clone, Debug)] 42 46 /// cbindgen:ignore ··· 53 57 pub ss_sp: *mut c_void, 54 58 pub ss_flags: c_int, 55 59 pub ss_size: size_t, 60 + } 61 + 62 + #[repr(C)] 63 + #[derive(Clone)] 64 + pub struct sigevent { 65 + pub sigev_value: sigval, 66 + pub sigev_signo: c_int, 67 + pub sigev_notify: c_int, 68 + pub sigev_notify_function: Option<extern "C" fn(sigval)>, 69 + pub sigev_notify_attributes: *mut pthread_attr_t, 56 70 } 57 71 58 72 // FIXME: This struct is wrong on Linux ··· 525 539 string.as_bytes().len(), 526 540 ); 527 541 } 542 + 543 + #[unsafe(no_mangle)] 544 + pub unsafe extern "C" fn cbindgen_stupid_struct_sigevent_for_timer(a: sigevent) {}
+4 -1
src/header/time/cbindgen.toml
··· 1 - sys_includes = ["sys/types.h", "stdint.h", "stddef.h", "features.h"] 1 + sys_includes = ["sys/types.h", "signal.h", "stdint.h", "stddef.h", "features.h"] 2 2 include_guard = "_RELIBC_TIME_H" 3 3 language = "C" 4 4 style = "Tag" ··· 7 7 8 8 [enum] 9 9 prefix_with_name = true 10 + 11 + [export.rename] 12 + "sigevent" = "struct sigevent"
+62 -15
src/header/time/mod.rs
··· 6 6 c_str::{CStr, CString}, 7 7 error::ResultExt, 8 8 fs::File, 9 - header::{errno::EOVERFLOW, fcntl::O_RDONLY, stdlib::getenv, unistd::readlink}, 9 + header::{ 10 + errno::EOVERFLOW, fcntl::O_RDONLY, signal::sigevent, stdlib::getenv, unistd::readlink, 11 + }, 10 12 io::Read, 11 13 out::Out, 12 14 platform::{self, Pal, Sys, types::*}, ··· 47 49 48 50 impl timespec { 49 51 // TODO: Write test 52 + pub fn add(base: timespec, interval: timespec) -> Option<timespec> { 53 + let base_nsec = c_ulong::try_from(base.tv_nsec).ok()?; 54 + let interval_nsec = c_ulong::try_from(interval.tv_nsec).ok()?; 55 + 56 + Some(if base_nsec.checked_add(interval_nsec)? < 1_000_000_000 { 57 + timespec { 58 + tv_sec: base.tv_sec.checked_add(interval.tv_sec)?, 59 + tv_nsec: (base_nsec + interval_nsec) as _, 60 + } 61 + } else { 62 + timespec { 63 + tv_sec: base.tv_sec.checked_add(interval.tv_sec)?.checked_add(1)?, 64 + tv_nsec: ((interval_nsec + base_nsec) - 1_000_000_000) as c_long, 65 + } 66 + }) 67 + } 68 + // TODO: Write test 50 69 pub fn subtract(later: timespec, earlier: timespec) -> Option<timespec> { 51 - // TODO: Can tv_nsec be negative? 52 70 let later_nsec = c_ulong::try_from(later.tv_nsec).ok()?; 53 71 let earlier_nsec = c_ulong::try_from(earlier.tv_nsec).ok()?; 54 72 55 - Some(if later_nsec > earlier_nsec { 73 + let time = if later_nsec > earlier_nsec { 56 74 timespec { 57 75 tv_sec: later.tv_sec.checked_sub(earlier.tv_sec)?, 58 76 tv_nsec: (later_nsec - earlier_nsec) as _, ··· 62 80 tv_sec: later.tv_sec.checked_sub(earlier.tv_sec)?.checked_sub(1)?, 63 81 tv_nsec: 1_000_000_000 - (earlier_nsec - later_nsec) as c_long, 64 82 } 65 - }) 83 + }; 84 + 85 + if time.tv_sec < 0 { 86 + // https://man7.org/linux/man-pages/man2/settimeofday.2.html 87 + // caller should return EINVAL 88 + return None; 89 + } 90 + 91 + Some(time) 92 + } 93 + pub fn is_default(&self) -> bool { 94 + return self.tv_nsec == 0 && self.tv_sec == 0; 66 95 } 67 96 } 68 97 ··· 74 103 tv_nsec: tp.tv_nsec as _, 75 104 } 76 105 } 106 + } 107 + 108 + /// timer_t internal data, ABI unstable 109 + #[repr(C)] 110 + #[derive(Clone)] 111 + #[cfg(target_os = "redox")] 112 + pub(crate) struct timer_internal_t { 113 + pub clockid: clockid_t, 114 + pub timerfd: usize, 115 + pub eventfd: usize, 116 + pub evp: sigevent, 117 + pub thread: pthread_t, 118 + // relibc handles it_interval, not the kernel 119 + pub next_wake_time: itimerspec, 77 120 } 78 121 79 122 /// See <https://pubs.opengroup.org/onlinepubs/9799919799/basedefs/time.h.html>. ··· 132 175 133 176 /// See <https://pubs.opengroup.org/onlinepubs/9799919799/basedefs/time.h.html>. 134 177 #[repr(C)] 178 + #[derive(Clone, Default)] 135 179 pub struct itimerspec { 136 180 pub it_interval: timespec, 137 181 pub it_value: timespec, 138 182 } 139 - 140 - /// See <https://pubs.opengroup.org/onlinepubs/9799919799/basedefs/time.h.html>. 141 - pub struct sigevent; 142 183 143 184 /// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/asctime.html>. 144 185 /// ··· 493 534 } 494 535 495 536 /// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/timer_create.html>. 496 - // #[unsafe(no_mangle)] 537 + #[unsafe(no_mangle)] 497 538 pub extern "C" fn timer_create( 498 539 clock_id: clockid_t, 499 540 evp: *mut sigevent, 500 541 timerid: *mut timer_t, 501 542 ) -> c_int { 502 - unimplemented!(); 543 + Sys::timer_create(clock_id, evp, timerid) 544 + .map(|()| 0) 545 + .or_minus_one_errno() 503 546 } 504 547 505 548 /// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/timer_delete.html>. 506 - // #[unsafe(no_mangle)] 549 + #[unsafe(no_mangle)] 507 550 pub extern "C" fn timer_delete(timerid: timer_t) -> c_int { 508 - unimplemented!(); 551 + Sys::timer_delete(timerid).map(|()| 0).or_minus_one_errno() 509 552 } 510 553 511 554 /// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/timer_getoverrun.html>. ··· 515 558 } 516 559 517 560 /// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/timer_getoverrun.html>. 518 - // #[unsafe(no_mangle)] 561 + #[unsafe(no_mangle)] 519 562 pub extern "C" fn timer_gettime(timerid: timer_t, value: *mut itimerspec) -> c_int { 520 - unimplemented!(); 563 + Sys::timer_gettime(timerid, value) 564 + .map(|()| 0) 565 + .or_minus_one_errno() 521 566 } 522 567 523 568 /// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/timer_getoverrun.html>. 524 - // #[unsafe(no_mangle)] 569 + #[unsafe(no_mangle)] 525 570 pub extern "C" fn timer_settime( 526 571 timerid: timer_t, 527 572 flags: c_int, 528 573 value: *const itimerspec, 529 574 ovalue: *mut itimerspec, 530 575 ) -> c_int { 531 - unimplemented!(); 576 + Sys::timer_settime(timerid, flags, value, ovalue) 577 + .map(|()| 0) 578 + .or_minus_one_errno() 532 579 } 533 580 534 581 /// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/timespec_get.html>.
+23 -1
src/platform/linux/mod.rs
··· 7 7 dirent::dirent, 8 8 errno::{EINVAL, EIO, EOPNOTSUPP}, 9 9 fcntl::{AT_EMPTY_PATH, AT_FDCWD, AT_REMOVEDIR, AT_SYMLINK_NOFOLLOW}, 10 - signal::SIGCHLD, 10 + signal::{SIGCHLD, sigevent}, 11 11 sys_resource::{rlimit, rusage}, 12 12 sys_stat::{S_IFIFO, stat}, 13 13 sys_statvfs::statvfs, 14 14 sys_time::{timeval, timezone}, 15 + time::itimerspec, 15 16 unistd::{SEEK_CUR, SEEK_SET}, 16 17 }, 17 18 io::Write, ··· 723 724 724 725 fn sync() -> Result<()> { 725 726 e_raw(unsafe { syscall!(SYNC) }).map(|_| ()) 727 + } 728 + 729 + fn timer_create(clock_id: clockid_t, evp: *mut sigevent, timerid: *mut timer_t) -> Result<()> { 730 + e_raw(unsafe { syscall!(TIMER_CREATE, clock_id, evp, timerid) }).map(|_| ()) 731 + } 732 + 733 + fn timer_delete(timerid: timer_t) -> Result<()> { 734 + e_raw(unsafe { syscall!(TIMER_DELETE, timerid) }).map(|_| ()) 735 + } 736 + 737 + fn timer_gettime(timerid: timer_t, value: *mut itimerspec) -> Result<()> { 738 + e_raw(unsafe { syscall!(TIMER_GETTIME, timerid, value) }).map(|_| ()) 739 + } 740 + 741 + fn timer_settime( 742 + timerid: timer_t, 743 + flags: c_int, 744 + value: *const itimerspec, 745 + ovalue: *mut itimerspec, 746 + ) -> Result<()> { 747 + e_raw(unsafe { syscall!(TIMER_SETTIME, timerid, flags, value, ovalue) }).map(|_| ()) 726 748 } 727 749 728 750 fn umask(mask: mode_t) -> mode_t {
+15 -1
src/platform/pal/mod.rs
··· 3 3 c_str::CStr, 4 4 error::{Errno, Result}, 5 5 header::{ 6 + signal::sigevent, 6 7 sys_resource::{rlimit, rusage}, 7 8 sys_stat::stat, 8 9 sys_statvfs::statvfs, 9 10 sys_time::{timeval, timezone}, 10 11 sys_utsname::utsname, 11 - time::timespec, 12 + time::{itimerspec, timespec}, 12 13 }, 13 14 out::Out, 14 15 pthread, ··· 251 252 fn symlink(path1: CStr, path2: CStr) -> Result<()>; 252 253 253 254 fn sync() -> Result<()>; 255 + 256 + fn timer_create(clock_id: clockid_t, evp: *mut sigevent, timerid: *mut timer_t) -> Result<()>; 257 + 258 + fn timer_delete(timerid: timer_t) -> Result<()>; 259 + 260 + fn timer_gettime(timerid: timer_t, value: *mut itimerspec) -> Result<()>; 261 + 262 + fn timer_settime( 263 + timerid: timer_t, 264 + flags: c_int, 265 + value: *const itimerspec, 266 + ovalue: *mut itimerspec, 267 + ) -> Result<()>; 254 268 255 269 // Always successful 256 270 fn umask(mask: mode_t) -> mode_t;
+183 -3
src/platform/redox/mod.rs
··· 21 21 header::{ 22 22 dirent::dirent, 23 23 errno::{ 24 - EBADF, EBADFD, EBADR, EINTR, EINVAL, EIO, ENAMETOOLONG, ENOENT, ENOMEM, ENOSYS, 24 + EBADF, EBADFD, EBADR, EFAULT, EINTR, EINVAL, EIO, ENAMETOOLONG, ENOENT, ENOMEM, ENOSYS, 25 25 EOPNOTSUPP, EPERM, ERANGE, 26 26 }, 27 - fcntl::{self, AT_FDCWD, O_RDONLY}, 27 + fcntl::{self, AT_FDCWD, O_CREAT, O_RDONLY, O_RDWR}, 28 28 limits, 29 + pthread::{pthread_cancel, pthread_create}, 30 + signal::{SIGEV_NONE, SIGEV_SIGNAL, SIGEV_THREAD, sigevent}, 29 31 sys_mman::{MAP_ANONYMOUS, MAP_FAILED, PROT_READ, PROT_WRITE}, 30 32 sys_random, 31 33 sys_resource::{RLIM_INFINITY, rlimit, rusage}, ··· 34 36 sys_time::{timeval, timezone}, 35 37 sys_utsname::{UTSLENGTH, utsname}, 36 38 sys_wait, 37 - time::timespec, 39 + time::{itimerspec, timer_internal_t, timespec}, 38 40 unistd::{F_OK, R_OK, SEEK_CUR, SEEK_SET, W_OK, X_OK}, 39 41 }, 40 42 io::{self, BufReader, prelude::*}, 41 43 out::Out, 44 + platform::sys::{ 45 + libredox::RawResult, 46 + timer::{timer_routine, timer_update_wake_time}, 47 + }, 42 48 sync::rwlock::RwLock, 43 49 }; 44 50 ··· 73 79 mod ptrace; 74 80 pub(crate) mod signal; 75 81 mod socket; 82 + mod timer; 76 83 77 84 macro_rules! path_from_c_str { 78 85 ($c_str:expr) => {{ ··· 863 870 let fd = usize::try_from(fd).map_err(|_| Errno(EBADF))?; 864 871 Ok(redox_rt::sys::posix_read(fd, buf)?) 865 872 } 873 + 866 874 fn pread(fd: c_int, buf: &mut [u8], offset: off_t) -> Result<usize> { 867 875 unsafe { 868 876 Ok(syscall::syscall5( ··· 1005 1013 } 1006 1014 1007 1015 fn sync() -> Result<()> { 1016 + Ok(()) 1017 + } 1018 + 1019 + fn timer_create(clock_id: clockid_t, evp: *mut sigevent, timerid: *mut timer_t) -> Result<()> { 1020 + if timerid.is_null() || evp.is_null() { 1021 + return Err(Errno(EFAULT)); 1022 + } 1023 + let ev = unsafe { &*evp }; 1024 + if ev.sigev_notify == SIGEV_THREAD && ev.sigev_notify_function.is_none() { 1025 + return Err(Errno(EINVAL)); 1026 + } 1027 + 1028 + let path = format!("/scheme/time/{clock_id}"); 1029 + let timerfd = libredox::open(&path, O_RDWR, 0)?; 1030 + 1031 + unsafe { 1032 + let eventfd = Error::demux(event::redox_event_queue_create_v1(0)).map_err(|e| { 1033 + let _ = syscall::close(timerfd); 1034 + e 1035 + })?; 1036 + 1037 + let timer_buf = Self::mmap( 1038 + ptr::null_mut(), 1039 + size_of::<timer_internal_t>(), 1040 + PROT_READ | PROT_WRITE, 1041 + MAP_ANONYMOUS, 1042 + 0, 1043 + 0, 1044 + ) 1045 + .map_err(|e| { 1046 + let _ = syscall::close(timerfd); 1047 + let _ = syscall::close(eventfd); 1048 + e 1049 + })?; 1050 + 1051 + *timerid = timer_buf; 1052 + 1053 + let timer_ptr = timer_buf as *mut timer_internal_t; 1054 + let timer_st = (&mut *timer_ptr); 1055 + 1056 + timer_st.clockid = clock_id; 1057 + timer_st.timerfd = timerfd; 1058 + timer_st.eventfd = eventfd; 1059 + timer_st.evp = (*evp).clone(); 1060 + timer_st.next_wake_time = itimerspec::default(); 1061 + timer_st.thread = ptr::null_mut(); 1062 + } 1063 + Ok(()) 1064 + } 1065 + 1066 + fn timer_delete(timerid: timer_t) -> Result<()> { 1067 + if timerid.is_null() { 1068 + return Err(Errno(EFAULT)); 1069 + } 1070 + unsafe { 1071 + let timer_ptr = timerid as *mut timer_internal_t; 1072 + let timer_st = (&mut *timer_ptr); 1073 + let _ = syscall::close(timer_st.timerfd); 1074 + let _ = syscall::close(timer_st.eventfd); 1075 + if !timer_st.thread.is_null() { 1076 + let _ = pthread_cancel(timer_st.thread); 1077 + } 1078 + Self::munmap(timer_ptr as *mut c_void, size_of::<timer_internal_t>())?; 1079 + } 1080 + 1081 + Ok(()) 1082 + } 1083 + 1084 + fn timer_gettime(timerid: timer_t, value: *mut itimerspec) -> Result<()> { 1085 + if value.is_null() { 1086 + return Err(Errno(EFAULT)); 1087 + } 1088 + 1089 + let timer_st = unsafe { &mut *(timerid as *mut timer_internal_t) }; 1090 + let mut now = timespec::default(); 1091 + Self::clock_gettime(timer_st.clockid, Out::from_mut(&mut now))?; 1092 + 1093 + if timer_st.evp.sigev_notify == SIGEV_NONE { 1094 + if timespec::subtract(timer_st.next_wake_time.it_value, now).is_none() { 1095 + // error here means the timer is disarmed 1096 + let _ = timer_update_wake_time(timer_st); 1097 + } 1098 + } 1099 + 1100 + unsafe { 1101 + *value = if timer_st.next_wake_time.it_value.is_default() { 1102 + // disarmed 1103 + itimerspec::default() 1104 + } else { 1105 + itimerspec { 1106 + it_interval: timer_st.next_wake_time.it_interval, 1107 + it_value: timespec::subtract(timer_st.next_wake_time.it_value, now) 1108 + .unwrap_or_default(), 1109 + } 1110 + }; 1111 + } 1112 + 1113 + Ok(()) 1114 + } 1115 + 1116 + fn timer_settime( 1117 + timerid: timer_t, 1118 + _flags: c_int, 1119 + value: *const itimerspec, 1120 + ovalue: *mut itimerspec, 1121 + ) -> Result<()> { 1122 + if timerid.is_null() || value.is_null() { 1123 + return Err(Errno(EFAULT)); 1124 + } 1125 + 1126 + let timer_st = unsafe { &mut *(timerid as *mut timer_internal_t) }; 1127 + 1128 + if !ovalue.is_null() { 1129 + Self::timer_gettime(timerid, ovalue)?; 1130 + } 1131 + 1132 + let mut now = timespec::default(); 1133 + Self::clock_gettime(timer_st.clockid, Out::from_mut(&mut now))?; 1134 + 1135 + //FIXME: make these atomic? 1136 + timer_st.next_wake_time = unsafe { 1137 + let mut val = (*value).clone(); 1138 + val.it_value = timespec::add(now, val.it_value).ok_or((Errno(EINVAL)))?; 1139 + val 1140 + }; 1141 + 1142 + Error::demux(unsafe { 1143 + event::redox_event_queue_ctl_v1(timer_st.eventfd, timer_st.timerfd, 1, 0) 1144 + })?; 1145 + 1146 + let buf_to_write = unsafe { 1147 + slice::from_raw_parts( 1148 + &timer_st.next_wake_time.it_value as *const _ as *const u8, 1149 + mem::size_of::<timespec>(), 1150 + ) 1151 + }; 1152 + 1153 + let bytes_written = redox_rt::sys::posix_write(timer_st.timerfd, buf_to_write)?; 1154 + 1155 + if bytes_written < mem::size_of::<timespec>() { 1156 + return Err(Errno(EIO)); 1157 + } 1158 + 1159 + if timer_st.thread.is_null() { 1160 + timer_st.thread = match timer_st.evp.sigev_notify { 1161 + SIGEV_THREAD => { 1162 + let mut tid = pthread_t::default(); 1163 + 1164 + let result = unsafe { 1165 + pthread_create( 1166 + &mut tid as *mut _, 1167 + ptr::null(), 1168 + timer_routine, 1169 + timerid as *mut c_void, 1170 + ) 1171 + }; 1172 + if result != 0 { 1173 + return Err(Errno(result)); 1174 + } 1175 + tid 1176 + } 1177 + //TODO 1178 + SIGEV_SIGNAL => { 1179 + return Err(Errno(ENOSYS)); 1180 + } 1181 + SIGEV_NONE => ptr::null_mut(), 1182 + _ => { 1183 + return Err(Errno(EINVAL)); 1184 + } 1185 + }; 1186 + } 1187 + 1008 1188 Ok(()) 1009 1189 } 1010 1190
+100
src/platform/redox/timer.rs
··· 1 + use ::event::raw::RawEventV1; 2 + use syscall::Error; 3 + 4 + use crate::{ 5 + error::{Errno, Result}, 6 + header::{ 7 + errno::EIO, 8 + signal::{sigevent, sigval}, 9 + time::{timer_internal_t, timespec}, 10 + }, 11 + out::Out, 12 + platform::{ 13 + Pal, Sys, 14 + sys::{event, libredox}, 15 + types::c_void, 16 + }, 17 + }; 18 + use core::{ 19 + mem::{MaybeUninit, size_of, transmute}, 20 + ops::ControlFlow, 21 + ptr, slice, 22 + }; 23 + 24 + pub extern "C" fn timer_routine(arg: *mut c_void) -> *mut c_void { 25 + unsafe { 26 + let timer_st = &mut *(arg as *mut timer_internal_t); 27 + 28 + loop { 29 + let mut buf = MaybeUninit::uninit(); 30 + 31 + unsafe { 32 + let res = Error::demux(event::redox_event_queue_get_events_v1( 33 + timer_st.eventfd, 34 + buf.as_mut_ptr(), 35 + 1, 36 + 0, 37 + core::ptr::null(), 38 + core::ptr::null(), 39 + )); 40 + if let Ok(res) = res { 41 + assert_eq!(res, 1, "EOF is not yet well defined for event queues"); 42 + } else { 43 + timer_st.thread = ptr::null_mut(); 44 + break; 45 + } 46 + 47 + if let Some(fun) = timer_st.evp.sigev_notify_function { 48 + fun(timer_st.evp.sigev_value); 49 + } 50 + 51 + if timer_next_event(timer_st).is_err() { 52 + timer_st.thread = ptr::null_mut(); 53 + break; 54 + } 55 + } 56 + } 57 + } 58 + 59 + ptr::null_mut() 60 + } 61 + 62 + fn timer_next_event(timer_st: &mut timer_internal_t) -> Result<()> { 63 + timer_update_wake_time(timer_st)?; 64 + 65 + Error::demux(unsafe { 66 + event::redox_event_queue_ctl_v1(timer_st.eventfd, timer_st.timerfd, 1, 0) 67 + })?; 68 + 69 + let buf_to_write = unsafe { 70 + slice::from_raw_parts( 71 + &timer_st.next_wake_time.it_value as *const _ as *const u8, 72 + size_of::<timespec>(), 73 + ) 74 + }; 75 + 76 + let bytes_written = redox_rt::sys::posix_write(timer_st.timerfd, buf_to_write)?; 77 + if bytes_written < size_of::<timespec>() { 78 + return Err(Errno(EIO)); 79 + } 80 + Ok(()) 81 + } 82 + 83 + pub(crate) fn timer_update_wake_time(timer_st: &mut timer_internal_t) -> Result<()> { 84 + timer_st.next_wake_time.it_value = if timer_st.next_wake_time.it_interval.is_default() { 85 + timespec::default() 86 + } else { 87 + let mut now = timespec::default(); 88 + Sys::clock_gettime(timer_st.clockid, Out::from_mut(&mut now))?; 89 + let next_time = match timespec::add(now, timer_st.next_wake_time.it_interval) { 90 + Some(a) => a, 91 + None => timespec::default(), 92 + }; 93 + 94 + next_time 95 + }; 96 + if timer_st.next_wake_time.it_value.is_default() { 97 + return Err(Errno(0)); 98 + } 99 + Ok(()) 100 + }