fa54b985ff
Per local/docs/PATCH-PRESERVATION-AUDIT-2026-07-12.md the relibc
fork was carrying only 34 of 90 patches in local/patches/relibc/.
The other 56 patches' content was silently missing from the fork.
This commit re-applies 27 patches that genuinely still apply
cleanly. Recovery covers:
- eventfd implementation (sys/eventfd.h + eventfd.rs)
- signalfd implementation (sys/signalfd.h + signalfd.rs)
- timerfd implementation (sys/timerfd.h + timerfd.rs)
- bits/eventfd.h header
- spawn() function: cbindgen + stdint fix
- P3-timerfd-cbindgen-fix
- cbindgen language=C fixes for sys/{timerfd,semaphore}
- stdint include chain fixes
- strtold implementation
- dns aaaa getaddrinfo ipv6
- various stack/threading/header threading fixes
- dup3 syscalls
- waitid implementation
- bits/timespec reverse_from
- open_memstream integration
24 files changed.
139 lines
4.5 KiB
Rust
139 lines
4.5 KiB
Rust
//! `sys/timerfd.h` implementation.
|
|
//!
|
|
//! Non-POSIX, see <https://man7.org/linux/man-pages/man2/timerfd_create.2.html>.
|
|
|
|
use alloc::{collections::BTreeMap, format};
|
|
use core::{mem, slice, sync::atomic::{AtomicBool, Ordering}};
|
|
|
|
use crate::{
|
|
c_str::{CStr, CString},
|
|
error::{Errno, ResultExt},
|
|
header::{
|
|
bits_timespec::timespec,
|
|
errno::{EBADF, EFAULT, EINVAL, EIO},
|
|
fcntl::{O_CLOEXEC, O_NONBLOCK, O_RDWR},
|
|
},
|
|
out::Out,
|
|
platform::{
|
|
Pal, Sys,
|
|
types::{c_int, clockid_t},
|
|
},
|
|
sync::Mutex,
|
|
};
|
|
|
|
pub use crate::header::time::itimerspec;
|
|
|
|
pub const TFD_CLOEXEC: c_int = 0x80000;
|
|
pub const TFD_NONBLOCK: c_int = 0x800;
|
|
pub const TFD_TIMER_ABSTIME: c_int = 0x1;
|
|
pub const TFD_TIMER_CANCEL_ON_SET: c_int = 0x2;
|
|
|
|
const NSEC_PER_SEC: i64 = 1_000_000_000;
|
|
|
|
static MAP_INIT: AtomicBool = AtomicBool::new(false);
|
|
static TIMERFD_CLOCKIDS: Mutex<Option<BTreeMap<c_int, clockid_t>>> = Mutex::new(None);
|
|
|
|
fn with_map<R>(f: impl FnOnce(&mut BTreeMap<c_int, clockid_t>) -> R) -> R {
|
|
let mut guard = TIMERFD_CLOCKIDS.lock();
|
|
if !MAP_INIT.load(Ordering::Acquire) {
|
|
*guard = Some(BTreeMap::new());
|
|
MAP_INIT.store(true, Ordering::Release);
|
|
}
|
|
f(guard.as_mut().unwrap())
|
|
}
|
|
|
|
fn add_timespec(a: ×pec, b: ×pec) -> timespec {
|
|
let total_nsec = a.tv_nsec as i64 + b.tv_nsec as i64;
|
|
let mut sec = a.tv_sec + b.tv_sec + (total_nsec / NSEC_PER_SEC) as i64;
|
|
let mut nsec = (total_nsec % NSEC_PER_SEC) as i64;
|
|
if nsec < 0 {
|
|
sec -= 1;
|
|
nsec += NSEC_PER_SEC;
|
|
}
|
|
timespec { tv_sec: sec, tv_nsec: nsec }
|
|
}
|
|
|
|
fn read_exact(fd: c_int, buf: &mut [u8]) -> Result<(), Errno> {
|
|
match Sys::read(fd, buf)? {
|
|
n if n == buf.len() => Ok(()),
|
|
_ => Err(Errno(EIO)),
|
|
}
|
|
}
|
|
|
|
fn write_exact(fd: c_int, buf: &[u8]) -> Result<(), Errno> {
|
|
match Sys::write(fd, buf)? {
|
|
n if n == buf.len() => Ok(()),
|
|
_ => Err(Errno(EIO)),
|
|
}
|
|
}
|
|
|
|
#[unsafe(no_mangle)]
|
|
pub extern "C" fn timerfd_create(clockid: clockid_t, flags: c_int) -> c_int {
|
|
let supported = TFD_CLOEXEC | TFD_NONBLOCK;
|
|
if flags & !supported != 0 {
|
|
return Err::<c_int, _>(Errno(EINVAL)).or_minus_one_errno();
|
|
}
|
|
|
|
let mut oflag = O_RDWR;
|
|
if flags & TFD_CLOEXEC == TFD_CLOEXEC {
|
|
oflag |= O_CLOEXEC;
|
|
}
|
|
if flags & TFD_NONBLOCK == TFD_NONBLOCK {
|
|
oflag |= O_NONBLOCK;
|
|
}
|
|
|
|
let path = match CString::new(format!("/scheme/time/{clockid}")) {
|
|
Ok(path) => path,
|
|
Err(_) => return Err::<c_int, _>(Errno(EINVAL)).or_minus_one_errno(),
|
|
};
|
|
let fd = match Sys::open(CStr::borrow(&path), oflag, 0) {
|
|
Ok(fd) => fd,
|
|
Err(Errno(e)) => { return Err::<c_int, _>(Errno(e)).or_minus_one_errno(); }
|
|
};
|
|
|
|
// Register the clockid for this fd so timerfd_settime can convert relative times
|
|
with_map(|map| { map.insert(fd, clockid); });
|
|
|
|
fd
|
|
}
|
|
|
|
#[unsafe(no_mangle)]
|
|
pub unsafe extern "C" fn timerfd_settime(fd: c_int, flags: c_int, new: *const itimerspec, old: *mut itimerspec) -> c_int {
|
|
let supported = TFD_TIMER_ABSTIME | TFD_TIMER_CANCEL_ON_SET;
|
|
if flags & !supported != 0 {
|
|
return Err::<c_int, _>(Errno(EINVAL)).or_minus_one_errno();
|
|
}
|
|
if new.is_null() {
|
|
return Err::<c_int, _>(Errno(EFAULT)).or_minus_one_errno();
|
|
}
|
|
if !old.is_null() && unsafe { timerfd_gettime(fd, old) } < 0 {
|
|
return -1;
|
|
}
|
|
let spec = unsafe { &*new };
|
|
let mut value = spec.it_value.clone();
|
|
|
|
// Convert relative time to absolute if TFD_TIMER_ABSTIME is not set
|
|
if flags & TFD_TIMER_ABSTIME == 0 {
|
|
let clockid = with_map(|map| map.get(&fd).copied()).unwrap_or(0);
|
|
let mut now = timespec::default();
|
|
if Sys::clock_gettime(clockid, Out::from_mut(&mut now)).is_err() {
|
|
return Err::<c_int, _>(Errno(EBADF)).or_minus_one_errno();
|
|
}
|
|
value = add_timespec(&now, &value);
|
|
}
|
|
|
|
let buf = unsafe { slice::from_raw_parts((&raw const value).cast::<u8>(), mem::size_of::<timespec>()) };
|
|
write_exact(fd, buf).map(|()| 0).or_minus_one_errno()
|
|
}
|
|
|
|
#[unsafe(no_mangle)]
|
|
pub unsafe extern "C" fn timerfd_gettime(fd: c_int, curr: *mut itimerspec) -> c_int {
|
|
if curr.is_null() {
|
|
return Err::<c_int, _>(Errno(EFAULT)).or_minus_one_errno();
|
|
}
|
|
let curr = unsafe { &mut *curr };
|
|
curr.it_interval = timespec::default();
|
|
let buf = unsafe { slice::from_raw_parts_mut((&raw mut curr.it_value).cast::<u8>(), mem::size_of::<timespec>()) };
|
|
read_exact(fd, buf).map(|()| 0).or_minus_one_errno()
|
|
}
|