git: e1136fbcab18 - main - libthr: implement pthread_cond_clockwait(3)
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Mon, 27 Jul 2026 16:17:56 UTC
The branch main has been updated by kib:
URL: https://cgit.FreeBSD.org/src/commit/?id=e1136fbcab184b8fb87456ca0d115d502bab6643
commit e1136fbcab184b8fb87456ca0d115d502bab6643
Author: Konstantin Belousov <kib@FreeBSD.org>
AuthorDate: 2026-07-25 23:45:11 +0000
Commit: Konstantin Belousov <kib@FreeBSD.org>
CommitDate: 2026-07-27 16:17:28 +0000
libthr: implement pthread_cond_clockwait(3)
Reviewed by: markj
Sponsored by: The FreeBSD Foundation
MFC after: 1 week
Differential revision: https://reviews.freebsd.org/D58463
---
include/pthread.h | 5 ++++
lib/libthr/pthread.map | 1 +
lib/libthr/thread/thr_barrier.c | 6 ++--
lib/libthr/thread/thr_cond.c | 64 ++++++++++++++++++++++++++++++-----------
lib/libthr/thread/thr_umtx.c | 30 ++++++++++++++-----
lib/libthr/thread/thr_umtx.h | 3 +-
6 files changed, 83 insertions(+), 26 deletions(-)
diff --git a/include/pthread.h b/include/pthread.h
index 311211cb48f1..1686b54314ef 100644
--- a/include/pthread.h
+++ b/include/pthread.h
@@ -199,6 +199,11 @@ int pthread_condattr_init(pthread_condattr_t *);
int pthread_condattr_setclock(pthread_condattr_t *, clockid_t);
int pthread_condattr_setpshared(pthread_condattr_t *, int);
int pthread_cond_broadcast(pthread_cond_t *);
+#if __POSIX_VISIBLE >= 202405
+int pthread_cond_clockwait(pthread_cond_t * __restrict,
+ pthread_mutex_t * __restrict, clockid_t,
+ const struct timespec * __restrict);
+#endif
int pthread_cond_destroy(pthread_cond_t *);
int pthread_cond_init(pthread_cond_t * __restrict,
const pthread_condattr_t * __restrict);
diff --git a/lib/libthr/pthread.map b/lib/libthr/pthread.map
index ad0c28de98c1..4fe5f2c28331 100644
--- a/lib/libthr/pthread.map
+++ b/lib/libthr/pthread.map
@@ -344,5 +344,6 @@ FBSD_1.8 {
};
FBSD_1.9 {
+ pthread_cond_clockwait;
pthread_tryjoin_np;
};
diff --git a/lib/libthr/thread/thr_barrier.c b/lib/libthr/thread/thr_barrier.c
index 13dec864e2f6..e15b1627ee5d 100644
--- a/lib/libthr/thread/thr_barrier.c
+++ b/lib/libthr/thread/thr_barrier.c
@@ -76,7 +76,8 @@ _pthread_barrier_destroy(pthread_barrier_t *barrier)
return (EBUSY);
}
if (bar->b_refcount != 0) {
- _thr_ucond_wait(&bar->b_cv, &bar->b_lock, NULL, 0);
+ _thr_ucond_wait(&bar->b_cv, &bar->b_lock, NULL,
+ NULL, 0);
THR_UMUTEX_LOCK(curthread, &bar->b_lock);
} else
break;
@@ -158,7 +159,8 @@ _pthread_barrier_wait(pthread_barrier_t *barrier)
cycle = bar->b_cycle;
bar->b_refcount++;
do {
- _thr_ucond_wait(&bar->b_cv, &bar->b_lock, NULL, 0);
+ _thr_ucond_wait(&bar->b_cv, &bar->b_lock, NULL,
+ NULL, 0);
THR_UMUTEX_LOCK(curthread, &bar->b_lock);
/* test cycle to avoid bogus wakeup */
} while (cycle == bar->b_cycle);
diff --git a/lib/libthr/thread/thr_cond.c b/lib/libthr/thread/thr_cond.c
index f8c9118968bb..cce2ba7b6c3c 100644
--- a/lib/libthr/thread/thr_cond.c
+++ b/lib/libthr/thread/thr_cond.c
@@ -46,11 +46,14 @@ _Static_assert(sizeof(struct pthread_cond) <= THR_PAGE_SIZE_MIN,
/*
* Prototypes
*/
+int __pthread_cond_clockwait(pthread_cond_t *cond, pthread_mutex_t *mutex,
+ clockid_t clockid, const struct timespec *abstime);
int __pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex,
const struct timespec * abstime);
static int cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr);
static int cond_wait_common(pthread_cond_t *cond, pthread_mutex_t *mutex,
- const struct timespec *abstime, bool cancel);
+ clockid_t clockid, const struct timespec *abstime, bool cancel,
+ bool clockwait);
static int cond_signal_common(pthread_cond_t *cond);
static int cond_broadcast_common(pthread_cond_t *cond);
@@ -64,6 +67,7 @@ __weak_reference(__thr_cond_wait, __pthread_cond_wait);
__weak_reference(_thr_cond_wait, _pthread_cond_wait);
__weak_reference(__pthread_cond_timedwait, pthread_cond_timedwait);
__weak_reference(_thr_cond_timedwait, _pthread_cond_timedwait);
+__weak_reference(__pthread_cond_clockwait, pthread_cond_clockwait);
__weak_reference(_thr_cond_init, pthread_cond_init);
__weak_reference(_thr_cond_init, _pthread_cond_init);
__weak_reference(_thr_cond_destroy, pthread_cond_destroy);
@@ -202,9 +206,11 @@ _thr_cond_destroy(pthread_cond_t *cond)
*/
static int
cond_wait_kernel(struct pthread_cond *cvp, struct pthread_mutex *mp,
- const struct timespec *abstime, bool cancel)
+ clockid_t clockid, const struct timespec *abstime, bool cancel,
+ bool clockwait)
{
struct pthread *curthread;
+ struct _umtx_time utime;
int error, error2, recurse, robust;
curthread = _get_curthread();
@@ -219,8 +225,16 @@ cond_wait_kernel(struct pthread_cond *cvp, struct pthread_mutex *mp,
if (cancel)
_thr_cancel_enter2(curthread, 0);
- error = _thr_ucond_wait(&cvp->kcond, &mp->m_lock, abstime,
- CVWAIT_ABSTIME | CVWAIT_CLOCKID);
+ if (clockwait) {
+ utime._timeout = *abstime;
+ utime._flags = UMTX_ABSTIME;
+ utime._clockid = clockid;
+ error = _thr_ucond_wait(&cvp->kcond, &mp->m_lock, NULL,
+ &utime, CVWAIT_UMTX_TIME);
+ } else {
+ error = _thr_ucond_wait(&cvp->kcond, &mp->m_lock, abstime,
+ NULL, CVWAIT_ABSTIME | CVWAIT_CLOCKID);
+ }
if (cancel)
_thr_cancel_leave(curthread, 0);
@@ -274,7 +288,7 @@ cond_wait_kernel(struct pthread_cond *cvp, struct pthread_mutex *mp,
static int
cond_wait_user(struct pthread_cond *cvp, struct pthread_mutex *mp,
- const struct timespec *abstime, bool cancel)
+ clockid_t clockid, const struct timespec *abstime, bool cancel)
{
struct pthread *curthread;
struct sleepqueue *sq;
@@ -315,7 +329,7 @@ cond_wait_user(struct pthread_cond *cvp, struct pthread_mutex *mp,
if (cancel)
_thr_cancel_enter2(curthread, 0);
- error = _thr_sleep(curthread, cvp->kcond.c_clockid, abstime);
+ error = _thr_sleep(curthread, clockid, abstime);
if (cancel)
_thr_cancel_leave(curthread, 0);
@@ -350,7 +364,8 @@ cond_wait_user(struct pthread_cond *cvp, struct pthread_mutex *mp,
static int
cond_wait_common(pthread_cond_t *cond, pthread_mutex_t *mutex,
- const struct timespec *abstime, bool cancel)
+ clockid_t clockid, const struct timespec *abstime, bool cancel,
+ bool clockwait)
{
struct pthread *curthread = _get_curthread();
struct pthread_cond *cvp;
@@ -359,6 +374,9 @@ cond_wait_common(pthread_cond_t *cond, pthread_mutex_t *mutex,
CHECK_AND_INIT_COND
+ if (!clockwait)
+ clockid = cvp->kcond.c_clockid;
+
if (*mutex == THR_PSHARED_PTR) {
mp = __thr_pshared_offpage(mutex, 0);
if (mp == NULL)
@@ -372,23 +390,25 @@ cond_wait_common(pthread_cond_t *cond, pthread_mutex_t *mutex,
if (curthread->attr.sched_policy != SCHED_OTHER ||
(mp->m_lock.m_flags & (UMUTEX_PRIO_PROTECT | UMUTEX_PRIO_INHERIT |
- USYNC_PROCESS_SHARED)) != 0 || CV_PSHARED(cvp))
- return (cond_wait_kernel(cvp, mp, abstime, cancel));
- else
- return (cond_wait_user(cvp, mp, abstime, cancel));
+ USYNC_PROCESS_SHARED)) != 0 || CV_PSHARED(cvp)) {
+ return (cond_wait_kernel(cvp, mp, clockid, abstime, cancel,
+ clockwait));
+ } else {
+ return (cond_wait_user(cvp, mp, clockid, abstime, cancel));
+ }
}
int
_thr_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
{
- return (cond_wait_common(cond, mutex, NULL, false));
+ return (cond_wait_common(cond, mutex, 0, NULL, false, false));
}
int
__thr_cond_wait(pthread_cond_t * __restrict cond,
pthread_mutex_t * __restrict mutex)
{
- return (cond_wait_common(cond, mutex, NULL, true));
+ return (cond_wait_common(cond, mutex, 0, NULL, true, false));
}
int
@@ -400,18 +420,30 @@ _thr_cond_timedwait(pthread_cond_t * __restrict cond,
abstime->tv_nsec >= 1000000000)
return (EINVAL);
- return (cond_wait_common(cond, mutex, abstime, false));
+ return (cond_wait_common(cond, mutex, 0, abstime, false, false));
}
int
__pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex,
- const struct timespec *abstime)
+ const struct timespec *abstime)
{
if (abstime == NULL || abstime->tv_sec < 0 || abstime->tv_nsec < 0 ||
abstime->tv_nsec >= 1000000000)
return (EINVAL);
- return (cond_wait_common(cond, mutex, abstime, true));
+ return (cond_wait_common(cond, mutex, 0, abstime, true, false));
+}
+
+int
+__pthread_cond_clockwait(pthread_cond_t *cond, pthread_mutex_t *mutex,
+ clockid_t clockid, const struct timespec *abstime)
+{
+
+ if (abstime == NULL || abstime->tv_sec < 0 || abstime->tv_nsec < 0 ||
+ abstime->tv_nsec >= 1000000000)
+ return (EINVAL);
+
+ return (cond_wait_common(cond, mutex, clockid, abstime, true, true));
}
static int
diff --git a/lib/libthr/thread/thr_umtx.c b/lib/libthr/thread/thr_umtx.c
index db63017a6a13..edd0dacdaff1 100644
--- a/lib/libthr/thread/thr_umtx.c
+++ b/lib/libthr/thread/thr_umtx.c
@@ -28,6 +28,7 @@
#include "thr_private.h"
#include "thr_umtx.h"
+#include <assert.h>
void
_thr_umutex_init(struct umutex *mtx)
@@ -242,20 +243,35 @@ _thr_ucond_init(struct ucond *cv)
int
_thr_ucond_wait(struct ucond *cv, struct umutex *m,
- const struct timespec *timeout, int flags)
+ const struct timespec *timeout, const struct _umtx_time *utimep, int flags)
{
struct pthread *curthread;
-
- if (timeout != NULL && (timeout->tv_sec < 0 || (timeout->tv_sec == 0 &&
- timeout->tv_nsec <= 0))) {
+ const struct timespec *ts;
+ void *arg2;
+
+ assert(timeout == NULL || utimep == NULL);
+ if (timeout != NULL) {
+ ts = timeout;
+ arg2 = __DECONST(void *, timeout);
+ assert((flags & CVWAIT_UMTX_TIME) == 0);
+ } else if (utimep != NULL) {
+ ts = &utimep->_timeout;
+ arg2 = __DECONST(void *, utimep);
+ assert((flags & CVWAIT_UMTX_TIME) != 0);
+ } else {
+ ts = NULL;
+ arg2 = NULL;
+ assert((flags & CVWAIT_UMTX_TIME) == 0);
+ }
+ if (ts != NULL && (ts->tv_sec < 0 || (ts->tv_sec == 0 &&
+ ts->tv_nsec <= 0))) {
curthread = _get_curthread();
_thr_umutex_unlock(m, TID(curthread));
return (ETIMEDOUT);
}
- return (_umtx_op_err(cv, UMTX_OP_CV_WAIT, flags, m,
- __DECONST(void *, timeout)));
+ return (_umtx_op_err(cv, UMTX_OP_CV_WAIT, flags, m, arg2));
}
-
+
int
_thr_ucond_signal(struct ucond *cv)
{
diff --git a/lib/libthr/thread/thr_umtx.h b/lib/libthr/thread/thr_umtx.h
index 89f70e4ab14f..4e1c08ca64e8 100644
--- a/lib/libthr/thread/thr_umtx.h
+++ b/lib/libthr/thread/thr_umtx.h
@@ -59,7 +59,8 @@ int _thr_umtx_timedwait_uint(volatile u_int *mtx, u_int exp, int clockid,
const struct timespec *timeout, int shared) __hidden;
int _thr_umtx_wake(volatile void *mtx, int count, int shared) __hidden;
int _thr_ucond_wait(struct ucond *cv, struct umutex *m,
- const struct timespec *timeout, int flags) __hidden;
+ const struct timespec *timeout, const struct _umtx_time *utimep,
+ int flags) __hidden;
void _thr_ucond_init(struct ucond *cv) __hidden;
int _thr_ucond_signal(struct ucond *cv) __hidden;
int _thr_ucond_broadcast(struct ucond *cv) __hidden;