summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRich Felker <dalias@aerifal.cx>2019-07-28 17:44:51 -0400
committerRich Felker <dalias@aerifal.cx>2019-07-28 17:44:51 -0400
commit1492bdf53c70f436b0fc2a7238011f9786bf4cd5 (patch)
tree3c4a0b830c8bc8c24d2ad9d25d57cf8f56bfb683
parenteb2e298cdc814493a6ced8c05cf0d0f5cccc8b63 (diff)
downloadmusl-1492bdf53c70f436b0fc2a7238011f9786bf4cd5.tar.gz
futex wait operations: add time64 syscall support, decouple 32-bit time_t
thanks to the original factorization using the __timedwait function, there are no FUTEX_WAIT calls anywhere else, giving us a single point of change to make nearly all the timed thread primitives time64-ready. the one exception is the FUTEX_LOCK_PI command for PI mutex timedlock. I haven't tried to make these two points share code, since they have different fallbacks (no non-private fallback needed for PI since PI was added later) and FUTEX_LOCK_PI isn't a cancellation point (thus allowing the whole code path to inline into pthread_mutex_timedlock). as for other changes in this series, the time64 syscall is used only if it's the only one defined for the arch, or if the requested timeout does not fit in 32 bits. on current 32-bit archs where time_t is a 32-bit type, this makes it statically unreachable. on 64-bit archs, there are only superficial changes to the code after preprocessing. on current 32-bit archs, the time is passed via an intermediate copy to remove the assumption that time_t is a 32-bit type.
-rw-r--r--src/thread/__timedwait.c24
-rw-r--r--src/thread/pthread_mutex_timedlock.c20
2 files changed, 41 insertions, 3 deletions
diff --git a/src/thread/__timedwait.c b/src/thread/__timedwait.c
index ae19bd63..666093be 100644
--- a/src/thread/__timedwait.c
+++ b/src/thread/__timedwait.c
@@ -5,6 +5,27 @@
#include "syscall.h"
#include "pthread_impl.h"
+#define IS32BIT(x) !((x)+0x80000000ULL>>32)
+#define CLAMP(x) (int)(IS32BIT(x) ? (x) : 0x7fffffffU+((0ULL+(x))>>63))
+
+static int __futex4_cp(volatile void *addr, int op, int val, const struct timespec *to)
+{
+ int r;
+#ifdef SYS_futex_time64
+ time_t s = to ? to->tv_sec : 0;
+ long ns = to ? to->tv_nsec : 0;
+ r = -ENOSYS;
+ if (SYS_futex == SYS_futex_time64 || !IS32BIT(s))
+ r = __syscall_cp(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
+ r = __syscall_cp(SYS_futex, addr, op, val, to);
+ if (r != -ENOSYS) return r;
+ return __syscall_cp(SYS_futex, addr, op & ~FUTEX_PRIVATE, val, to);
+}
+
static volatile int dummy = 0;
weak_alias(dummy, __eintr_valid_flag);
@@ -28,8 +49,7 @@ int __timedwait_cp(volatile int *addr, int val,
top = &to;
}
- r = -__syscall_cp(SYS_futex, addr, FUTEX_WAIT|priv, val, top);
- if (r == ENOSYS) r = -__syscall_cp(SYS_futex, addr, FUTEX_WAIT, val, top);
+ r = -__futex4_cp(addr, FUTEX_WAIT|priv, val, top);
if (r != EINTR && r != ETIMEDOUT && r != ECANCELED) r = 0;
/* Mitigate bug in old kernels wrongly reporting EINTR for non-
* interrupting (SA_RESTART) signal handlers. This is only practical
diff --git a/src/thread/pthread_mutex_timedlock.c b/src/thread/pthread_mutex_timedlock.c
index 6b893627..9279fc54 100644
--- a/src/thread/pthread_mutex_timedlock.c
+++ b/src/thread/pthread_mutex_timedlock.c
@@ -1,5 +1,23 @@
#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;
@@ -9,7 +27,7 @@ static int pthread_mutex_timedlock_pi(pthread_mutex_t *restrict m, const struct
if (!priv) self->robust_list.pending = &m->_m_next;
- do e = -__syscall(SYS_futex, &m->_m_lock, FUTEX_LOCK_PI|priv, 0, at);
+ do e = -__futex4(&m->_m_lock, FUTEX_LOCK_PI|priv, 0, at);
while (e==EINTR);
if (e) self->robust_list.pending = 0;