git: e1136fbcab18 - main - libthr: implement pthread_cond_clockwait(3)

Konstantin Belousov <[email protected]>
Newsgroups gmane.os.freebsd.devel.cvs.src
Message-ID <6a6784b4.1e302.52074cf8__10816.3115613692$1785169123$gmane$org@gitrepo.freebsd.org>
The branch main has been updated by kib:

URL: https://cgit.FreeBSD.org/src/commit/?id=e1136fbcab184b8fb87456ca0d115d502bab6643

commit e1136fbcab184b8fb87456ca0d115d502bab6643
Author:     Konstantin Belousov <[email protected]>
AuthorDate: 2026-07-25 23:45:11 +0000
Commit:     Konstantin Belousov <[email protected]>
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;
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.