Implement pthread_cond_timedwait futex properly

This commit is contained in:
Wildan M
2026-01-06 15:33:58 +07:00
parent 3eeaf4eb22
commit 242ed32b42
5 changed files with 243 additions and 69 deletions
+24 -23
View File
@@ -24,7 +24,6 @@ use crate::{
},
sync::{Mutex, MutexGuard},
};
use __libc_only_for_layout_checks::EINVAL;
use alloc::{boxed::Box, collections::BTreeSet, string::String, vec::Vec};
use chrono::{
DateTime, Datelike, FixedOffset, NaiveDate, NaiveDateTime, Offset, ParseError, TimeZone,
@@ -34,6 +33,7 @@ use chrono_tz::{OffsetComponents, OffsetName, Tz};
use core::{
cell::OnceCell,
convert::{TryFrom, TryInto},
fmt::Debug,
mem, ptr,
};
@@ -48,11 +48,12 @@ 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: i64 = 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)]
#[derive(Clone, Copy, Default, Debug)]
pub struct timespec {
pub tv_sec: time_t,
pub tv_nsec: c_long,
@@ -60,36 +61,36 @@ 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,
}
/// similar logic with timeradd
pub fn add(base: timespec, interval: timespec) -> Option<timespec> {
let delta_sec = base.tv_sec + interval.tv_sec;
let delta_nsec = base.tv_nsec + interval.tv_nsec;
if delta_sec < 0 || delta_nsec < 0 {
return None;
}
Some(Self {
tv_sec: delta_sec + (delta_nsec / NANOSECONDS),
tv_nsec: delta_nsec % NANOSECONDS,
})
}
// TODO: Write test
/// similar logic with timersub
pub fn subtract(later: timespec, earlier: timespec) -> Option<timespec> {
let later_nsec = c_ulong::try_from(later.tv_nsec).ok()?;
let earlier_nsec = c_ulong::try_from(earlier.tv_nsec).ok()?;
let delta_sec = later.tv_sec - earlier.tv_sec;
let delta_nsec = later.tv_nsec - earlier.tv_nsec;
let time = if later_nsec > earlier_nsec {
let time = if delta_nsec < 0 {
let roundup_sec = -delta_nsec / NANOSECONDS + 1;
timespec {
tv_sec: later.tv_sec.checked_sub(earlier.tv_sec)?,
tv_nsec: (later_nsec - earlier_nsec) as _,
tv_sec: delta_sec - roundup_sec,
tv_nsec: roundup_sec * NANOSECONDS - delta_nsec,
}
} else {
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,
tv_sec: delta_sec + (delta_nsec / NANOSECONDS),
tv_nsec: delta_nsec % NANOSECONDS,
}
};