* [musl] [PATCH] Implement pthread_mutex_clocklock
@ 2026-02-20 20:43 Laurent Bercot
0 siblings, 0 replies; only message in thread
From: Laurent Bercot @ 2026-02-20 20:43 UTC (permalink / raw)
To: musl@lists.openwall.com
[-- Attachment #1: Type: text/plain, Size: 605 bytes --]
Hello,
This patch implements the new pthread_mutex_clocklock() function,
defined in The Open Group Base Specifications Issue 8:
https://pubs.opengroup.org/onlinepubs/9799919799/functions/pthread_mutex_clocklock.html
It basically renames pthread_mutex_timedlock.c into
pthread_mutex_clocklock.c, adds a clockid_t parameter where appropriate,
and rewrites pthread_mutex_timedlock() as a trivial wrapper.
The futex() system call should probably also use the
FUTEX_CLOCK_REALTIME flag when the clockid is CLOCK_REALTIME, but that
can be added in a subsequent patch.
--
Laurent
[-- Attachment #2: 0001-Implement-pthread_mutex_clocklock.patch --]
[-- Type: application/octet-stream, Size: 8336 bytes --]
From 9d03f69e1b499966ff371a3bb491c12f5c730c2a Mon Sep 17 00:00:00 2001
From: Laurent Bercot <ska-skaware@skarnet.org>
Date: Sat, 14 Feb 2026 12:23:20 +0000
Subject: [PATCH] Implement pthread_mutex_clocklock()
pthread_mutex_clocklock() is defined in The Open Group Base
Specifications Issue 8:
https://pubs.opengroup.org/onlinepubs/9799919799/functions/pthread_mutex_clocklock.html
Compared to pthread_mutex_timedlock(), it just takes an additional
parameter defining the clock to use. So we copy the existing
pthread_mutex_timedlock() implementation, changing every instance
of __timedwait() with CLOCK_REALTIME to use the extra parameter.
pthread_mutex_timedlock() then becomes a thin wrapper around
the new pthread_mutex_clocklock().
---
include/pthread.h | 1 +
src/include/pthread.h | 1 +
src/thread/pthread_mutex_clocklock.c | 92 ++++++++++++++++++++++++++++
src/thread/pthread_mutex_timedlock.c | 86 +-------------------------
4 files changed, 95 insertions(+), 85 deletions(-)
create mode 100644 src/thread/pthread_mutex_clocklock.c
diff --git a/include/pthread.h b/include/pthread.h
index 89fd9ff7..cf6a5d31 100644
--- a/include/pthread.h
+++ b/include/pthread.h
@@ -107,6 +107,7 @@ int pthread_mutex_init(pthread_mutex_t *__restrict, const pthread_mutexattr_t *_
int pthread_mutex_lock(pthread_mutex_t *);
int pthread_mutex_unlock(pthread_mutex_t *);
int pthread_mutex_trylock(pthread_mutex_t *);
+int pthread_mutex_clocklock(pthread_mutex_t *__restrict, clockid_t, const struct timespec *__restrict);
int pthread_mutex_timedlock(pthread_mutex_t *__restrict, const struct timespec *__restrict);
int pthread_mutex_destroy(pthread_mutex_t *);
int pthread_mutex_consistent(pthread_mutex_t *);
diff --git a/src/include/pthread.h b/src/include/pthread.h
index 7167d3e1..49b63f3d 100644
--- a/src/include/pthread.h
+++ b/src/include/pthread.h
@@ -12,6 +12,7 @@ hidden int __pthread_join(pthread_t, void **);
hidden int __pthread_mutex_lock(pthread_mutex_t *);
hidden int __pthread_mutex_trylock(pthread_mutex_t *);
hidden int __pthread_mutex_trylock_owner(pthread_mutex_t *);
+hidden int __pthread_mutex_clocklock(pthread_mutex_t *restrict, clockid_t, const struct timespec *restrict);
hidden int __pthread_mutex_timedlock(pthread_mutex_t *restrict, const struct timespec *restrict);
hidden int __pthread_mutex_unlock(pthread_mutex_t *);
hidden int __private_cond_signal(pthread_cond_t *, int);
diff --git a/src/thread/pthread_mutex_clocklock.c b/src/thread/pthread_mutex_clocklock.c
new file mode 100644
index 00000000..32f99356
--- /dev/null
+++ b/src/thread/pthread_mutex_clocklock.c
@@ -0,0 +1,92 @@
+#include "pthread_impl.h"
+
+#define IS32BIT(x) !((x)+0x80000000ULL>>32)
+#define CLAMP(x) (int)(IS32BIT(x) ? (x) : 0x7fffffffU+((0ULL+(x))>>63))
+
+static int __futex4(volatile void *addr, int op, int val, const struct timespec *to)
+{
+#ifdef SYS_futex_time64
+ time_t s = to ? to->tv_sec : 0;
+ long ns = to ? to->tv_nsec : 0;
+ int r = -ENOSYS;
+ if (SYS_futex == SYS_futex_time64 || !IS32BIT(s))
+ r = __syscall(SYS_futex_time64, addr, op, val,
+ to ? ((long long[]){s, ns}) : 0);
+ if (SYS_futex == SYS_futex_time64 || r!=-ENOSYS) return r;
+ to = to ? (void *)(long[]){CLAMP(s), ns} : 0;
+#endif
+ return __syscall(SYS_futex, addr, op, val, to);
+}
+
+static int pthread_mutex_clocklock_pi(pthread_mutex_t *restrict m, clockid_t clock, const struct timespec *restrict at)
+{
+ int type = m->_m_type;
+ int priv = (type & 128) ^ 128;
+ pthread_t self = __pthread_self();
+ int e;
+
+ if (!priv) self->robust_list.pending = &m->_m_next;
+
+ do e = -__futex4(&m->_m_lock, FUTEX_LOCK_PI|priv, 0, at);
+ while (e==EINTR);
+ if (e) self->robust_list.pending = 0;
+
+ switch (e) {
+ case 0:
+ /* Catch spurious success for non-robust mutexes. */
+ if (!(type&4) && ((m->_m_lock & 0x40000000) || m->_m_waiters)) {
+ a_store(&m->_m_waiters, -1);
+ __syscall(SYS_futex, &m->_m_lock, FUTEX_UNLOCK_PI|priv);
+ self->robust_list.pending = 0;
+ break;
+ }
+ /* Signal to trylock that we already have the lock. */
+ m->_m_count = -1;
+ return __pthread_mutex_trylock(m);
+ case ETIMEDOUT:
+ return e;
+ case EDEADLK:
+ if ((type&3) == PTHREAD_MUTEX_ERRORCHECK) return e;
+ }
+ do e = __timedwait(&(int){0}, 0, clock, at, 1);
+ while (e != ETIMEDOUT);
+ return e;
+}
+
+int __pthread_mutex_clocklock(pthread_mutex_t *restrict m, clockid_t clock, const struct timespec *restrict at)
+{
+ if ((m->_m_type&15) == PTHREAD_MUTEX_NORMAL
+ && !a_cas(&m->_m_lock, 0, EBUSY))
+ return 0;
+
+ int type = m->_m_type;
+ int r, t, priv = (type & 128) ^ 128;
+
+ r = __pthread_mutex_trylock(m);
+ if (r != EBUSY) return r;
+
+ if (type&8) return pthread_mutex_clocklock_pi(m, clock, at);
+
+ int spins = 100;
+ while (spins-- && m->_m_lock && !m->_m_waiters) a_spin();
+
+ while ((r=__pthread_mutex_trylock(m)) == EBUSY) {
+ r = m->_m_lock;
+ int own = r & 0x3fffffff;
+ if (!own && (!r || (type&4)))
+ continue;
+ if ((type&3) == PTHREAD_MUTEX_ERRORCHECK
+ && own == __pthread_self()->tid)
+ return EDEADLK;
+
+ a_inc(&m->_m_waiters);
+ t = r | 0x80000000;
+ a_cas(&m->_m_lock, r, t);
+ r = __timedwait(&m->_m_lock, t, clock, at, priv);
+ a_dec(&m->_m_waiters);
+ if (r && r != EINTR) break;
+ }
+ return r;
+}
+
+weak_alias(__pthread_mutex_clocklock, pthread_mutex_clocklock);
diff --git a/src/thread/pthread_mutex_timedlock.c b/src/thread/pthread_mutex_timedlock.c
index 9279fc54..14a87065 100644
--- a/src/thread/pthread_mutex_timedlock.c
+++ b/src/thread/pthread_mutex_timedlock.c
@@ -1,92 +1,8 @@
#include "pthread_impl.h"
-#define IS32BIT(x) !((x)+0x80000000ULL>>32)
-#define CLAMP(x) (int)(IS32BIT(x) ? (x) : 0x7fffffffU+((0ULL+(x))>>63))
-
-static int __futex4(volatile void *addr, int op, int val, const struct timespec *to)
-{
-#ifdef SYS_futex_time64
- time_t s = to ? to->tv_sec : 0;
- long ns = to ? to->tv_nsec : 0;
- int r = -ENOSYS;
- if (SYS_futex == SYS_futex_time64 || !IS32BIT(s))
- r = __syscall(SYS_futex_time64, addr, op, val,
- to ? ((long long[]){s, ns}) : 0);
- if (SYS_futex == SYS_futex_time64 || r!=-ENOSYS) return r;
- to = to ? (void *)(long[]){CLAMP(s), ns} : 0;
-#endif
- return __syscall(SYS_futex, addr, op, val, to);
-}
-
-static int pthread_mutex_timedlock_pi(pthread_mutex_t *restrict m, const struct timespec *restrict at)
-{
- int type = m->_m_type;
- int priv = (type & 128) ^ 128;
- pthread_t self = __pthread_self();
- int e;
-
- if (!priv) self->robust_list.pending = &m->_m_next;
-
- do e = -__futex4(&m->_m_lock, FUTEX_LOCK_PI|priv, 0, at);
- while (e==EINTR);
- if (e) self->robust_list.pending = 0;
-
- switch (e) {
- case 0:
- /* Catch spurious success for non-robust mutexes. */
- if (!(type&4) && ((m->_m_lock & 0x40000000) || m->_m_waiters)) {
- a_store(&m->_m_waiters, -1);
- __syscall(SYS_futex, &m->_m_lock, FUTEX_UNLOCK_PI|priv);
- self->robust_list.pending = 0;
- break;
- }
- /* Signal to trylock that we already have the lock. */
- m->_m_count = -1;
- return __pthread_mutex_trylock(m);
- case ETIMEDOUT:
- return e;
- case EDEADLK:
- if ((type&3) == PTHREAD_MUTEX_ERRORCHECK) return e;
- }
- do e = __timedwait(&(int){0}, 0, CLOCK_REALTIME, at, 1);
- while (e != ETIMEDOUT);
- return e;
-}
-
int __pthread_mutex_timedlock(pthread_mutex_t *restrict m, const struct timespec *restrict at)
{
- if ((m->_m_type&15) == PTHREAD_MUTEX_NORMAL
- && !a_cas(&m->_m_lock, 0, EBUSY))
- return 0;
-
- int type = m->_m_type;
- int r, t, priv = (type & 128) ^ 128;
-
- r = __pthread_mutex_trylock(m);
- if (r != EBUSY) return r;
-
- if (type&8) return pthread_mutex_timedlock_pi(m, at);
-
- int spins = 100;
- while (spins-- && m->_m_lock && !m->_m_waiters) a_spin();
-
- while ((r=__pthread_mutex_trylock(m)) == EBUSY) {
- r = m->_m_lock;
- int own = r & 0x3fffffff;
- if (!own && (!r || (type&4)))
- continue;
- if ((type&3) == PTHREAD_MUTEX_ERRORCHECK
- && own == __pthread_self()->tid)
- return EDEADLK;
-
- a_inc(&m->_m_waiters);
- t = r | 0x80000000;
- a_cas(&m->_m_lock, r, t);
- r = __timedwait(&m->_m_lock, t, CLOCK_REALTIME, at, priv);
- a_dec(&m->_m_waiters);
- if (r && r != EINTR) break;
- }
- return r;
+ return __pthread_mutex_clocklock(m, CLOCK_REALTIME, at);
}
weak_alias(__pthread_mutex_timedlock, pthread_mutex_timedlock);
--
2.49.0
^ permalink raw reply related [flat|nested] only message in thread
only message in thread, other threads:[~2026-02-20 20:43 UTC | newest]
Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-02-20 20:43 [musl] [PATCH] Implement pthread_mutex_clocklock Laurent Bercot
Code repositories for project(s) associated with this public inbox
https://git.vuxu.org/mirror/musl/
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).