Merge branch 'pthread-cond-docs' into 'master'

document functions in pthread cond

See merge request redox-os/relibc!1510
This commit is contained in:
Jeremy Soller
2026-07-03 11:35:44 -06:00
4 changed files with 218 additions and 31 deletions
+3
View File
@@ -10,6 +10,9 @@ sys_includes = ["sched.h", "time.h", "bits/pthread.h", "features.h"]
# TODO: Any better way to implement pthread_cleanup_push/pthread_cleanup_pop?
after_includes = """
// A value that shall not compare equal to any exiting thread.
#define PTHREAD_NULL (pthread_t(NULL))
#define PTHREAD_COND_INITIALIZER {0}
#define PTHREAD_MUTEX_INITIALIZER {0}
#define PTHREAD_RWLOCK_INITIALIZER {0}
+207 -26
View File
@@ -1,18 +1,52 @@
// Used design from https://www.remlab.net/op/futex-condvar.shtml
use crate::header::time::CLOCK_REALTIME;
use super::*;
use crate::{
header::{
pthread::{PTHREAD_PROCESS_PRIVATE, PTHREAD_PROCESS_SHARED, RlctMutex, e},
time::{CLOCK_REALTIME, timespec},
},
platform::types::{c_int, clockid_t, pthread_cond_t, pthread_condattr_t, pthread_mutex_t},
};
// PTHREAD_COND_INITIALIZER is defined manually in bits_pthread/cbindgen.toml
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/pthread_cond_broadcast.html>.
///
/// As a single atomic operation, determines which threads, if any, are blocked
/// on the specified condition variable `cond` and unblocks all of these
/// threads.
///
/// Has no effect if no threads are blocked on `cond`.
///
/// Upon success, returns `0`. Upon failure, an error number is returned to
/// indicate the error.
///
/// # Implementation
/// Always successful, so will never return an error number.
///
/// # Safety
/// It is undefined behaviour if `cond` is not initialized.
#[unsafe(no_mangle)]
pub unsafe extern "C" fn pthread_cond_broadcast(cond: *mut pthread_cond_t) -> c_int {
e((unsafe { &*cond.cast::<RlctCond>() }).broadcast())
}
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/pthread_cond_destroy.html>.
///
/// Destroys the given condition variable specified by `cond`.
///
/// Upon success, returns `0`. Upon failure, an error number is returned to
/// indicate the error.
///
/// # Implementation
/// Always successful, so will never return an error number.
///
/// # Safety
/// It is undefined behaviour for the following:
/// - `cond` is not initialized when calling this function.
/// - Use of `cond` after calling this function without reinitializing it.
/// - Attempting to destroy a condition variable upon which other threads are
/// currently blocked.
#[unsafe(no_mangle)]
pub unsafe extern "C" fn pthread_cond_destroy(cond: *mut pthread_cond_t) -> c_int {
// No-op
@@ -21,6 +55,20 @@ pub unsafe extern "C" fn pthread_cond_destroy(cond: *mut pthread_cond_t) -> c_in
}
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/pthread_cond_init.html>.
///
/// Initializes the condition variable referenced by `cond` with attributes
/// referenced by `attr`.
///
/// Upon success, returns `0`. Upon failure, an error number is returned to
/// indicate the error.
///
/// # Implementation
/// Always successful, so will never return an error number.
///
/// # Safety
/// It is undefined behaviour for the following:
/// - `attr` is not initialized when calling this function.
/// - `cond` has already been initialized.
#[unsafe(no_mangle)]
pub unsafe extern "C" fn pthread_cond_init(
cond: *mut pthread_cond_t,
@@ -41,38 +89,99 @@ pub unsafe extern "C" fn pthread_cond_init(
}
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/pthread_cond_signal.html>.
///
/// As a single atomic operation, determines which threads, if any, are blocked
/// on the specified condition variable `cond` and unblocks at least one of
/// these threads.
///
/// Has no effect if no threads are blocked on `cond`.
///
/// Upon success, returns `0`. Upon failure, an error number is returned to
/// indicate the error.
///
/// # Implementation
/// Always successful, so will never return an error number.
/// Identical behaviour to `pthread_cond_broadcast()`.
///
/// # Safety
/// It is undefined behaviour if `cond` is not initialized.
#[unsafe(no_mangle)]
pub unsafe extern "C" fn pthread_cond_signal(cond: *mut pthread_cond_t) -> c_int {
e((unsafe { &*cond.cast::<RlctCond>() }).signal())
}
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/pthread_cond_timedwait.html>.
///
/// Blocks on a condition variable.
///
/// Clock used for timeout depends on the clock attribute in `cond`. Defaults
/// to `CLOCK_REALTIME` if not set.
///
/// Upon success, returns `0` and the `mutex` shall have been locked and shall
/// be owned by the calling thread. Upon failure, an error number is returned
/// to indicate the error.
///
/// # Safety
/// It is undefined behaviour for the following:
/// - `cond` is uninitialized.
/// - `mutex` is uninitialized.
/// - `mutex` has not been locked by the calling thread before calling this
/// function.
#[unsafe(no_mangle)]
pub unsafe extern "C" fn pthread_cond_timedwait(
cond: *mut pthread_cond_t,
mutex: *mut pthread_mutex_t,
timeout: *const timespec,
abstime: *const timespec,
) -> c_int {
e((unsafe { &*cond.cast::<RlctCond>() })
.timedwait(unsafe { &*mutex.cast::<RlctMutex>() }, unsafe { &*timeout }))
.timedwait(unsafe { &*mutex.cast::<RlctMutex>() }, unsafe { &*abstime }))
}
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/pthread_cond_clockwait.html>.
///
/// Blocks on a condition variable.
///
/// `clock_id` determines the clock to use for the timeout specified by
/// `abstime`.
///
/// Upon success, returns `0` and the `mutex` shall have been locked and shall
/// be owned by the calling thread. Upon failure, an error number is returned
/// to indicate the error.
///
/// # Safety
/// It is undefined behaviour for the following:
/// - `cond` is uninitialized.
/// - `mutex` is uninitialized.
/// - `mutex` has not been locked by the calling thread before calling this
/// function.
#[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,
abstime: *const timespec,
) -> c_int {
e((unsafe { &*cond.cast::<RlctCond>() }).clockwait(
unsafe { &*mutex.cast::<RlctMutex>() },
unsafe { &*timeout },
unsafe { &*abstime },
clock_id,
))
}
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/pthread_cond_wait.html>.
///
/// Blocks on a condition variable.
///
/// Upon success, returns `0` and the `mutex` shall have been locked and shall
/// be owned by the calling thread. Upon failure, an error number is returned
/// to indicate the error.
///
/// # Safety
/// It is undefined behaviour for the following:
/// - `cond` is uninitialized.
/// - `mutex` is uninitialized.
/// - `mutex` has not been locked by the calling thread before calling this
/// function.
#[unsafe(no_mangle)]
pub unsafe extern "C" fn pthread_cond_wait(
cond: *mut pthread_cond_t,
@@ -82,62 +191,134 @@ pub unsafe extern "C" fn pthread_cond_wait(
}
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/pthread_condattr_destroy.html>.
///
/// Destroys a condition variable attributes object.
///
/// Upon success, returns `0`. Upon failure, an error number is returned to
/// indicated the error.
///
/// # Implementation
/// Always successful, so will never return an error number.
///
/// # Safety
/// It is undefined behaviour for the following:
/// - `attr` is uninitialized.
/// - `attr` is used after calling this function without reinitializing it.
#[unsafe(no_mangle)]
pub unsafe extern "C" fn pthread_condattr_destroy(condattr: *mut pthread_condattr_t) -> c_int {
unsafe { core::ptr::drop_in_place(condattr.cast::<RlctCondAttr>()) };
pub unsafe extern "C" fn pthread_condattr_destroy(attr: *mut pthread_condattr_t) -> c_int {
unsafe { core::ptr::drop_in_place(attr.cast::<RlctCondAttr>()) };
// No-op
0
}
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/pthread_condattr_getclock.html>.
///
/// Obtains the value of the clock attribute from the attributes object
/// referenced by `attr`.
///
/// Upon success, returns `0` and stores the value of the clock attribute of
/// `attr` into the object refereced by the `clock_id` argument. Upon failure,
/// an error number is returned to indicate the error.
///
/// # Implementation
/// Always successful, so will never return an error number.
///
/// # Safety
/// It is undefined behaviour if `attr` is uninitialized.
#[unsafe(no_mangle)]
pub unsafe extern "C" fn pthread_condattr_getclock(
condattr: *const pthread_condattr_t,
clock: *mut clockid_t,
attr: *const pthread_condattr_t,
clock_id: *mut clockid_t,
) -> c_int {
unsafe { core::ptr::write(clock, (*condattr.cast::<RlctCondAttr>()).clock) };
unsafe { core::ptr::write(clock_id, (*attr.cast::<RlctCondAttr>()).clock) };
0
}
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/pthread_condattr_getpshared.html>.
///
/// Obtains the value of the process-shared attribute from the attributes
/// object referenced by `attr`.
///
/// Upon success, returns `0` and stores the value of the process-shared
/// attribute of `attr` into the object referenced by the `pshared` parameter.
/// Upon failure, an error number is returned to indicate the error.
///
/// # Implementation
/// Always successful, so will never return an error number.
///
/// # Safety
/// It is undefined behaviour if `attr` is uninitialized.
#[unsafe(no_mangle)]
pub unsafe extern "C" fn pthread_condattr_getpshared(
condattr: *const pthread_condattr_t,
attr: *const pthread_condattr_t,
pshared: *mut c_int,
) -> c_int {
unsafe { core::ptr::write(pshared, (*condattr.cast::<RlctCondAttr>()).pshared) };
unsafe { core::ptr::write(pshared, (*attr.cast::<RlctCondAttr>()).pshared) };
0
}
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/pthread_condattr_init.html>.
///
/// Initializes a condition variable attribute object `attr` with the default
/// value for all of the attributes defined by the implementation.
///
/// Upon success, returns `0`. Upon failure, an error number is returned to
/// indicate the error.
///
/// # Implementation
/// Always successful, so will never return an error number.
///
/// # Safety
/// It is undefined behaviour if `attr` is already initialized.
#[unsafe(no_mangle)]
pub unsafe extern "C" fn pthread_condattr_init(condattr: *mut pthread_condattr_t) -> c_int {
unsafe {
condattr
.cast::<RlctCondAttr>()
.write(RlctCondAttr::default())
};
pub unsafe extern "C" fn pthread_condattr_init(attr: *mut pthread_condattr_t) -> c_int {
unsafe { attr.cast::<RlctCondAttr>().write(RlctCondAttr::default()) };
0
}
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/pthread_condattr_setclock.html>.
///
/// Sets the clock attribute in the attributes object referenced by `attr`.
/// Upon success, returns `0`. Upon failure, an error number is returned to
/// indicated the error.
///
/// # Implementation
/// Always successful, so will never return an error number.
///
/// # Safety
/// It is undefined behaviour if `attr` is uninitialized.
#[unsafe(no_mangle)]
pub unsafe extern "C" fn pthread_condattr_setclock(
condattr: *mut pthread_condattr_t,
clock: clockid_t,
attr: *mut pthread_condattr_t,
clock_id: clockid_t,
) -> c_int {
(unsafe { *condattr.cast::<RlctCondAttr>() }).clock = clock;
// TODO return EINVAL if clock_id is invalid or a CPU-time clock
(unsafe { *attr.cast::<RlctCondAttr>() }).clock = clock_id;
0
}
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/pthread_condattr_setpshared.html>.
///
/// Sets the process-shared attribute in the attributes object referenced by
/// `attr`.
///
/// Upon success, returns `0`. Upon failure, an error number is returned to
/// indicate the error.
///
/// # Safety
/// It is undefined behaviour if `attr` is uninitialized.
#[unsafe(no_mangle)]
pub unsafe extern "C" fn pthread_condattr_setpshared(
condattr: *mut pthread_condattr_t,
attr: *mut pthread_condattr_t,
pshared: c_int,
) -> c_int {
(unsafe { *condattr.cast::<RlctCondAttr>() }).pshared = pshared;
0
match pshared {
PTHREAD_PROCESS_SHARED | PTHREAD_PROCESS_PRIVATE => {
(unsafe { *attr.cast::<RlctCondAttr>() }).pshared = pshared;
0
}
_ => crate::header::errno::EINVAL,
}
}
pub(crate) type RlctCondAttr = crate::sync::cond::CondAttr;
+7 -4
View File
@@ -7,12 +7,11 @@ use core::{cell::Cell, ptr::NonNull};
use crate::{
error::Errno,
header::{sched::*, time::timespec},
header::{sched::sched_param, time::timespec},
platform::types::{
c_int, c_uchar, c_uint, c_void, clockid_t, pthread_attr_t, pthread_barrier_t,
pthread_barrierattr_t, pthread_cond_t, pthread_condattr_t, pthread_key_t, pthread_mutex_t,
pthread_mutexattr_t, pthread_once_t, pthread_rwlock_t, pthread_rwlockattr_t, pthread_t,
size_t,
pthread_barrierattr_t, pthread_key_t, pthread_mutex_t, pthread_mutexattr_t, pthread_once_t,
pthread_rwlock_t, pthread_rwlockattr_t, pthread_t, size_t,
},
pthread,
};
@@ -73,6 +72,10 @@ pub const PTHREAD_PRIO_NONE: c_int = 0;
pub const PTHREAD_PRIO_PROTECT: c_int = 0;
/// Permits a condition variable to be operated upon by any thread that has
/// access to the memory where the condition variable is allocated, even if the
/// condition variable is allocated in memory that is shared by multiple
/// processes.
pub const PTHREAD_PROCESS_SHARED: c_int = 0;
pub const PTHREAD_PROCESS_PRIVATE: c_int = 1;
+1 -1
View File
@@ -4,7 +4,7 @@ use crate::{
error::Errno,
header::{
errno::{EINVAL, ETIMEDOUT},
pthread::*,
pthread::{PTHREAD_PROCESS_PRIVATE, RlctMutex},
time::{CLOCK_MONOTONIC, CLOCK_REALTIME, timespec, timespec_realtime_to_monotonic},
},
platform::types::clockid_t,