From 0d702f34d726a9f9daedf45302e7086a16415fac Mon Sep 17 00:00:00 2001 From: Chris Friedt Date: Wed, 23 Apr 2025 08:44:27 -0400 Subject: [PATCH 01/13] tests: posix: pthread: correct cases for pthread_timedjoin_np() pthread_timedjoin_np() is allowed to take a negative tv_sec parameter, since that is still a valid timespec. Signed-off-by: Chris Friedt --- tests/posix/common/src/pthread.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/tests/posix/common/src/pthread.c b/tests/posix/common/src/pthread.c index 3801d3b41862c..035730ee4dc73 100644 --- a/tests/posix/common/src/pthread.c +++ b/tests/posix/common/src/pthread.c @@ -404,9 +404,8 @@ ZTEST(pthread, test_pthread_timedjoin) struct timespec not_done; struct timespec done; struct timespec invalid[] = { - [0] = {.tv_sec = -1}, - [1] = {.tv_nsec = -1}, - [2] = {.tv_nsec = NSEC_PER_SEC}, + {.tv_nsec = -1}, + {.tv_nsec = NSEC_PER_SEC}, }; /* setup timespecs when the thread is still running and when it is done */ @@ -426,7 +425,7 @@ ZTEST(pthread, test_pthread_timedjoin) /* Creating a thread that exits after 200ms*/ zassert_ok(pthread_create(&th, NULL, timedjoin_thread, INT_TO_POINTER(sleep_duration_ms))); - /* pthread_timedjoin-np must return -EINVAL for invalid struct timespecs */ + /* pthread_timedjoin-np must return EINVAL for invalid struct timespecs */ zassert_equal(pthread_timedjoin_np(th, &ret, NULL), EINVAL); for (size_t i = 0; i < ARRAY_SIZE(invalid); ++i) { zassert_equal(pthread_timedjoin_np(th, &ret, &invalid[i]), EINVAL); From 88a2cc17a113a7ce503f97997e34e6ed56772edb Mon Sep 17 00:00:00 2001 From: Chris Friedt Date: Wed, 23 Apr 2025 06:11:10 -0400 Subject: [PATCH 02/13] posix: declare timespec_to_timeoutms() in posix_clock.h Provide a single declaration of timespec_to_timeoutms() (which is a private function), in the private header file posix_clock.h . Signed-off-by: Chris Friedt --- lib/posix/options/cond.c | 4 +--- lib/posix/options/mqueue.c | 10 +++++----- lib/posix/options/mutex.c | 6 ++---- lib/posix/options/posix_clock.h | 5 +++-- lib/posix/options/pthread.c | 2 +- lib/posix/options/rwlock.c | 20 +++++++------------- lib/posix/options/timespec_to_timeout.c | 4 +++- 7 files changed, 22 insertions(+), 29 deletions(-) diff --git a/lib/posix/options/cond.c b/lib/posix/options/cond.c index 8155b993fcc22..da7c526399141 100644 --- a/lib/posix/options/cond.c +++ b/lib/posix/options/cond.c @@ -15,8 +15,6 @@ LOG_MODULE_REGISTER(pthread_cond, CONFIG_PTHREAD_COND_LOG_LEVEL); -int64_t timespec_to_timeoutms(const struct timespec *abstime); - __pinned_bss static struct k_condvar posix_cond_pool[CONFIG_MAX_PTHREAD_COND_COUNT]; @@ -168,7 +166,7 @@ int pthread_cond_wait(pthread_cond_t *cv, pthread_mutex_t *mut) int pthread_cond_timedwait(pthread_cond_t *cv, pthread_mutex_t *mut, const struct timespec *abstime) { - return cond_wait(cv, mut, K_MSEC((int32_t)timespec_to_timeoutms(abstime))); + return cond_wait(cv, mut, K_MSEC(timespec_to_timeoutms(abstime))); } int pthread_cond_init(pthread_cond_t *cvar, const pthread_condattr_t *att) diff --git a/lib/posix/options/mqueue.c b/lib/posix/options/mqueue.c index 12bbf30d0ab5e..99966786a0b28 100644 --- a/lib/posix/options/mqueue.c +++ b/lib/posix/options/mqueue.c @@ -4,6 +4,9 @@ * * SPDX-License-Identifier: Apache-2.0 */ + +#include "posix_clock.h" + #include #include #include @@ -34,7 +37,6 @@ K_SEM_DEFINE(mq_sem, 1, 1); /* Initialize the list */ sys_slist_t mq_list = SYS_SLIST_STATIC_INIT(&mq_list); -int64_t timespec_to_timeoutms(const struct timespec *abstime); static mqueue_object *find_in_list(const char *name); static int32_t send_message(mqueue_desc *mqd, const char *msg_ptr, size_t msg_len, k_timeout_t timeout); @@ -255,9 +257,8 @@ int mq_timedsend(mqd_t mqdes, const char *msg_ptr, size_t msg_len, unsigned int msg_prio, const struct timespec *abstime) { mqueue_desc *mqd = (mqueue_desc *)mqdes; - int32_t timeout = (int32_t) timespec_to_timeoutms(abstime); - return send_message(mqd, msg_ptr, msg_len, K_MSEC(timeout)); + return send_message(mqd, msg_ptr, msg_len, K_MSEC(timespec_to_timeoutms(abstime))); } /** @@ -286,9 +287,8 @@ int mq_timedreceive(mqd_t mqdes, char *msg_ptr, size_t msg_len, unsigned int *msg_prio, const struct timespec *abstime) { mqueue_desc *mqd = (mqueue_desc *)mqdes; - int32_t timeout = (int32_t) timespec_to_timeoutms(abstime); - return receive_message(mqd, msg_ptr, msg_len, K_MSEC(timeout)); + return receive_message(mqd, msg_ptr, msg_len, K_MSEC(timespec_to_timeoutms(abstime))); } /** diff --git a/lib/posix/options/mutex.c b/lib/posix/options/mutex.c index d6a54fd36d561..d61458d1e4392 100644 --- a/lib/posix/options/mutex.c +++ b/lib/posix/options/mutex.c @@ -5,6 +5,7 @@ * SPDX-License-Identifier: Apache-2.0 */ +#include "posix_clock.h" #include "posix_internal.h" #include @@ -18,8 +19,6 @@ LOG_MODULE_REGISTER(pthread_mutex, CONFIG_PTHREAD_MUTEX_LOG_LEVEL); static SYS_SEM_DEFINE(lock, 1, 1); -int64_t timespec_to_timeoutms(const struct timespec *abstime); - #define MUTEX_MAX_REC_LOCK 32767 /* @@ -212,8 +211,7 @@ int pthread_mutex_trylock(pthread_mutex_t *m) int pthread_mutex_timedlock(pthread_mutex_t *m, const struct timespec *abstime) { - int32_t timeout = (int32_t)timespec_to_timeoutms(abstime); - return acquire_mutex(m, K_MSEC(timeout)); + return acquire_mutex(m, K_MSEC(timespec_to_timeoutms(abstime))); } /** diff --git a/lib/posix/options/posix_clock.h b/lib/posix/options/posix_clock.h index f505dbc175271..129a797e4f08c 100644 --- a/lib/posix/options/posix_clock.h +++ b/lib/posix/options/posix_clock.h @@ -1,5 +1,6 @@ /* * Copyright (c) 2023, Meta + * Copyright (c) 2025 Tenstorrent AI ULC * * SPDX-License-Identifier: Apache-2.0 */ @@ -7,10 +8,10 @@ #ifndef ZEPHYR_LIB_POSIX_POSIX_CLOCK_H_ #define ZEPHYR_LIB_POSIX_POSIX_CLOCK_H_ +#include #include -#include -#include +uint32_t timespec_to_timeoutms(const struct timespec *abstime); __syscall int __posix_clock_get_base(clockid_t clock_id, struct timespec *ts); diff --git a/lib/posix/options/pthread.c b/lib/posix/options/pthread.c index 398951307aa7e..db0ec7ec8c517 100644 --- a/lib/posix/options/pthread.c +++ b/lib/posix/options/pthread.c @@ -5,6 +5,7 @@ * SPDX-License-Identifier: Apache-2.0 */ +#include "posix_clock.h" #include "posix_internal.h" #include "pthread_sched.h" @@ -81,7 +82,6 @@ BUILD_ASSERT((PTHREAD_CANCEL_ENABLE == 0 || PTHREAD_CANCEL_DISABLE == 0) && BUILD_ASSERT(CONFIG_POSIX_PTHREAD_ATTR_STACKSIZE_BITS + CONFIG_POSIX_PTHREAD_ATTR_GUARDSIZE_BITS <= 32); -int64_t timespec_to_timeoutms(const struct timespec *abstime); static void posix_thread_recycle(void); __pinned_data diff --git a/lib/posix/options/rwlock.c b/lib/posix/options/rwlock.c index fab35ec84a233..84133859e862a 100644 --- a/lib/posix/options/rwlock.c +++ b/lib/posix/options/rwlock.c @@ -4,6 +4,7 @@ * SPDX-License-Identifier: Apache-2.0 */ +#include "posix_clock.h" #include "posix_internal.h" #include @@ -27,9 +28,8 @@ struct posix_rwlockattr { bool pshared: 1; }; -int64_t timespec_to_timeoutms(const struct timespec *abstime); -static uint32_t read_lock_acquire(struct posix_rwlock *rwl, int32_t timeout); -static uint32_t write_lock_acquire(struct posix_rwlock *rwl, int32_t timeout); +static uint32_t read_lock_acquire(struct posix_rwlock *rwl, uint32_t timeout); +static uint32_t write_lock_acquire(struct posix_rwlock *rwl, uint32_t timeout); LOG_MODULE_REGISTER(pthread_rwlock, CONFIG_PTHREAD_RWLOCK_LOG_LEVEL); @@ -198,7 +198,6 @@ int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock) int pthread_rwlock_timedrdlock(pthread_rwlock_t *rwlock, const struct timespec *abstime) { - int32_t timeout; uint32_t ret = 0U; struct posix_rwlock *rwl; @@ -206,14 +205,12 @@ int pthread_rwlock_timedrdlock(pthread_rwlock_t *rwlock, return EINVAL; } - timeout = (int32_t) timespec_to_timeoutms(abstime); - rwl = get_posix_rwlock(*rwlock); if (rwl == NULL) { return EINVAL; } - if (read_lock_acquire(rwl, timeout) != 0U) { + if (read_lock_acquire(rwl, timespec_to_timeoutms(abstime)) != 0U) { ret = ETIMEDOUT; } @@ -271,7 +268,6 @@ int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock) int pthread_rwlock_timedwrlock(pthread_rwlock_t *rwlock, const struct timespec *abstime) { - int32_t timeout; uint32_t ret = 0U; struct posix_rwlock *rwl; @@ -279,14 +275,12 @@ int pthread_rwlock_timedwrlock(pthread_rwlock_t *rwlock, return EINVAL; } - timeout = (int32_t) timespec_to_timeoutms(abstime); - rwl = get_posix_rwlock(*rwlock); if (rwl == NULL) { return EINVAL; } - if (write_lock_acquire(rwl, timeout) != 0U) { + if (write_lock_acquire(rwl, timespec_to_timeoutms(abstime)) != 0U) { ret = ETIMEDOUT; } @@ -345,7 +339,7 @@ int pthread_rwlock_unlock(pthread_rwlock_t *rwlock) return 0; } -static uint32_t read_lock_acquire(struct posix_rwlock *rwl, int32_t timeout) +static uint32_t read_lock_acquire(struct posix_rwlock *rwl, uint32_t timeout) { uint32_t ret = 0U; @@ -360,7 +354,7 @@ static uint32_t read_lock_acquire(struct posix_rwlock *rwl, int32_t timeout) return ret; } -static uint32_t write_lock_acquire(struct posix_rwlock *rwl, int32_t timeout) +static uint32_t write_lock_acquire(struct posix_rwlock *rwl, uint32_t timeout) { uint32_t ret = 0U; int64_t elapsed_time, st_time = k_uptime_get(); diff --git a/lib/posix/options/timespec_to_timeout.c b/lib/posix/options/timespec_to_timeout.c index e72956e6e3e93..063a511a4e7d2 100644 --- a/lib/posix/options/timespec_to_timeout.c +++ b/lib/posix/options/timespec_to_timeout.c @@ -4,11 +4,13 @@ * SPDX-License-Identifier: Apache-2.0 */ +#include "posix_clock.h" + #include #include #include -int64_t timespec_to_timeoutms(const struct timespec *abstime) +uint32_t timespec_to_timeoutms(const struct timespec *abstime) { int64_t milli_secs, secs, nsecs; struct timespec curtime; From 3d992490dcf28c2d9c607cc8b68f91f38e234b99 Mon Sep 17 00:00:00 2001 From: Chris Friedt Date: Wed, 23 Apr 2025 07:00:37 -0400 Subject: [PATCH 03/13] posix: provide timespec_to_clock_timeoutms Provide a private internal function timespec_to_clock_timeoutms() to complement timespec_to_timeoutms(). This new variant accepts a clock_t parameter that allows the caller to specify which clock to use. The original timespec_to_timeoutms() then just becomes a static inline wrapper around the original. Note: timespec_to_clock_timeoutms() and timespec_to_timeoutms() might have a limited lifespan, since it might make sense to create a common timespec manipulation library. Signed-off-by: Chris Friedt --- lib/posix/options/posix_clock.h | 1 + lib/posix/options/timespec_to_timeout.c | 13 +++++++------ 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/lib/posix/options/posix_clock.h b/lib/posix/options/posix_clock.h index 129a797e4f08c..18fe562ec4dc9 100644 --- a/lib/posix/options/posix_clock.h +++ b/lib/posix/options/posix_clock.h @@ -11,6 +11,7 @@ #include #include +uint32_t timespec_to_clock_timeoutms(clockid_t clock_id, const struct timespec *abstime); uint32_t timespec_to_timeoutms(const struct timespec *abstime); __syscall int __posix_clock_get_base(clockid_t clock_id, struct timespec *ts); diff --git a/lib/posix/options/timespec_to_timeout.c b/lib/posix/options/timespec_to_timeout.c index 063a511a4e7d2..a3373a9a7bfcc 100644 --- a/lib/posix/options/timespec_to_timeout.c +++ b/lib/posix/options/timespec_to_timeout.c @@ -10,16 +10,12 @@ #include #include -uint32_t timespec_to_timeoutms(const struct timespec *abstime) +uint32_t timespec_to_clock_timeoutms(clockid_t clock_id, const struct timespec *abstime) { int64_t milli_secs, secs, nsecs; struct timespec curtime; - /* FIXME: Zephyr does have CLOCK_REALTIME to get time. - * As per POSIX standard time should be calculated wrt CLOCK_REALTIME. - * Zephyr deviates from POSIX 1003.1 standard on this aspect. - */ - clock_gettime(CLOCK_MONOTONIC, &curtime); + clock_gettime(clock_id, &curtime); secs = abstime->tv_sec - curtime.tv_sec; nsecs = abstime->tv_nsec - curtime.tv_nsec; @@ -31,3 +27,8 @@ uint32_t timespec_to_timeoutms(const struct timespec *abstime) return milli_secs; } + +uint32_t timespec_to_timeoutms(const struct timespec *abstime) +{ + return timespec_to_clock_timeoutms(CLOCK_MONOTONIC, abstime); +} From a73da15c3aacfb698176b996692211d689dd8c52 Mon Sep 17 00:00:00 2001 From: Chris Friedt Date: Wed, 23 Apr 2025 05:12:54 -0400 Subject: [PATCH 04/13] posix: posix_internal: add definitions for posix_condattr, posix_cond Add definitions for struct posix_condattr and struct posix_cond, which are internal variants of the external pthread_condattr_t and pthread_cond_t types. Signed-off-by: Chris Friedt --- lib/posix/options/posix_internal.h | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/lib/posix/options/posix_internal.h b/lib/posix/options/posix_internal.h index 24bfb83e14b7e..3a4804d0ee4f3 100644 --- a/lib/posix/options/posix_internal.h +++ b/lib/posix/options/posix_internal.h @@ -66,6 +66,20 @@ struct posix_thread { uint8_t qid; }; +struct posix_condattr { + /* leaves room for CLOCK_REALTIME (1, default) and CLOCK_MONOTONIC (4) */ + unsigned int clock: 3; + bool initialized: 1; +#ifdef _POSIX_THREAD_PROCESS_SHARED + unsigned int pshared: 1; +#endif +}; + +struct posix_cond { + struct k_condvar condvar; + struct posix_condattr attr; +}; + typedef struct pthread_key_obj { /* List of pthread_key_data objects that contain thread * specific data for the key From 6877c1865a34307878e7d2549c619cedbcd4692b Mon Sep 17 00:00:00 2001 From: Chris Friedt Date: Wed, 23 Apr 2025 05:49:13 -0400 Subject: [PATCH 05/13] posix: cond: use struct posix_cond and struct posix_condattr internally Use struct posix_cond and struct posix_condattr internally. Signed-off-by: Chris Friedt --- lib/posix/options/cond.c | 56 ++++++++++++++++++++++++---------------- 1 file changed, 34 insertions(+), 22 deletions(-) diff --git a/lib/posix/options/cond.c b/lib/posix/options/cond.c index da7c526399141..4799224b01467 100644 --- a/lib/posix/options/cond.c +++ b/lib/posix/options/cond.c @@ -5,6 +5,7 @@ * SPDX-License-Identifier: Apache-2.0 */ +#include "posix_clock.h" #include "posix_internal.h" #include @@ -15,11 +16,13 @@ LOG_MODULE_REGISTER(pthread_cond, CONFIG_PTHREAD_COND_LOG_LEVEL); -__pinned_bss -static struct k_condvar posix_cond_pool[CONFIG_MAX_PTHREAD_COND_COUNT]; +static __pinned_bss struct posix_cond posix_cond_pool[CONFIG_MAX_PTHREAD_COND_COUNT]; SYS_BITARRAY_DEFINE_STATIC(posix_cond_bitarray, CONFIG_MAX_PTHREAD_COND_COUNT); +BUILD_ASSERT(sizeof(struct posix_condattr) <= sizeof(pthread_condattr_t), + "posix_condattr is too large"); + /* * We reserve the MSB to mark a pthread_cond_t as initialized (from the * perspective of the application). With a linear space, this means that @@ -28,7 +31,7 @@ SYS_BITARRAY_DEFINE_STATIC(posix_cond_bitarray, CONFIG_MAX_PTHREAD_COND_COUNT); BUILD_ASSERT(CONFIG_MAX_PTHREAD_COND_COUNT < PTHREAD_OBJ_MASK_INIT, "CONFIG_MAX_PTHREAD_COND_COUNT is too high"); -static inline size_t posix_cond_to_offset(struct k_condvar *cv) +static inline size_t posix_cond_to_offset(struct posix_cond *cv) { return cv - posix_cond_pool; } @@ -38,7 +41,7 @@ static inline size_t to_posix_cond_idx(pthread_cond_t cond) return mark_pthread_obj_uninitialized(cond); } -static struct k_condvar *get_posix_cond(pthread_cond_t cond) +static struct posix_cond *get_posix_cond(pthread_cond_t cond) { int actually_initialized; size_t bit = to_posix_cond_idx(cond); @@ -64,10 +67,10 @@ static struct k_condvar *get_posix_cond(pthread_cond_t cond) return &posix_cond_pool[bit]; } -static struct k_condvar *to_posix_cond(pthread_cond_t *cvar) +static struct posix_cond *to_posix_cond(pthread_cond_t *cvar) { size_t bit; - struct k_condvar *cv; + struct posix_cond *cv; if (*cvar != PTHREAD_COND_INITIALIZER) { return get_posix_cond(*cvar); @@ -91,7 +94,7 @@ static int cond_wait(pthread_cond_t *cond, pthread_mutex_t *mu, k_timeout_t time { int ret; struct k_mutex *m; - struct k_condvar *cv; + struct posix_cond *cv; m = to_posix_mutex(mu); cv = to_posix_cond(cond); @@ -100,7 +103,7 @@ static int cond_wait(pthread_cond_t *cond, pthread_mutex_t *mu, k_timeout_t time } LOG_DBG("Waiting on cond %p with timeout %llx", cv, timeout.ticks); - ret = k_condvar_wait(cv, m, timeout); + ret = k_condvar_wait(&cv->condvar, m, timeout); if (ret == -EAGAIN) { LOG_DBG("Timeout waiting on cond %p", cv); ret = ETIMEDOUT; @@ -118,7 +121,7 @@ static int cond_wait(pthread_cond_t *cond, pthread_mutex_t *mu, k_timeout_t time int pthread_cond_signal(pthread_cond_t *cvar) { int ret; - struct k_condvar *cv; + struct posix_cond *cv; cv = to_posix_cond(cvar); if (cv == NULL) { @@ -126,7 +129,7 @@ int pthread_cond_signal(pthread_cond_t *cvar) } LOG_DBG("Signaling cond %p", cv); - ret = k_condvar_signal(cv); + ret = k_condvar_signal(&cv->condvar); if (ret < 0) { LOG_DBG("k_condvar_signal() failed: %d", ret); return -ret; @@ -140,7 +143,7 @@ int pthread_cond_signal(pthread_cond_t *cvar) int pthread_cond_broadcast(pthread_cond_t *cvar) { int ret; - struct k_condvar *cv; + struct posix_cond *cv; cv = get_posix_cond(*cvar); if (cv == NULL) { @@ -148,7 +151,7 @@ int pthread_cond_broadcast(pthread_cond_t *cvar) } LOG_DBG("Broadcasting on cond %p", cv); - ret = k_condvar_broadcast(cv); + ret = k_condvar_broadcast(&cv->condvar); if (ret < 0) { LOG_DBG("k_condvar_broadcast() failed: %d", ret); return -ret; @@ -171,12 +174,9 @@ int pthread_cond_timedwait(pthread_cond_t *cv, pthread_mutex_t *mut, const struc int pthread_cond_init(pthread_cond_t *cvar, const pthread_condattr_t *att) { - struct k_condvar *cv; + struct posix_cond *cv; - ARG_UNUSED(att); *cvar = PTHREAD_COND_INITIALIZER; - - /* calls k_condvar_init() */ cv = to_posix_cond(cvar); if (cv == NULL) { return ENOMEM; @@ -191,7 +191,7 @@ int pthread_cond_destroy(pthread_cond_t *cvar) { int err; size_t bit; - struct k_condvar *cv; + struct posix_cond *cv; cv = get_posix_cond(*cvar); if (cv == NULL) { @@ -216,7 +216,7 @@ static int pthread_cond_pool_init(void) size_t i; for (i = 0; i < CONFIG_MAX_PTHREAD_COND_COUNT; ++i) { - err = k_condvar_init(&posix_cond_pool[i]); + err = k_condvar_init(&posix_cond_pool[i].condvar); __ASSERT_NO_MSG(err == 0); } @@ -227,14 +227,22 @@ int pthread_condattr_init(pthread_condattr_t *att) { __ASSERT_NO_MSG(att != NULL); - att->clock = CLOCK_MONOTONIC; + struct posix_condattr *const attr = (struct posix_condattr *)att; + + attr->clock = CLOCK_MONOTONIC; return 0; } int pthread_condattr_destroy(pthread_condattr_t *att) { - ARG_UNUSED(att); + struct posix_condattr *const attr = (struct posix_condattr *)att; + + if (attr == NULL) { + return EINVAL; + } + + *attr = (struct posix_condattr){0}; return 0; } @@ -242,18 +250,22 @@ int pthread_condattr_destroy(pthread_condattr_t *att) int pthread_condattr_getclock(const pthread_condattr_t *ZRESTRICT att, clockid_t *ZRESTRICT clock_id) { - *clock_id = att->clock; + struct posix_condattr *const attr = (struct posix_condattr *)att; + + *clock_id = attr->clock; return 0; } int pthread_condattr_setclock(pthread_condattr_t *att, clockid_t clock_id) { + struct posix_condattr *const attr = (struct posix_condattr *)att; + if (clock_id != CLOCK_REALTIME && clock_id != CLOCK_MONOTONIC) { return -EINVAL; } - att->clock = clock_id; + attr->clock = clock_id; return 0; } From 3f8da89e4cd99bb0002d8b9443a3ccd5de276b00 Mon Sep 17 00:00:00 2001 From: Chris Friedt Date: Wed, 23 Apr 2025 06:50:09 -0400 Subject: [PATCH 06/13] posix: cond: check whether condattr is initialized in attr fns Check whenther a pthread_condattr_t has been initialized in pthread_condattr_*() functions. Signed-off-by: Chris Friedt --- lib/posix/options/cond.c | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/lib/posix/options/cond.c b/lib/posix/options/cond.c index 4799224b01467..7f64385ba33d1 100644 --- a/lib/posix/options/cond.c +++ b/lib/posix/options/cond.c @@ -225,11 +225,18 @@ static int pthread_cond_pool_init(void) int pthread_condattr_init(pthread_condattr_t *att) { - __ASSERT_NO_MSG(att != NULL); - struct posix_condattr *const attr = (struct posix_condattr *)att; + if (att == NULL) { + return EINVAL; + } + if (attr->initialized) { + LOG_DBG("%s %s initialized", "attribute", "already"); + return EINVAL; + } + attr->clock = CLOCK_MONOTONIC; + attr->initialized = true; return 0; } @@ -238,7 +245,8 @@ int pthread_condattr_destroy(pthread_condattr_t *att) { struct posix_condattr *const attr = (struct posix_condattr *)att; - if (attr == NULL) { + if ((attr == NULL) || !attr->initialized) { + LOG_DBG("%s %s initialized", "attribute", "not"); return EINVAL; } @@ -252,6 +260,11 @@ int pthread_condattr_getclock(const pthread_condattr_t *ZRESTRICT att, { struct posix_condattr *const attr = (struct posix_condattr *)att; + if ((attr == NULL) || !attr->initialized) { + LOG_DBG("%s %s initialized", "attribute", "not"); + return EINVAL; + } + *clock_id = attr->clock; return 0; @@ -265,6 +278,11 @@ int pthread_condattr_setclock(pthread_condattr_t *att, clockid_t clock_id) return -EINVAL; } + if ((attr == NULL) || !attr->initialized) { + LOG_DBG("%s %s initialized", "attribute", "not"); + return EINVAL; + } + attr->clock = clock_id; return 0; From bead984399a76520a934e09a37a436c0a6f301fb Mon Sep 17 00:00:00 2001 From: Chris Friedt Date: Wed, 23 Apr 2025 07:46:59 -0400 Subject: [PATCH 07/13] posix: cond: use clock specified via pthread_condattr_t Use the clock specified via pthread_condattr_t in pthread_cond_timedwait(). Signed-off-by: Chris Friedt --- lib/posix/options/cond.c | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/lib/posix/options/cond.c b/lib/posix/options/cond.c index 7f64385ba33d1..55e840210d97f 100644 --- a/lib/posix/options/cond.c +++ b/lib/posix/options/cond.c @@ -86,15 +86,17 @@ static struct posix_cond *to_posix_cond(pthread_cond_t *cvar) /* Record the associated posix_cond in mu and mark as initialized */ *cvar = mark_pthread_obj_initialized(bit); cv = &posix_cond_pool[bit]; + (void)pthread_condattr_init((pthread_condattr_t *)&cv->attr); return cv; } -static int cond_wait(pthread_cond_t *cond, pthread_mutex_t *mu, k_timeout_t timeout) +static int cond_wait(pthread_cond_t *cond, pthread_mutex_t *mu, const struct timespec *abstime) { int ret; struct k_mutex *m; struct posix_cond *cv; + k_timeout_t timeout = K_FOREVER; m = to_posix_mutex(mu); cv = to_posix_cond(cond); @@ -102,6 +104,10 @@ static int cond_wait(pthread_cond_t *cond, pthread_mutex_t *mu, k_timeout_t time return EINVAL; } + if (abstime != NULL) { + timeout = K_MSEC(timespec_to_clock_timeoutms(cv->attr.clock, abstime)); + } + LOG_DBG("Waiting on cond %p with timeout %llx", cv, timeout.ticks); ret = k_condvar_wait(&cv->condvar, m, timeout); if (ret == -EAGAIN) { @@ -164,17 +170,18 @@ int pthread_cond_broadcast(pthread_cond_t *cvar) int pthread_cond_wait(pthread_cond_t *cv, pthread_mutex_t *mut) { - return cond_wait(cv, mut, K_FOREVER); + return cond_wait(cv, mut, NULL); } int pthread_cond_timedwait(pthread_cond_t *cv, pthread_mutex_t *mut, const struct timespec *abstime) { - return cond_wait(cv, mut, K_MSEC(timespec_to_timeoutms(abstime))); + return cond_wait(cv, mut, abstime); } int pthread_cond_init(pthread_cond_t *cvar, const pthread_condattr_t *att) { struct posix_cond *cv; + struct posix_condattr *attr = (struct posix_condattr *)attr; *cvar = PTHREAD_COND_INITIALIZER; cv = to_posix_cond(cvar); @@ -182,6 +189,15 @@ int pthread_cond_init(pthread_cond_t *cvar, const pthread_condattr_t *att) return ENOMEM; } + if (attr != NULL) { + if (!attr->initialized) { + return EINVAL; + } + + (void)pthread_condattr_destroy((pthread_condattr_t *)&cv->attr); + cv->attr = *attr; + } + LOG_DBG("Initialized cond %p", cv); return 0; From ce4942b3764f5d42b3b70c6491b2cdeb1d254362 Mon Sep 17 00:00:00 2001 From: Chris Friedt Date: Wed, 23 Apr 2025 08:15:17 -0400 Subject: [PATCH 08/13] posix: add timespec_is_valid() private internal function Add a common private function timespec_is_valid() that can be used to check if a timespec object is valid, and use that consistently in lib/posix/options. Signed-off-by: Chris Friedt --- lib/posix/options/cond.c | 5 +++++ lib/posix/options/mqueue.c | 10 ++++++++++ lib/posix/options/mutex.c | 5 +++++ lib/posix/options/posix_clock.h | 11 +++++++++++ lib/posix/options/pthread.c | 7 ++----- lib/posix/options/rwlock.c | 6 ++++-- lib/posix/options/semaphore.c | 6 +++--- lib/posix/options/timer.c | 11 ++++++----- 8 files changed, 46 insertions(+), 15 deletions(-) diff --git a/lib/posix/options/cond.c b/lib/posix/options/cond.c index 55e840210d97f..40947aa3c453c 100644 --- a/lib/posix/options/cond.c +++ b/lib/posix/options/cond.c @@ -175,6 +175,11 @@ int pthread_cond_wait(pthread_cond_t *cv, pthread_mutex_t *mut) int pthread_cond_timedwait(pthread_cond_t *cv, pthread_mutex_t *mut, const struct timespec *abstime) { + if ((abstime == NULL) || !timespec_is_valid(abstime)) { + LOG_DBG("%s is invalid", "abstime"); + return EINVAL; + } + return cond_wait(cv, mut, abstime); } diff --git a/lib/posix/options/mqueue.c b/lib/posix/options/mqueue.c index 99966786a0b28..23f2ee73ccbda 100644 --- a/lib/posix/options/mqueue.c +++ b/lib/posix/options/mqueue.c @@ -258,6 +258,11 @@ int mq_timedsend(mqd_t mqdes, const char *msg_ptr, size_t msg_len, { mqueue_desc *mqd = (mqueue_desc *)mqdes; + if ((abstime == NULL) || !timespec_is_valid(abstime)) { + errno = EINVAL; + return -1; + } + return send_message(mqd, msg_ptr, msg_len, K_MSEC(timespec_to_timeoutms(abstime))); } @@ -288,6 +293,11 @@ int mq_timedreceive(mqd_t mqdes, char *msg_ptr, size_t msg_len, { mqueue_desc *mqd = (mqueue_desc *)mqdes; + if ((abstime == NULL) || !timespec_is_valid(abstime)) { + errno = EINVAL; + return -1; + } + return receive_message(mqd, msg_ptr, msg_len, K_MSEC(timespec_to_timeoutms(abstime))); } diff --git a/lib/posix/options/mutex.c b/lib/posix/options/mutex.c index d61458d1e4392..51bd3f53c7c32 100644 --- a/lib/posix/options/mutex.c +++ b/lib/posix/options/mutex.c @@ -211,6 +211,11 @@ int pthread_mutex_trylock(pthread_mutex_t *m) int pthread_mutex_timedlock(pthread_mutex_t *m, const struct timespec *abstime) { + if ((abstime == NULL) || !timespec_is_valid(abstime)) { + LOG_DBG("%s is invalid", "abstime"); + return EINVAL; + } + return acquire_mutex(m, K_MSEC(timespec_to_timeoutms(abstime))); } diff --git a/lib/posix/options/posix_clock.h b/lib/posix/options/posix_clock.h index 18fe562ec4dc9..c0ebe66fde65a 100644 --- a/lib/posix/options/posix_clock.h +++ b/lib/posix/options/posix_clock.h @@ -8,9 +8,20 @@ #ifndef ZEPHYR_LIB_POSIX_POSIX_CLOCK_H_ #define ZEPHYR_LIB_POSIX_POSIX_CLOCK_H_ +#include +#include #include #include +#include +#include + +static inline bool timespec_is_valid(const struct timespec *ts) +{ + __ASSERT_NO_MSG(ts != NULL); + return (ts->tv_nsec >= 0) && (ts->tv_nsec < NSEC_PER_SEC); +} + uint32_t timespec_to_clock_timeoutms(clockid_t clock_id, const struct timespec *abstime); uint32_t timespec_to_timeoutms(const struct timespec *abstime); diff --git a/lib/posix/options/pthread.c b/lib/posix/options/pthread.c index db0ec7ec8c517..da79330be17e8 100644 --- a/lib/posix/options/pthread.c +++ b/lib/posix/options/pthread.c @@ -1149,11 +1149,8 @@ static int pthread_timedjoin_internal(pthread_t pthread, void **status, k_timeou */ int pthread_timedjoin_np(pthread_t pthread, void **status, const struct timespec *abstime) { - if (abstime == NULL) { - return EINVAL; - } - - if (abstime->tv_sec < 0 || abstime->tv_nsec < 0 || abstime->tv_nsec >= NSEC_PER_SEC) { + if ((abstime == NULL) || !timespec_is_valid(abstime)) { + LOG_DBG("%s is invalid", "abstime"); return EINVAL; } diff --git a/lib/posix/options/rwlock.c b/lib/posix/options/rwlock.c index 84133859e862a..8d1a35584f985 100644 --- a/lib/posix/options/rwlock.c +++ b/lib/posix/options/rwlock.c @@ -201,7 +201,8 @@ int pthread_rwlock_timedrdlock(pthread_rwlock_t *rwlock, uint32_t ret = 0U; struct posix_rwlock *rwl; - if (abstime->tv_nsec < 0 || abstime->tv_nsec > NSEC_PER_SEC) { + if ((abstime == NULL) || !timespec_is_valid(abstime)) { + LOG_DBG("%s is invalid", "abstime"); return EINVAL; } @@ -271,7 +272,8 @@ int pthread_rwlock_timedwrlock(pthread_rwlock_t *rwlock, uint32_t ret = 0U; struct posix_rwlock *rwl; - if (abstime->tv_nsec < 0 || abstime->tv_nsec > NSEC_PER_SEC) { + if ((abstime == NULL) || !timespec_is_valid(abstime)) { + LOG_DBG("%s is invalid", "abstime"); return EINVAL; } diff --git a/lib/posix/options/semaphore.c b/lib/posix/options/semaphore.c index 537b618ff6f7c..d3787862fb4da 100644 --- a/lib/posix/options/semaphore.c +++ b/lib/posix/options/semaphore.c @@ -5,6 +5,8 @@ * SPDX-License-Identifier: Apache-2.0 */ +#include "posix_clock.h" + #include #include #include @@ -163,9 +165,7 @@ int sem_timedwait(sem_t *semaphore, struct timespec *abstime) struct timespec current; int64_t current_ms, abstime_ms; - __ASSERT(abstime, "abstime pointer NULL"); - - if ((abstime->tv_sec < 0) || (abstime->tv_nsec >= NSEC_PER_SEC)) { + if ((abstime == NULL) || !timespec_is_valid(abstime)) { errno = EINVAL; return -1; } diff --git a/lib/posix/options/timer.c b/lib/posix/options/timer.c index e810b4576f7c9..41dcbefeb576a 100644 --- a/lib/posix/options/timer.c +++ b/lib/posix/options/timer.c @@ -4,8 +4,12 @@ * * SPDX-License-Identifier: Apache-2.0 */ + #undef _POSIX_C_SOURCE #define _POSIX_C_SOURCE 200809L + +#include "posix_clock.h" + #include #include @@ -241,11 +245,8 @@ int timer_settime(timer_t timerid, int flags, const struct itimerspec *value, struct timer_obj *timer = (struct timer_obj *) timerid; uint32_t duration, current; - if (timer == NULL || - value->it_interval.tv_nsec < 0 || - value->it_interval.tv_nsec >= NSEC_PER_SEC || - value->it_value.tv_nsec < 0 || - value->it_value.tv_nsec >= NSEC_PER_SEC) { + if ((timer == NULL) || !timespec_is_valid(&value->it_interval) || + !timespec_is_valid(&value->it_value)) { errno = EINVAL; return -1; } From 9ff91f1cfba5e36b1e0ca807d259306f139995e8 Mon Sep 17 00:00:00 2001 From: Chris Friedt Date: Wed, 23 Apr 2025 09:09:50 -0400 Subject: [PATCH 09/13] posix + tests: use CLOCK_REALTIME where specified by POSIX Use CLOCK_REALTIME for the default clock source throughout the POSIX implementation and tests so that we are consistent with the specification. Signed-off-by: Chris Friedt --- lib/posix/options/cond.c | 2 +- lib/posix/options/mqueue.c | 6 ++++-- lib/posix/options/mutex.c | 2 +- lib/posix/options/pthread.c | 3 ++- lib/posix/options/rwlock.c | 4 ++-- lib/posix/options/semaphore.c | 19 +------------------ tests/lib/c_lib/thrd/src/cnd.c | 2 +- tests/posix/common/src/cond.c | 2 +- tests/posix/rwlocks/src/main.c | 5 +++-- 9 files changed, 16 insertions(+), 29 deletions(-) diff --git a/lib/posix/options/cond.c b/lib/posix/options/cond.c index 40947aa3c453c..8c81de5b2f627 100644 --- a/lib/posix/options/cond.c +++ b/lib/posix/options/cond.c @@ -256,7 +256,7 @@ int pthread_condattr_init(pthread_condattr_t *att) return EINVAL; } - attr->clock = CLOCK_MONOTONIC; + attr->clock = CLOCK_REALTIME; attr->initialized = true; return 0; diff --git a/lib/posix/options/mqueue.c b/lib/posix/options/mqueue.c index 23f2ee73ccbda..72244a1981d87 100644 --- a/lib/posix/options/mqueue.c +++ b/lib/posix/options/mqueue.c @@ -263,7 +263,8 @@ int mq_timedsend(mqd_t mqdes, const char *msg_ptr, size_t msg_len, return -1; } - return send_message(mqd, msg_ptr, msg_len, K_MSEC(timespec_to_timeoutms(abstime))); + return send_message(mqd, msg_ptr, msg_len, + K_MSEC(timespec_to_clock_timeoutms(CLOCK_REALTIME, abstime))); } /** @@ -298,7 +299,8 @@ int mq_timedreceive(mqd_t mqdes, char *msg_ptr, size_t msg_len, return -1; } - return receive_message(mqd, msg_ptr, msg_len, K_MSEC(timespec_to_timeoutms(abstime))); + return receive_message(mqd, msg_ptr, msg_len, + K_MSEC(timespec_to_clock_timeoutms(CLOCK_REALTIME, abstime))); } /** diff --git a/lib/posix/options/mutex.c b/lib/posix/options/mutex.c index 51bd3f53c7c32..ff2efc7f65546 100644 --- a/lib/posix/options/mutex.c +++ b/lib/posix/options/mutex.c @@ -216,7 +216,7 @@ int pthread_mutex_timedlock(pthread_mutex_t *m, return EINVAL; } - return acquire_mutex(m, K_MSEC(timespec_to_timeoutms(abstime))); + return acquire_mutex(m, K_MSEC(timespec_to_clock_timeoutms(CLOCK_REALTIME, abstime))); } /** diff --git a/lib/posix/options/pthread.c b/lib/posix/options/pthread.c index da79330be17e8..bc88ea29fe279 100644 --- a/lib/posix/options/pthread.c +++ b/lib/posix/options/pthread.c @@ -1154,7 +1154,8 @@ int pthread_timedjoin_np(pthread_t pthread, void **status, const struct timespec return EINVAL; } - return pthread_timedjoin_internal(pthread, status, K_MSEC(timespec_to_timeoutms(abstime))); + return pthread_timedjoin_internal( + pthread, status, K_MSEC(timespec_to_clock_timeoutms(CLOCK_REALTIME, abstime))); } /** diff --git a/lib/posix/options/rwlock.c b/lib/posix/options/rwlock.c index 8d1a35584f985..39404c9229fa8 100644 --- a/lib/posix/options/rwlock.c +++ b/lib/posix/options/rwlock.c @@ -211,7 +211,7 @@ int pthread_rwlock_timedrdlock(pthread_rwlock_t *rwlock, return EINVAL; } - if (read_lock_acquire(rwl, timespec_to_timeoutms(abstime)) != 0U) { + if (read_lock_acquire(rwl, timespec_to_clock_timeoutms(CLOCK_REALTIME, abstime)) != 0U) { ret = ETIMEDOUT; } @@ -282,7 +282,7 @@ int pthread_rwlock_timedwrlock(pthread_rwlock_t *rwlock, return EINVAL; } - if (write_lock_acquire(rwl, timespec_to_timeoutms(abstime)) != 0U) { + if (write_lock_acquire(rwl, timespec_to_clock_timeoutms(CLOCK_REALTIME, abstime)) != 0U) { ret = ETIMEDOUT; } diff --git a/lib/posix/options/semaphore.c b/lib/posix/options/semaphore.c index d3787862fb4da..77a879a8cb924 100644 --- a/lib/posix/options/semaphore.c +++ b/lib/posix/options/semaphore.c @@ -161,29 +161,12 @@ int sem_post(sem_t *semaphore) */ int sem_timedwait(sem_t *semaphore, struct timespec *abstime) { - int32_t timeout; - struct timespec current; - int64_t current_ms, abstime_ms; - if ((abstime == NULL) || !timespec_is_valid(abstime)) { errno = EINVAL; return -1; } - if (clock_gettime(CLOCK_REALTIME, ¤t) < 0) { - return -1; - } - - abstime_ms = (int64_t)_ts_to_ms(abstime); - current_ms = (int64_t)_ts_to_ms(¤t); - - if (abstime_ms <= current_ms) { - timeout = 0; - } else { - timeout = (int32_t)(abstime_ms - current_ms); - } - - if (k_sem_take(semaphore, K_MSEC(timeout))) { + if (k_sem_take(semaphore, K_MSEC(timespec_to_clock_timeoutms(CLOCK_REALTIME, abstime)))) { errno = ETIMEDOUT; return -1; } diff --git a/tests/lib/c_lib/thrd/src/cnd.c b/tests/lib/c_lib/thrd/src/cnd.c index aaf00f9cb7b97..82741e352bbcf 100644 --- a/tests/lib/c_lib/thrd/src/cnd.c +++ b/tests/lib/c_lib/thrd/src/cnd.c @@ -71,7 +71,7 @@ static int test_cnd_thread_fn(void *arg) struct libc_cnd_fixture *const fixture = arg; if (fixture->do_timedwait) { - zassume_ok(clock_gettime(CLOCK_MONOTONIC, &time_point)); + zassume_ok(clock_gettime(CLOCK_REALTIME, &time_point)); timespec_add_ms(&time_point, WAIT_TIME_MS); res = cnd_timedwait(&fixture->cond, &fixture->mutex, &time_point); } else { diff --git a/tests/posix/common/src/cond.c b/tests/posix/common/src/cond.c index b648ac0abd0f3..94de124c3758a 100644 --- a/tests/posix/common/src/cond.c +++ b/tests/posix/common/src/cond.c @@ -55,7 +55,7 @@ ZTEST(cond, test_pthread_condattr) zassert_ok(pthread_condattr_init(&att)); zassert_ok(pthread_condattr_getclock(&att, &clock_id), "pthread_condattr_getclock failed"); - zassert_equal(clock_id, CLOCK_MONOTONIC, "clock attribute not set correctly"); + zassert_equal(clock_id, CLOCK_REALTIME, "clock attribute not set correctly"); zassert_ok(pthread_condattr_setclock(&att, CLOCK_REALTIME), "pthread_condattr_setclock failed"); diff --git a/tests/posix/rwlocks/src/main.c b/tests/posix/rwlocks/src/main.c index 7e0fd101f028a..aaf859663bfbd 100644 --- a/tests/posix/rwlocks/src/main.c +++ b/tests/posix/rwlocks/src/main.c @@ -86,8 +86,9 @@ ZTEST(posix_rw_locks, test_rw_lock) usleep(USEC_PER_MSEC); LOG_DBG("Parent thread acquiring WR lock again"); - time.tv_sec = 2; - time.tv_nsec = 0; + zassert_ok(clock_gettime(CLOCK_REALTIME, &time)); + time.tv_sec += 2; + ret = pthread_rwlock_timedwrlock(&rwlock, &time); if (ret) { zassert_ok(pthread_rwlock_wrlock(&rwlock), "Failed to acquire write lock"); From c74788028f44953cef0398c49a53e3434671aaac Mon Sep 17 00:00:00 2001 From: Chris Friedt Date: Wed, 23 Apr 2025 09:16:54 -0400 Subject: [PATCH 10/13] posix: always require clockid_t argument to timespec_to_timeoutms() Always require the clockid_t argument to timespec_to_timeoutms() and remove the unused variant that accepts no clockid_t parameter. Signed-off-by: Chris Friedt --- lib/posix/options/cond.c | 2 +- lib/posix/options/mqueue.c | 4 ++-- lib/posix/options/mutex.c | 2 +- lib/posix/options/posix_clock.h | 3 +-- lib/posix/options/pthread.c | 4 ++-- lib/posix/options/rwlock.c | 4 ++-- lib/posix/options/semaphore.c | 2 +- lib/posix/options/timespec_to_timeout.c | 7 +------ 8 files changed, 11 insertions(+), 17 deletions(-) diff --git a/lib/posix/options/cond.c b/lib/posix/options/cond.c index 8c81de5b2f627..d1fc231c94c0f 100644 --- a/lib/posix/options/cond.c +++ b/lib/posix/options/cond.c @@ -105,7 +105,7 @@ static int cond_wait(pthread_cond_t *cond, pthread_mutex_t *mu, const struct tim } if (abstime != NULL) { - timeout = K_MSEC(timespec_to_clock_timeoutms(cv->attr.clock, abstime)); + timeout = K_MSEC(timespec_to_timeoutms(cv->attr.clock, abstime)); } LOG_DBG("Waiting on cond %p with timeout %llx", cv, timeout.ticks); diff --git a/lib/posix/options/mqueue.c b/lib/posix/options/mqueue.c index 72244a1981d87..0eef3f81ccf35 100644 --- a/lib/posix/options/mqueue.c +++ b/lib/posix/options/mqueue.c @@ -264,7 +264,7 @@ int mq_timedsend(mqd_t mqdes, const char *msg_ptr, size_t msg_len, } return send_message(mqd, msg_ptr, msg_len, - K_MSEC(timespec_to_clock_timeoutms(CLOCK_REALTIME, abstime))); + K_MSEC(timespec_to_timeoutms(CLOCK_REALTIME, abstime))); } /** @@ -300,7 +300,7 @@ int mq_timedreceive(mqd_t mqdes, char *msg_ptr, size_t msg_len, } return receive_message(mqd, msg_ptr, msg_len, - K_MSEC(timespec_to_clock_timeoutms(CLOCK_REALTIME, abstime))); + K_MSEC(timespec_to_timeoutms(CLOCK_REALTIME, abstime))); } /** diff --git a/lib/posix/options/mutex.c b/lib/posix/options/mutex.c index ff2efc7f65546..52dec35d24911 100644 --- a/lib/posix/options/mutex.c +++ b/lib/posix/options/mutex.c @@ -216,7 +216,7 @@ int pthread_mutex_timedlock(pthread_mutex_t *m, return EINVAL; } - return acquire_mutex(m, K_MSEC(timespec_to_clock_timeoutms(CLOCK_REALTIME, abstime))); + return acquire_mutex(m, K_MSEC(timespec_to_timeoutms(CLOCK_REALTIME, abstime))); } /** diff --git a/lib/posix/options/posix_clock.h b/lib/posix/options/posix_clock.h index c0ebe66fde65a..5ff567245410e 100644 --- a/lib/posix/options/posix_clock.h +++ b/lib/posix/options/posix_clock.h @@ -22,8 +22,7 @@ static inline bool timespec_is_valid(const struct timespec *ts) return (ts->tv_nsec >= 0) && (ts->tv_nsec < NSEC_PER_SEC); } -uint32_t timespec_to_clock_timeoutms(clockid_t clock_id, const struct timespec *abstime); -uint32_t timespec_to_timeoutms(const struct timespec *abstime); +uint32_t timespec_to_timeoutms(clockid_t clock_id, const struct timespec *abstime); __syscall int __posix_clock_get_base(clockid_t clock_id, struct timespec *ts); diff --git a/lib/posix/options/pthread.c b/lib/posix/options/pthread.c index bc88ea29fe279..c505b8564bb30 100644 --- a/lib/posix/options/pthread.c +++ b/lib/posix/options/pthread.c @@ -1154,8 +1154,8 @@ int pthread_timedjoin_np(pthread_t pthread, void **status, const struct timespec return EINVAL; } - return pthread_timedjoin_internal( - pthread, status, K_MSEC(timespec_to_clock_timeoutms(CLOCK_REALTIME, abstime))); + return pthread_timedjoin_internal(pthread, status, + K_MSEC(timespec_to_timeoutms(CLOCK_REALTIME, abstime))); } /** diff --git a/lib/posix/options/rwlock.c b/lib/posix/options/rwlock.c index 39404c9229fa8..b7eb21bd6be2e 100644 --- a/lib/posix/options/rwlock.c +++ b/lib/posix/options/rwlock.c @@ -211,7 +211,7 @@ int pthread_rwlock_timedrdlock(pthread_rwlock_t *rwlock, return EINVAL; } - if (read_lock_acquire(rwl, timespec_to_clock_timeoutms(CLOCK_REALTIME, abstime)) != 0U) { + if (read_lock_acquire(rwl, timespec_to_timeoutms(CLOCK_REALTIME, abstime)) != 0U) { ret = ETIMEDOUT; } @@ -282,7 +282,7 @@ int pthread_rwlock_timedwrlock(pthread_rwlock_t *rwlock, return EINVAL; } - if (write_lock_acquire(rwl, timespec_to_clock_timeoutms(CLOCK_REALTIME, abstime)) != 0U) { + if (write_lock_acquire(rwl, timespec_to_timeoutms(CLOCK_REALTIME, abstime)) != 0U) { ret = ETIMEDOUT; } diff --git a/lib/posix/options/semaphore.c b/lib/posix/options/semaphore.c index 77a879a8cb924..55ac57c5cfd3f 100644 --- a/lib/posix/options/semaphore.c +++ b/lib/posix/options/semaphore.c @@ -166,7 +166,7 @@ int sem_timedwait(sem_t *semaphore, struct timespec *abstime) return -1; } - if (k_sem_take(semaphore, K_MSEC(timespec_to_clock_timeoutms(CLOCK_REALTIME, abstime)))) { + if (k_sem_take(semaphore, K_MSEC(timespec_to_timeoutms(CLOCK_REALTIME, abstime)))) { errno = ETIMEDOUT; return -1; } diff --git a/lib/posix/options/timespec_to_timeout.c b/lib/posix/options/timespec_to_timeout.c index a3373a9a7bfcc..d307efa736e37 100644 --- a/lib/posix/options/timespec_to_timeout.c +++ b/lib/posix/options/timespec_to_timeout.c @@ -10,7 +10,7 @@ #include #include -uint32_t timespec_to_clock_timeoutms(clockid_t clock_id, const struct timespec *abstime) +uint32_t timespec_to_timeoutms(clockid_t clock_id, const struct timespec *abstime) { int64_t milli_secs, secs, nsecs; struct timespec curtime; @@ -27,8 +27,3 @@ uint32_t timespec_to_clock_timeoutms(clockid_t clock_id, const struct timespec * return milli_secs; } - -uint32_t timespec_to_timeoutms(const struct timespec *abstime) -{ - return timespec_to_clock_timeoutms(CLOCK_MONOTONIC, abstime); -} From 582334491dc8e29289dc69650a9f28e051acb61b Mon Sep 17 00:00:00 2001 From: Chris Friedt Date: Wed, 23 Apr 2025 09:19:33 -0400 Subject: [PATCH 11/13] posix: doc: hide internal posix_clock.h functions from doxygen Prevent doxygen from parsing internal functions declared in posix_clock.h . Signed-off-by: Chris Friedt --- lib/posix/options/posix_clock.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/posix/options/posix_clock.h b/lib/posix/options/posix_clock.h index 5ff567245410e..832f5b8e8afbd 100644 --- a/lib/posix/options/posix_clock.h +++ b/lib/posix/options/posix_clock.h @@ -16,6 +16,8 @@ #include #include +/** @cond INTERNAL_HIDDEN */ + static inline bool timespec_is_valid(const struct timespec *ts) { __ASSERT_NO_MSG(ts != NULL); @@ -26,6 +28,8 @@ uint32_t timespec_to_timeoutms(clockid_t clock_id, const struct timespec *abstim __syscall int __posix_clock_get_base(clockid_t clock_id, struct timespec *ts); +/** INTERNAL_HIDDEN @endcond */ + #include #endif From 3310630522a3dd94916856d56bc3d719fc02e22e Mon Sep 17 00:00:00 2001 From: Chris Friedt Date: Wed, 23 Apr 2025 09:29:26 -0400 Subject: [PATCH 12/13] posix: move timespec functions to posix_clock.h Move somewhat useful (but private and internal functions) that deal with struct timespec to posix_clock.h until there is a better API available for dealing with operations on struct timespec. Signed-off-by: Chris Friedt --- include/zephyr/posix/time.h | 5 ----- lib/posix/options/posix_clock.h | 37 +++++++++++++++++++++++++++++++ lib/posix/options/timer.c | 4 ++-- tests/posix/timers/CMakeLists.txt | 1 + tests/posix/timers/src/clock.c | 33 ++++----------------------- 5 files changed, 44 insertions(+), 36 deletions(-) diff --git a/include/zephyr/posix/time.h b/include/zephyr/posix/time.h index 51542f304fa9a..7f944b7db97ae 100644 --- a/include/zephyr/posix/time.h +++ b/include/zephyr/posix/time.h @@ -85,11 +85,6 @@ extern "C" { #define TIMER_ABSTIME 4 #endif -static inline int32_t _ts_to_ms(const struct timespec *to) -{ - return (int32_t)(to->tv_sec * MSEC_PER_SEC) + (int32_t)(to->tv_nsec / NSEC_PER_MSEC); -} - int clock_gettime(clockid_t clock_id, struct timespec *ts); int clock_getres(clockid_t clock_id, struct timespec *ts); int clock_settime(clockid_t clock_id, const struct timespec *ts); diff --git a/lib/posix/options/posix_clock.h b/lib/posix/options/posix_clock.h index 832f5b8e8afbd..12de6f9fe8c9f 100644 --- a/lib/posix/options/posix_clock.h +++ b/lib/posix/options/posix_clock.h @@ -16,6 +16,10 @@ #include #include +#ifdef __cplusplus +extern "C" { +#endif + /** @cond INTERNAL_HIDDEN */ static inline bool timespec_is_valid(const struct timespec *ts) @@ -24,6 +28,35 @@ static inline bool timespec_is_valid(const struct timespec *ts) return (ts->tv_nsec >= 0) && (ts->tv_nsec < NSEC_PER_SEC); } +static inline int64_t ts_to_ns(const struct timespec *ts) +{ + return ts->tv_sec * NSEC_PER_SEC + ts->tv_nsec; +} + +static inline int64_t ts_to_ms(const struct timespec *ts) +{ + return ts->tv_sec * MSEC_PER_SEC + ts->tv_nsec / NSEC_PER_MSEC; +} + +static inline bool tp_ge(const struct timespec *a, const struct timespec *b) +{ + return ts_to_ns(a) >= ts_to_ns(b); +} + +static inline int64_t tp_diff(const struct timespec *a, const struct timespec *b) +{ + return ts_to_ns(a) - ts_to_ns(b); +} + +/* lo <= (a - b) < hi */ +static inline bool tp_diff_in_range_ns(const struct timespec *a, const struct timespec *b, + int64_t lo, int64_t hi) +{ + int64_t diff = tp_diff(a, b); + + return diff >= lo && diff < hi; +} + uint32_t timespec_to_timeoutms(clockid_t clock_id, const struct timespec *abstime); __syscall int __posix_clock_get_base(clockid_t clock_id, struct timespec *ts); @@ -32,4 +65,8 @@ __syscall int __posix_clock_get_base(clockid_t clock_id, struct timespec *ts); #include +#ifdef __cplusplus +} +#endif + #endif diff --git a/lib/posix/options/timer.c b/lib/posix/options/timer.c index 41dcbefeb576a..257fdce59ef36 100644 --- a/lib/posix/options/timer.c +++ b/lib/posix/options/timer.c @@ -267,12 +267,12 @@ int timer_settime(timer_t timerid, int flags, const struct itimerspec *value, } /* Calculate timer period */ - timer->reload = _ts_to_ms(&value->it_interval); + timer->reload = ts_to_ms(&value->it_interval); timer->interval.tv_sec = value->it_interval.tv_sec; timer->interval.tv_nsec = value->it_interval.tv_nsec; /* Calculate timer duration */ - duration = _ts_to_ms(&(value->it_value)); + duration = ts_to_ms(&(value->it_value)); if ((flags & TIMER_ABSTIME) != 0) { current = k_timer_remaining_get(&timer->ztimer); diff --git a/tests/posix/timers/CMakeLists.txt b/tests/posix/timers/CMakeLists.txt index 7c689da26a445..9eab9f09c6fc2 100644 --- a/tests/posix/timers/CMakeLists.txt +++ b/tests/posix/timers/CMakeLists.txt @@ -9,3 +9,4 @@ FILE(GLOB app_sources src/*.c) target_sources(app PRIVATE ${app_sources}) target_compile_options(app PRIVATE -U_POSIX_C_SOURCE -D_POSIX_C_SOURCE=200809L) +target_include_directories(app PRIVATE ${ZEPHYR_BASE}/lib/posix/options) diff --git a/tests/posix/timers/src/clock.c b/tests/posix/timers/src/clock.c index 0b34e87db06f4..7e6b39137b962 100644 --- a/tests/posix/timers/src/clock.c +++ b/tests/posix/timers/src/clock.c @@ -4,6 +4,10 @@ * * SPDX-License-Identifier: Apache-2.0 */ + +/* for tp_ge(), tp_diff() */ +#include "posix_clock.h" + #include #include #include @@ -29,35 +33,6 @@ static const bool settable[] = { true, }; -static inline int64_t ts_to_ns(const struct timespec *ts) -{ - return ts->tv_sec * NSEC_PER_SEC + ts->tv_nsec; -} - -#define _tp_op(_a, _b, _op) (ts_to_ns(_a) _op ts_to_ns(_b)) - -#define _decl_op(_type, _name, _op) \ - __used static inline _type _name(const struct timespec *_a, const struct timespec *_b) \ - { \ - return _tp_op(_a, _b, _op); \ - } - -_decl_op(bool, tp_eq, ==); /* a == b */ -_decl_op(bool, tp_lt, <); /* a < b */ -_decl_op(bool, tp_gt, >); /* a > b */ -_decl_op(bool, tp_le, <=); /* a <= b */ -_decl_op(bool, tp_ge, >=); /* a >= b */ -_decl_op(int64_t, tp_diff, -); /* a - b */ - -/* lo <= (a - b) < hi */ -__used static inline bool tp_diff_in_range_ns(const struct timespec *a, const struct timespec *b, - int64_t lo, int64_t hi) -{ - int64_t diff = tp_diff(a, b); - - return diff >= lo && diff < hi; -} - ZTEST(posix_timers, test_clock_gettime) { struct timespec ts; From 9aff67e1586a299d55472a2bf2574d2c1ca88b65 Mon Sep 17 00:00:00 2001 From: Chris Friedt Date: Wed, 23 Apr 2025 09:35:03 -0400 Subject: [PATCH 13/13] posix: refactor timespec_to_timeoutms() to use tp_diff() Use the tp_diff() macro as a means of converting an absolute timeout with respect to a specific clock to a relative timeout, in ms. Clamp the result between 0 and UINT32_MAX. Signed-off-by: Chris Friedt --- lib/posix/options/timespec_to_timeout.c | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/lib/posix/options/timespec_to_timeout.c b/lib/posix/options/timespec_to_timeout.c index d307efa736e37..068646c2064d4 100644 --- a/lib/posix/options/timespec_to_timeout.c +++ b/lib/posix/options/timespec_to_timeout.c @@ -6,24 +6,19 @@ #include "posix_clock.h" -#include -#include +#include +#include + #include +#include uint32_t timespec_to_timeoutms(clockid_t clock_id, const struct timespec *abstime) { - int64_t milli_secs, secs, nsecs; struct timespec curtime; - clock_gettime(clock_id, &curtime); - secs = abstime->tv_sec - curtime.tv_sec; - nsecs = abstime->tv_nsec - curtime.tv_nsec; - - if (secs < 0 || (secs == 0 && nsecs < NSEC_PER_MSEC)) { - milli_secs = 0; - } else { - milli_secs = secs * MSEC_PER_SEC + nsecs / NSEC_PER_MSEC; + if (clock_gettime(clock_id, &curtime) < 0) { + return 0; } - return milli_secs; + return CLAMP(tp_diff(abstime, &curtime) / NSEC_PER_MSEC, 0, UINT32_MAX); }