From 572c33a522f97fc6b9b9f416d20091f7302c908e Mon Sep 17 00:00:00 2001 From: auronandace Date: Fri, 3 Jul 2026 13:17:38 +0100 Subject: [PATCH] document functions in pthread cond --- src/header/pthread/cbindgen.toml | 3 + src/header/pthread/cond.rs | 233 +++++++++++++++++++++++++++---- src/header/pthread/mod.rs | 11 +- src/sync/cond.rs | 2 +- 4 files changed, 218 insertions(+), 31 deletions(-) diff --git a/src/header/pthread/cbindgen.toml b/src/header/pthread/cbindgen.toml index f48667192a..1419ad0b6e 100644 --- a/src/header/pthread/cbindgen.toml +++ b/src/header/pthread/cbindgen.toml @@ -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} diff --git a/src/header/pthread/cond.rs b/src/header/pthread/cond.rs index b22dfbcd27..42d5689279 100644 --- a/src/header/pthread/cond.rs +++ b/src/header/pthread/cond.rs @@ -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 . +/// +/// 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::() }).broadcast()) } /// See . +/// +/// 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 . +/// +/// 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 . +/// +/// 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::() }).signal()) } /// See . +/// +/// 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::() }) - .timedwait(unsafe { &*mutex.cast::() }, unsafe { &*timeout })) + .timedwait(unsafe { &*mutex.cast::() }, unsafe { &*abstime })) } /// See . +/// +/// 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::() }).clockwait( unsafe { &*mutex.cast::() }, - unsafe { &*timeout }, + unsafe { &*abstime }, clock_id, )) } /// See . +/// +/// 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 . +/// +/// 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::()) }; +pub unsafe extern "C" fn pthread_condattr_destroy(attr: *mut pthread_condattr_t) -> c_int { + unsafe { core::ptr::drop_in_place(attr.cast::()) }; // No-op 0 } /// See . +/// +/// 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::()).clock) }; + unsafe { core::ptr::write(clock_id, (*attr.cast::()).clock) }; 0 } /// See . +/// +/// 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::()).pshared) }; + unsafe { core::ptr::write(pshared, (*attr.cast::()).pshared) }; 0 } /// See . +/// +/// 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::() - .write(RlctCondAttr::default()) - }; +pub unsafe extern "C" fn pthread_condattr_init(attr: *mut pthread_condattr_t) -> c_int { + unsafe { attr.cast::().write(RlctCondAttr::default()) }; 0 } /// See . +/// +/// 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::() }).clock = clock; + // TODO return EINVAL if clock_id is invalid or a CPU-time clock + (unsafe { *attr.cast::() }).clock = clock_id; 0 } /// See . +/// +/// 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::() }).pshared = pshared; - 0 + match pshared { + PTHREAD_PROCESS_SHARED | PTHREAD_PROCESS_PRIVATE => { + (unsafe { *attr.cast::() }).pshared = pshared; + 0 + } + _ => crate::header::errno::EINVAL, + } } pub(crate) type RlctCondAttr = crate::sync::cond::CondAttr; diff --git a/src/header/pthread/mod.rs b/src/header/pthread/mod.rs index 8eea5c8827..3af191ede8 100644 --- a/src/header/pthread/mod.rs +++ b/src/header/pthread/mod.rs @@ -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; diff --git a/src/sync/cond.rs b/src/sync/cond.rs index fdc15c0fe8..fa63fef0c8 100644 --- a/src/sync/cond.rs +++ b/src/sync/cond.rs @@ -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,