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
This commit is contained in:
Konstantin Belousov committed 2026-07-27 19:17:28 +03:00
1 parent 149d3e5fcb
commit e1136fbcab
6 files changed
+82 -25

No files matched your search

+5
View File
@@ -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);
+1
View File
@@ -344,5 +344,6 @@ FBSD_1.8 {
};
FBSD_1.9 {
pthread_cond_clockwait;
pthread_tryjoin_np;
};
+4 -2
View File
@@ -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);
+48 -16
View File
@@ -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
+22 -6
View File
@@ -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;
const struct timespec *ts;
void *arg2;
if (timeout != NULL && (timeout->tv_sec < 0 || (timeout->tv_sec == 0 &&
timeout->tv_nsec <= 0))) {
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)
{
+2 -1
View File
@@ -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;