Implement pthread_cond_timedwait futex properly
This commit is contained in:
+25
-16
@@ -1,5 +1,7 @@
|
||||
// Used design from https://www.remlab.net/op/futex-condvar.shtml
|
||||
|
||||
use crate::header::time::CLOCK_REALTIME;
|
||||
|
||||
use super::*;
|
||||
|
||||
// PTHREAD_COND_INITIALIZER is defined manually in bits_pthread/cbindgen.toml
|
||||
@@ -19,8 +21,19 @@ pub unsafe extern "C" fn pthread_cond_destroy(cond: *mut pthread_cond_t) -> c_in
|
||||
#[unsafe(no_mangle)]
|
||||
pub unsafe extern "C" fn pthread_cond_init(
|
||||
cond: *mut pthread_cond_t,
|
||||
_attr: *const pthread_condattr_t,
|
||||
attr: *const pthread_condattr_t,
|
||||
) -> c_int {
|
||||
let attr = attr
|
||||
.cast::<RlctCondAttr>()
|
||||
.as_ref()
|
||||
.copied()
|
||||
.unwrap_or_default();
|
||||
|
||||
if attr.clock != CLOCK_REALTIME {
|
||||
// As monotonic clock always smaller than realtime clock, this always result in instant timeout.
|
||||
println!("TODO: pthread_cond_init with monotonic clock");
|
||||
}
|
||||
|
||||
cond.cast::<RlctCond>().write(RlctCond::new());
|
||||
|
||||
0
|
||||
@@ -40,6 +53,16 @@ pub unsafe extern "C" fn pthread_cond_timedwait(
|
||||
e((&*cond.cast::<RlctCond>()).timedwait(&*mutex.cast::<RlctMutex>(), &*timeout))
|
||||
}
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
pub unsafe extern "C" fn pthread_cond_clockwait(
|
||||
cond: *mut pthread_cond_t,
|
||||
mutex: *mut pthread_mutex_t,
|
||||
clock_id: clockid_t,
|
||||
timeout: *const timespec,
|
||||
) -> c_int {
|
||||
e((&*cond.cast::<RlctCond>()).clockwait(&*mutex.cast::<RlctMutex>(), &*timeout, clock_id))
|
||||
}
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
pub unsafe extern "C" fn pthread_cond_wait(
|
||||
cond: *mut pthread_cond_t,
|
||||
@@ -100,20 +123,6 @@ pub unsafe extern "C" fn pthread_condattr_setpshared(
|
||||
0
|
||||
}
|
||||
|
||||
pub(crate) struct RlctCondAttr {
|
||||
clock: clockid_t,
|
||||
pshared: c_int,
|
||||
}
|
||||
pub(crate) type RlctCondAttr = crate::sync::cond::CondAttr;
|
||||
|
||||
pub(crate) type RlctCond = crate::sync::cond::Cond;
|
||||
|
||||
impl Default for RlctCondAttr {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
// FIXME: system clock
|
||||
clock: 0,
|
||||
// Default
|
||||
pshared: PTHREAD_PROCESS_PRIVATE,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+24
-23
@@ -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,
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user