|
|
Message-Id: <f21ea165c38a4dfc9ac0b9a5b95f2a5622697213.1498228733.git.Jens.Gustedt@inria.fr>
Date: Tue, 20 Jun 2017 22:35:28 +0200
From: Jens Gustedt <Jens.Gustedt@...ia.fr>
To: musl@...ts.openwall.com
Subject: [PATCH 4/8] determine the existence of private futexes at the first
thread creation
The current strategie to deal with kernels that don't implement private
futexes is to
- test if the call works with FUTEX_PRIVATE
- fallback to a call without if it doesn't
This forces an overhead for both sides, Linux'es with and without private
futexes. For those with, it adds a superflouous branch instruction to all
calls. For those without, it add the whole call overhead of a syscall.
The idea of this patch is simple. We determine dynamically but only once
when we switch from 1 thread to multiple threads if private futexes are
implemented. This reduces the overhead to
- one system call in total
- one load of a global and an OR of the flags at each futex call
In addition this system call will be as short as possible, because it
futexes on a local variable where nobody is to woken, and all this is in
a context (thread creation) that is clearly dominated by a lot of other
things.
This patch also clears an inconsistency in the code that had
FUTEX_PRIVATE written out as 128 in many places, which made it really
hard to digest and to identify what was going on.
---
src/internal/pthread_impl.h | 11 +++++------
src/thread/__timedwait.c | 3 +--
src/thread/__wait.c | 5 ++---
src/thread/pthread_barrier_wait.c | 3 +--
src/thread/pthread_cond_timedwait.c | 3 +--
src/thread/pthread_create.c | 10 +++++++++-
6 files changed, 19 insertions(+), 16 deletions(-)
diff --git a/src/internal/pthread_impl.h b/src/internal/pthread_impl.h
index e1dd4421..02929e07 100644
--- a/src/internal/pthread_impl.h
+++ b/src/internal/pthread_impl.h
@@ -126,18 +126,17 @@ void __vm_unlock(void);
int __timedwait(volatile int *, int, clockid_t, const struct timespec *, int);
int __timedwait_cp(volatile int *, int, clockid_t, const struct timespec *, int);
void __wait(volatile int *, volatile int *, int, int);
+extern int __futex_private;
static inline void __wake(volatile void *addr, int cnt, int priv)
{
- if (priv) priv = 128;
+ if (priv) priv = __futex_private;
if (cnt<0) cnt = INT_MAX;
- __syscall(SYS_futex, addr, FUTEX_WAKE|priv, cnt) != -ENOSYS ||
- __syscall(SYS_futex, addr, FUTEX_WAKE, cnt);
+ __syscall(SYS_futex, addr, FUTEX_WAKE|priv, cnt);
}
static inline void __futexwait(volatile void *addr, int val, int priv)
{
- if (priv) priv = 128;
- __syscall(SYS_futex, addr, FUTEX_WAIT|priv, val) != -ENOSYS ||
- __syscall(SYS_futex, addr, FUTEX_WAIT, val);
+ if (priv) priv = __futex_private;
+ __syscall(SYS_futex, addr, FUTEX_WAIT|priv, val);
}
void __acquire_ptc(void);
diff --git a/src/thread/__timedwait.c b/src/thread/__timedwait.c
index 13d8465a..7f0f03e6 100644
--- a/src/thread/__timedwait.c
+++ b/src/thread/__timedwait.c
@@ -14,7 +14,7 @@ int __timedwait_cp(volatile int *addr, int val,
int r;
struct timespec to, *top=0;
- if (priv) priv = 128;
+ if (priv) priv = __futex_private;
if (at) {
if (at->tv_nsec >= 1000000000UL) return EINVAL;
@@ -29,7 +29,6 @@ int __timedwait_cp(volatile int *addr, int val,
}
r = -__syscall_cp(SYS_futex, addr, FUTEX_WAIT|priv, val, top);
- if (r == ENOSYS) r = -__syscall_cp(SYS_futex, addr, FUTEX_WAIT, val, top);
if (r != EINTR && r != ETIMEDOUT && r != ECANCELED) r = 0;
return r;
diff --git a/src/thread/__wait.c b/src/thread/__wait.c
index dc33c1a3..a3391b79 100644
--- a/src/thread/__wait.c
+++ b/src/thread/__wait.c
@@ -3,15 +3,14 @@
void __wait(volatile int *addr, volatile int *waiters, int val, int priv)
{
int spins=100;
- if (priv) priv = FUTEX_PRIVATE;
+ if (priv) priv = __futex_private;
while (spins-- && (!waiters || !*waiters)) {
if (*addr==val) a_spin();
else return;
}
if (waiters) a_inc(waiters);
while (*addr==val) {
- __syscall(SYS_futex, addr, FUTEX_WAIT|priv, val, 0) != -ENOSYS
- || __syscall(SYS_futex, addr, FUTEX_WAIT, val, 0);
+ __syscall(SYS_futex, addr, FUTEX_WAIT|priv, val, 0);
}
if (waiters) a_dec(waiters);
}
diff --git a/src/thread/pthread_barrier_wait.c b/src/thread/pthread_barrier_wait.c
index 06b83db9..a89051e5 100644
--- a/src/thread/pthread_barrier_wait.c
+++ b/src/thread/pthread_barrier_wait.c
@@ -84,8 +84,7 @@ int pthread_barrier_wait(pthread_barrier_t *b)
a_spin();
a_inc(&inst->finished);
while (inst->finished == 1)
- __syscall(SYS_futex,&inst->finished,FUTEX_WAIT|128,1,0) != -ENOSYS
- || __syscall(SYS_futex,&inst->finished,FUTEX_WAIT,1,0);
+ __syscall(SYS_futex,&inst->finished,FUTEX_WAIT|__futex_private,1,0);
return PTHREAD_BARRIER_SERIAL_THREAD;
}
diff --git a/src/thread/pthread_cond_timedwait.c b/src/thread/pthread_cond_timedwait.c
index 3526ecfb..6d92ea88 100644
--- a/src/thread/pthread_cond_timedwait.c
+++ b/src/thread/pthread_cond_timedwait.c
@@ -54,8 +54,7 @@ static inline void unlock_requeue(volatile int *l, volatile int *r, int w)
{
a_store(l, 0);
if (w) __wake(l, 1, 1);
- else __syscall(SYS_futex, l, FUTEX_REQUEUE|128, 0, 1, r) != -ENOSYS
- || __syscall(SYS_futex, l, FUTEX_REQUEUE, 0, 1, r);
+ else __syscall(SYS_futex, l, FUTEX_REQUEUE|__futex_private, 0, 1, r);
}
enum {
diff --git a/src/thread/pthread_create.c b/src/thread/pthread_create.c
index ca5c6b90..26945022 100644
--- a/src/thread/pthread_create.c
+++ b/src/thread/pthread_create.c
@@ -10,6 +10,8 @@ void *__mmap(void *, size_t, int, int, int, off_t);
int __munmap(void *, size_t);
int __mprotect(void *, size_t, int);
+int __futex_private = 0;
+
static void dummy_0()
{
}
@@ -277,7 +279,13 @@ int __pthread_create(pthread_t *restrict res, const pthread_attr_t *restrict att
new->unblock_cancel = self->cancel;
new->CANARY = self->CANARY;
- a_inc(&libc.threads_minus_1);
+ if (!a_fetch_add(&libc.threads_minus_1, 1)) {
+ // As long as we only have one thread, test if this supports
+ // private futexes.
+ __lock_t dummy = { 0 };
+ if (__syscall(SYS_futex, dummy.lc, FUTEX_WAKE|FUTEX_PRIVATE, 0) != -ENOSYS)
+ __futex_private = FUTEX_PRIVATE;
+ }
ret = __clone((c11 ? start_c11 : start), stack, flags, new, &new->tid, TP_ADJ(new), &new->tid);
__release_ptc();
Powered by blists - more mailing lists
Confused about mailing lists and their use? Read about mailing lists on Wikipedia and check out these guidelines on proper formatting of your messages.