Red Bear OS relibc baseline

From release 0.1.0 pre-patched archive.
This includes all Red Bear modifications previously maintained
as patches in local/patches/relibc/.
This commit is contained in:
Red Bear OS
2026-06-27 09:19:26 +03:00
commit 1b3e94a20d
2014 changed files with 155365 additions and 0 deletions
+23
View File
@@ -0,0 +1,23 @@
sys_includes = ["time.h"]
after_includes = """
#include <bits/timespec.h> // for itimerspec
"""
include_guard = "_SYS_TIMERFD_H"
language = "C"
style = "Tag"
no_includes = true
cpp_compat = true
[enum]
prefix_with_name = true
[export]
include = [
"TFD_CLOEXEC",
"TFD_NONBLOCK",
"TFD_TIMER_ABSTIME",
"TFD_TIMER_CANCEL_ON_SET",
]
[export.rename]
"itimerspec" = "struct itimerspec"
+89
View File
@@ -0,0 +1,89 @@
//! `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;
struct TimerState { clockid: clockid_t }
static MAP_INIT: AtomicBool = AtomicBool::new(false);
static TIMERFD_STATE: Mutex<Option<BTreeMap<c_int, TimerState>>> = Mutex::new(None);
fn with_map<R>(f: impl FnOnce(&mut BTreeMap<c_int, TimerState>) -> R) -> R {
let mut guard = TIMERFD_STATE.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: &timespec, b: &timespec) -> 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 {
if flags & !(TFD_CLOEXEC | TFD_NONBLOCK) != 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(p) => p, 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() };
with_map(|map| { map.insert(fd, TimerState { 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 {
if flags & !(TFD_TIMER_ABSTIME | TFD_TIMER_CANCEL_ON_SET) != 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();
// TFD_TIMER_CANCEL_ON_SET: flag accepted; clock-change notification requires
// kernel infrastructure not yet available. This is a bounded compatibility surface.
if flags & TFD_TIMER_ABSTIME == 0 {
let clockid = with_map(|map| map.get(&fd).map_or(0, |s| s.clockid));
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()
}