mailing list of musl libc
 help / color / mirror / code / Atom feed
* [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).