Merge branch 'disentangle-timespec' into 'master'

extract timespec to a bits header

See merge request redox-os/relibc!1001
This commit is contained in:
Jeremy Soller
2026-02-12 07:52:43 -07:00
37 changed files with 168 additions and 102 deletions
+2 -2
View File
@@ -1,6 +1,6 @@
use crate::{
header::{signal::sigevent, time::timespec},
platform::types::*,
header::{bits_time::timespec, signal::sigevent},
platform::types::{c_int, c_void},
};
pub struct aiocb {
+22
View File
@@ -0,0 +1,22 @@
# POSIX header spec: https://pubs.opengroup.org/onlinepubs/9799919799/basedefs/time.h.html
#
# The time header should define timespec but multiple headers make use of it.
# This type is split out from the time header to avoid including all of time in the other headers.
#
# POSIX headers that require timespec:
# - aio.h (all functions currently unimplemented but timespec imported)
# - poll.h
# - sched.h
# - semaphore.h
# - signal.h
# - sys/select.h (not currently imported, needed for pselect, no TODO)
# - sys/stat.h
# - sys/time.h
include_guard = "_RELIBC_BITS_TIME_H"
language = "C"
style = "Tag"
no_includes = true
cpp_compat = true
[enum]
prefix_with_name = true
+71
View File
@@ -0,0 +1,71 @@
use crate::{
header::time::NANOSECONDS,
platform::types::{c_long, time_t},
};
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/basedefs/time.h.html>.
#[repr(C)]
#[derive(Clone, Copy, Default, Debug)]
pub struct timespec {
pub tv_sec: time_t,
pub tv_nsec: c_long,
}
impl timespec {
// TODO: Write test
/// similar logic with timeradd
pub fn add(base: timespec, interval: timespec) -> Option<timespec> {
let Some(delta_sec) = base.tv_sec.checked_add(interval.tv_sec) else {
return None;
};
let Some(delta_nsec) = base.tv_nsec.checked_add(interval.tv_nsec) else {
return None;
};
if delta_sec < 0 || delta_nsec < 0 {
return None;
}
Some(Self {
tv_sec: delta_sec + (delta_nsec / NANOSECONDS) as time_t,
tv_nsec: delta_nsec % NANOSECONDS,
})
}
/// similar logic with timersub
pub fn subtract(later: timespec, earlier: timespec) -> Option<timespec> {
let Some(delta_sec) = later.tv_sec.checked_sub(earlier.tv_sec) else {
return None;
};
let Some(delta_nsec) = later.tv_nsec.checked_sub(earlier.tv_nsec) else {
return None;
};
let time = if delta_nsec < 0 {
let roundup_sec = -delta_nsec / NANOSECONDS + 1;
timespec {
tv_sec: delta_sec - (roundup_sec as time_t),
tv_nsec: roundup_sec * NANOSECONDS - delta_nsec,
}
} else {
timespec {
tv_sec: delta_sec + (delta_nsec / NANOSECONDS) as time_t,
tv_nsec: delta_nsec % NANOSECONDS,
}
};
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;
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn cbindgen_stupid_alias_timespec(_: timespec) {}
+1
View File
@@ -10,6 +10,7 @@ pub mod bits_pthread;
pub mod bits_sched;
#[path = "bits_socklen-t/mod.rs"]
pub mod bits_socklen_t;
pub mod bits_time;
// complex.h implemented in C
// cpio.h implemented in C
pub mod crypt;
+2 -1
View File
@@ -10,6 +10,7 @@ use crate::{
};
use crate::header::{
bits_time::timespec,
errno::*,
netinet_in::{IPPROTO_UDP, htons, in_addr, sockaddr_in},
sys_socket::{
@@ -17,7 +18,7 @@ use crate::header::{
constants::{AF_INET, SOCK_DGRAM},
sockaddr, socklen_t,
},
time::{self, timespec},
time,
};
use super::{
+4 -1
View File
@@ -1,5 +1,8 @@
sys_includes = ["signal.h", "time.h"]
sys_includes = ["signal.h"]
include_guard = "_RELIBC_POLL_H"
after_includes = """
#include <bits/time.h> // for timespec
"""
language = "C"
style = "Tag"
no_includes = true
+1 -1
View File
@@ -7,6 +7,7 @@ use core::{mem, ptr, slice};
use crate::{
fs::File,
header::{
bits_time::timespec,
errno::EBADF,
signal::sigset_t,
sys_epoll::{
@@ -14,7 +15,6 @@ use crate::{
EPOLLPRI, EPOLLRDBAND, EPOLLRDNORM, EPOLLWRBAND, EPOLLWRNORM, epoll_create1, epoll_ctl,
epoll_data, epoll_event, epoll_pwait,
},
time::timespec,
},
platform::{
self,
+1 -1
View File
@@ -6,8 +6,8 @@ no_includes = true
cpp_compat = true
[export.rename]
"sched_param" = "struct sched_param"
"timespec" = "struct timespec"
"sched_param" = "struct sched_param"
[enum]
prefix_with_name = true
+1 -1
View File
@@ -7,7 +7,7 @@ use core::{cell::Cell, ptr::NonNull};
use crate::{
error::Errno,
header::{sched::*, time::timespec},
header::{bits_time::timespec, sched::*},
platform::{
Pal, Sys,
types::{
+7 -1
View File
@@ -1,5 +1,8 @@
sys_includes = ["time.h", "bits/sched.h"]
sys_includes = ["sys/types.h", "bits/sched.h"]
include_guard = "_RELIBC_SCHED_H"
after_includes = """
#include <bits/time.h> // for timespec
"""
language = "C"
style = "Tag"
no_includes = true
@@ -7,3 +10,6 @@ cpp_compat = true
[enum]
prefix_with_name = true
[export.rename]
"timespec" = "struct timespec"
+1 -1
View File
@@ -4,7 +4,7 @@
use crate::{
error::ResultExt,
header::time::timespec,
header::bits_time::timespec,
platform::{
Pal, Sys,
types::{c_int, pid_t},
+4 -1
View File
@@ -1,5 +1,8 @@
sys_includes = ["time.h"]
sys_includes = []
include_guard = "_RELIBC_SEMAPHORE_H"
after_includes = """
#include <bits/time.h> // for timespec
"""
language = "C"
style = "Type"
no_includes = true
+4 -1
View File
@@ -3,7 +3,10 @@
//! See <https://pubs.opengroup.org/onlinepubs/9799919799/basedefs/semaphore.h.html>.
use crate::{
header::time::{CLOCK_MONOTONIC, CLOCK_REALTIME, timespec},
header::{
bits_time::timespec,
time::{CLOCK_MONOTONIC, CLOCK_REALTIME},
},
platform::types::{c_char, c_int, c_long, c_uint, clockid_t},
};
+6 -3
View File
@@ -1,6 +1,9 @@
sys_includes = ["bits/signal.h", "stdint.h", "sys/types.h", "time.h", "bits/pthread.h", "features.h"]
sys_includes = ["bits/signal.h", "stdint.h", "sys/types.h", "bits/pthread.h", "features.h"]
include_guard = "_RELIBC_SIGNAL_H"
trailer = "#include <bits/signal.h>"
after_includes = """
#include <bits/time.h> // for timespec
#include <bits/signal.h>
"""
language = "C"
style = "Tag"
no_includes = true
@@ -10,5 +13,5 @@ cpp_compat = true
prefix_with_name = true
[export.rename]
"timespec" = "struct timespec"
"sigaction" = "struct sigaction"
"timespec" = "struct timespec"
+1 -1
View File
@@ -8,7 +8,7 @@ use cbitset::BitSet;
use crate::{
error::{Errno, ResultExt},
header::{errno, setjmp, time::timespec},
header::{bits_time::timespec, errno, setjmp},
platform::{
self, ERRNO, Pal, PalSignal, Sys,
types::{
+5 -2
View File
@@ -1,6 +1,9 @@
sys_includes = ["sys/types.h", "time.h"]
sys_includes = ["sys/types.h"]
include_guard = "_SYS_STAT_H"
trailer = "#include <bits/sys/stat.h>"
after_includes = """
#include <bits/time.h> // for timespec
#include <bits/sys/stat.h>
"""
language = "C"
style = "Tag"
no_includes = true
+1 -1
View File
@@ -6,8 +6,8 @@ use crate::{
c_str::CStr,
error::ResultExt,
header::{
bits_time::timespec,
fcntl::{O_NOFOLLOW, O_PATH},
time::timespec,
},
out::Out,
platform::{
+5 -1
View File
@@ -1,7 +1,10 @@
sys_includes = ["sys/types.h", "features.h", "sys/select.h"]
include_guard = "_SYS_TIME_H"
language = "C"
trailer = "#include <bits/sys/time.h>"
after_includes = """
#include <bits/time.h> // for timespec
#include <bits/sys/time.h>
"""
style = "Tag"
no_includes = true
cpp_compat = true
@@ -10,4 +13,5 @@ cpp_compat = true
prefix_with_name = true
[export.rename]
"timespec" = "struct timespec"
"timeval" = "struct timeval"
+1 -1
View File
@@ -5,7 +5,7 @@
use crate::{
c_str::CStr,
error::ResultExt,
header::{sys_select::timeval, time::timespec},
header::{bits_time::timespec, sys_select::timeval},
out::Out,
platform::{
Pal, PalSignal, Sys,
+2
View File
@@ -5,6 +5,7 @@ style = "Tag"
no_includes = true
cpp_compat = true
after_includes = """
#include <bits/time.h> // for timespec
struct sigevent;
"""
@@ -12,4 +13,5 @@ struct sigevent;
prefix_with_name = true
[export.rename]
"timespec" = "struct timespec"
"sigevent" = "struct sigevent"
+3 -66
View File
@@ -6,6 +6,7 @@ use crate::{
c_str::{CStr, CString},
error::{Errno, ResultExt},
header::{
bits_time::timespec,
errno::{EFAULT, ENOMEM, EOVERFLOW, ETIMEDOUT},
signal::sigevent,
stdlib::getenv,
@@ -26,7 +27,7 @@ use chrono::{
offset::MappedLocalTime,
};
use chrono_tz::{OffsetComponents, OffsetName, Tz};
use core::{cell::OnceCell, convert::TryFrom, fmt::Debug, mem, ptr};
use core::{cell::OnceCell, convert::TryFrom, mem, ptr};
pub use self::constants::*;
@@ -39,73 +40,9 @@ pub use strptime::strptime;
const YEARS_PER_ERA: time_t = 400;
const DAYS_PER_ERA: time_t = 146097;
const SECS_PER_DAY: time_t = 24 * 60 * 60;
const NANOSECONDS: c_long = 1_000_000_000;
pub(crate) const NANOSECONDS: c_long = 1_000_000_000;
const UTC_STR: &core::ffi::CStr = c"UTC";
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/basedefs/time.h.html>.
#[repr(C)]
#[derive(Clone, Copy, Default, Debug)]
pub struct timespec {
pub tv_sec: time_t,
pub tv_nsec: c_long,
}
impl timespec {
// TODO: Write test
/// similar logic with timeradd
pub fn add(base: timespec, interval: timespec) -> Option<timespec> {
let Some(delta_sec) = base.tv_sec.checked_add(interval.tv_sec) else {
return None;
};
let Some(delta_nsec) = base.tv_nsec.checked_add(interval.tv_nsec) else {
return None;
};
if delta_sec < 0 || delta_nsec < 0 {
return None;
}
Some(Self {
tv_sec: delta_sec + (delta_nsec / NANOSECONDS) as time_t,
tv_nsec: delta_nsec % NANOSECONDS,
})
}
/// similar logic with timersub
pub fn subtract(later: timespec, earlier: timespec) -> Option<timespec> {
let Some(delta_sec) = later.tv_sec.checked_sub(earlier.tv_sec) else {
return None;
};
let Some(delta_nsec) = later.tv_nsec.checked_sub(earlier.tv_nsec) else {
return None;
};
let time = if delta_nsec < 0 {
let roundup_sec = -delta_nsec / NANOSECONDS + 1;
timespec {
tv_sec: delta_sec - (roundup_sec as time_t),
tv_nsec: roundup_sec * NANOSECONDS - delta_nsec,
}
} else {
timespec {
tv_sec: delta_sec + (delta_nsec / NANOSECONDS) as time_t,
tv_nsec: delta_nsec % NANOSECONDS,
}
};
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;
}
}
#[cfg(target_os = "redox")]
impl<'a> From<&'a timespec> for syscall::TimeSpec {
fn from(tp: &timespec) -> Self {
+1 -1
View File
@@ -13,6 +13,7 @@ use crate::{
c_str::CStr,
error::{Errno, ResultExt},
header::{
bits_time::timespec,
crypt::{crypt_data, crypt_r},
errno::{self, ENAMETOOLONG},
fcntl, limits,
@@ -20,7 +21,6 @@ use crate::{
sys_ioctl, sys_resource,
sys_select::timeval,
sys_time, sys_utsname, termios,
time::timespec,
},
out::Out,
platform::{
+1 -1
View File
@@ -8,7 +8,7 @@
use crate::{
c_str::CStr,
error::ResultExt,
header::time::timespec,
header::bits_time::timespec,
platform::{
Pal, Sys,
types::{c_char, c_int, time_t},
+1 -1
View File
@@ -24,7 +24,7 @@ use core::{num::NonZeroU64, ptr};
// use header::sys_times::tms;
use crate::{
error::{Errno, Result},
header::{sys_utsname::utsname, time::timespec},
header::{bits_time::timespec, sys_utsname::utsname},
};
mod epoll;
+1 -1
View File
@@ -8,9 +8,9 @@ use super::{
use crate::{
error::{Errno, Result},
header::{
bits_time::timespec,
signal::{SA_RESTORER, SI_QUEUE, sigaction, siginfo_t, sigset_t, stack_t},
sys_time::itimerval,
time::timespec,
},
};
+2 -1
View File
@@ -5,6 +5,7 @@ use crate::{
c_str::CStr,
error::{Errno, Result},
header::{
bits_time::timespec,
signal::sigevent,
sys_resource::{rlimit, rusage},
sys_select::timeval,
@@ -12,7 +13,7 @@ use crate::{
sys_statvfs::statvfs,
sys_time::timezone,
sys_utsname::utsname,
time::{itimerspec, timespec},
time::itimerspec,
},
ld_so::tcb::OsSpecific,
out::Out,
+1 -1
View File
@@ -2,9 +2,9 @@ use super::super::{Pal, types::*};
use crate::{
error::{Errno, Result},
header::{
bits_time::timespec,
signal::{sigaction, siginfo_t, sigset_t, sigval, stack_t},
sys_time::itimerval,
time::timespec,
},
};
+1 -1
View File
@@ -1,9 +1,9 @@
use core::mem::size_of;
use crate::header::{
bits_time::timespec,
fcntl::{O_CLOEXEC, O_CREAT, O_RDWR},
signal::sigset_t,
time::timespec,
};
use super::libredox::RawResult;
+1 -1
View File
@@ -10,7 +10,7 @@ use syscall::{EMFILE, Error, Result};
use crate::{
header::{
errno::EINVAL, signal::sigaction, sys_stat::UTIME_NOW, sys_uio::iovec, time::timespec,
bits_time::timespec, errno::EINVAL, signal::sigaction, sys_stat::UTIME_NOW, sys_uio::iovec,
},
out::Out,
platform::{PalSignal, types::*},
+2 -1
View File
@@ -25,6 +25,7 @@ use crate::{
error::{Errno, Result},
fs::File,
header::{
bits_time::timespec,
errno::{
EBADF, EBADFD, EBADR, EEXIST, EFAULT, EFBIG, EINTR, EINVAL, EIO, ENAMETOOLONG, ENOENT,
ENOMEM, ENOSYS, EOPNOTSUPP, EPERM, ERANGE,
@@ -43,7 +44,7 @@ use crate::{
sys_statvfs::statvfs,
sys_time::timezone,
sys_utsname::{UTSLENGTH, utsname},
time::{TIMER_ABSTIME, itimerspec, timer_internal_t, timespec},
time::{TIMER_ABSTIME, itimerspec, timer_internal_t},
unistd::{F_OK, R_OK, SEEK_CUR, SEEK_SET, W_OK, X_OK},
},
io::{self, BufReader, prelude::*},
+1 -1
View File
@@ -5,13 +5,13 @@ use super::{
use crate::{
error::{Errno, Result},
header::{
bits_time::timespec,
errno::{EINVAL, ENOSYS},
signal::{
SIG_BLOCK, SIG_DFL, SIG_IGN, SIG_SETMASK, SIG_UNBLOCK, SS_DISABLE, SS_ONSTACK,
sigaction, siginfo_t, sigset_t, sigval, stack_t, ucontext_t,
},
sys_time::{ITIMER_REAL, itimerval},
time::timespec,
},
};
use core::mem::offset_of;
+2 -1
View File
@@ -3,9 +3,10 @@ use syscall::Error;
use crate::{
error::{Errno, Result},
header::{
bits_time::timespec,
errno::EIO,
signal::{SIGEV_SIGNAL, SIGEV_THREAD},
time::{timer_internal_t, timespec},
time::timer_internal_t,
},
out::Out,
platform::{Pal, Sys, sys::event, types::c_void},
+2 -1
View File
@@ -3,9 +3,10 @@
use crate::{
error::Errno,
header::{
bits_time::timespec,
errno::{EINVAL, ETIMEDOUT},
pthread::*,
time::{CLOCK_MONOTONIC, CLOCK_REALTIME, timespec, timespec_realtime_to_monotonic},
time::{CLOCK_MONOTONIC, CLOCK_REALTIME, timespec_realtime_to_monotonic},
},
platform::types::clockid_t,
};
+1 -1
View File
@@ -20,8 +20,8 @@ pub use self::{
use crate::{
error::Errno,
header::{
bits_time::timespec,
errno::{EAGAIN, EINTR, ETIMEDOUT},
time::timespec,
},
out::Out,
platform::{Pal, Sys, types::c_int},
+1 -1
View File
@@ -5,7 +5,7 @@ use core::{
use crate::{
error::Errno,
header::{errno::*, pthread::*, time::timespec},
header::{bits_time::timespec, errno::*, pthread::*},
};
use crate::platform::{Pal, Sys, types::c_int};
+1 -1
View File
@@ -4,7 +4,7 @@ use core::{
sync::atomic::{AtomicU32, Ordering},
};
use crate::{header::time::timespec, pthread::Pshared};
use crate::{header::bits_time::timespec, pthread::Pshared};
pub struct InnerRwLock {
state: AtomicU32,
+4 -1
View File
@@ -2,7 +2,10 @@
//TODO: improve implementation
use crate::{
header::time::{CLOCK_MONOTONIC, CLOCK_REALTIME, timespec, timespec_realtime_to_monotonic},
header::{
bits_time::timespec,
time::{CLOCK_MONOTONIC, CLOCK_REALTIME, timespec_realtime_to_monotonic},
},
platform::types::{c_uint, clockid_t},
};