Skip to content
Snippets Groups Projects
Commit 1e1fad4a authored by André Almeida's avatar André Almeida
Browse files

futex2: Adapt glibc to use futex2

Add a new low level lock interface to use futex2 syscall. Adapt the
current timed waiters to use absolute timeout, instead of relative ones.
Add FUTEX_32 flag to all futex2 calls.
parent 3de512be
No related branches found
No related tags found
No related merge requests found
......@@ -53,6 +53,7 @@ __lll_clocklock_wait (int *futex, int val, clockid_t clockid,
return ETIMEDOUT;
tsp = &ts;
private |= (clockid == CLOCK_REALTIME ? FUTEX_CLOCK_REALTIME : 0);
}
/* If *futex == val, wait until woken or timeout. */
......
......@@ -67,10 +67,12 @@ clockwait_tid (pid_t *tidp, clockid_t clockid, const struct timespec *abstime)
if (rt.tv_sec < 0)
return ETIMEDOUT;
int flags = (clockid == CLOCK_REALTIME ? FUTEX_CLOCK_REALTIME : 0) | LLL_SHARED;
/* If *tidp == tid, wait until thread terminates or the wait times out.
The kernel up to version 3.16.3 does not use the private futex
operations for futex wake-up when the clone terminates. */
if (lll_futex_timed_wait_cancel (tidp, tid, &rt, LLL_SHARED)
if (lll_futex_timed_wait_cancel (tidp, tid, abstime, flags)
== -ETIMEDOUT)
return ETIMEDOUT;
}
......
......@@ -564,9 +564,11 @@ __pthread_mutex_clocklock_common (pthread_mutex_t *mutex,
goto failpp;
}
int flags = CLOCK_REALTIME | PTHREAD_MUTEX_PSHARED (mutex);
lll_futex_timed_wait (&mutex->__data.__lock,
ceilval | 2, &rt,
PTHREAD_MUTEX_PSHARED (mutex));
ceilval | 2, abstime,
flags);
}
}
while (atomic_compare_and_exchange_val_acq (&mutex->__data.__lock,
......
......@@ -298,7 +298,7 @@ __pthread_mutex_trylock (pthread_mutex_t *mutex)
? PTHREAD_ROBUST_MUTEX_PSHARED (mutex)
: PTHREAD_MUTEX_PSHARED (mutex));
int e = INTERNAL_SYSCALL_CALL (futex, &mutex->__data.__lock,
__lll_private_flag (FUTEX_TRYLOCK_PI,
__lll_private_flag_old (FUTEX_TRYLOCK_PI,
private), 0, 0);
if (INTERNAL_SYSCALL_ERROR_P (e)
......
......@@ -125,7 +125,7 @@ while (<SOVERSIONS>) {
next if ($build_mathvec == 0 && $name eq "mvec");
if ($name ne "nss_ldap" && $name ne "db1"
&& $name ne "thread_db"
&& $name ne "nss_test1" && $name ne "libgcc_s") {
&& $name ne "nss_test1" && $name ne "nss_test2" && $name ne "nss_nis" && $name ne "nss_nisplus" && $name ne "libgcc_s") {
$link_libs .= " -l$name";
$versions{$name} = $version;
}
......
......@@ -25,6 +25,7 @@
#include <stdbool.h>
#include <libc-diag.h>
#define NSEC 1000000000
/* This file defines futex operations used internally in glibc. A futex
consists of the so-called futex word in userspace, which is of type
unsigned int and represents an application-specific condition, and kernel
......@@ -213,7 +214,22 @@ static __always_inline int
futex_reltimed_wait (unsigned int* futex_word, unsigned int expected,
const struct timespec* reltime, int private)
{
int err = lll_futex_timed_wait (futex_word, expected, reltime, private);
struct timespec now, abstime;
int err;
if (reltime) {
__clock_gettime (CLOCK_MONOTONIC, &now);
abstime.tv_sec = reltime->tv_sec + now.tv_sec;
abstime.tv_nsec = reltime->tv_nsec + now.tv_nsec;
if (abstime.tv_nsec >= NSEC) {
abstime.tv_sec++;
abstime.tv_nsec -= NSEC;
}
err = lll_futex_timed_wait (futex_word, expected, &abstime, private);
} else {
err = lll_futex_wait (futex_word, expected, private);
}
switch (err)
{
case 0:
......@@ -240,8 +256,25 @@ futex_reltimed_wait_cancelable (unsigned int* futex_word,
const struct timespec* reltime, int private)
{
int oldtype;
struct timespec now, abstime;
int err;
oldtype = LIBC_CANCEL_ASYNC ();
int err = lll_futex_timed_wait (futex_word, expected, reltime, private);
if (reltime) {
__clock_gettime (CLOCK_MONOTONIC, &now);
abstime.tv_nsec = reltime->tv_nsec + now.tv_nsec;
abstime.tv_sec = reltime->tv_sec + now.tv_sec;
if (abstime.tv_nsec >= NSEC) {
abstime.tv_sec++;
abstime.tv_nsec -= NSEC;
}
err = lll_futex_timed_wait (futex_word, expected, &abstime, private);
} else {
err = lll_futex_wait (futex_word, expected, private);
}
LIBC_CANCEL_RESET (oldtype);
switch (err)
{
......
......@@ -41,6 +41,8 @@
#define FUTEX_PRIVATE_FLAG 128
#define FUTEX_CLOCK_REALTIME 256
#define FUTEX_32 2
#define FUTEX_SHARED_FLAG 8
#define FUTEX_BITSET_MATCH_ANY 0xffffffff
/* Values for 'private' parameter of locking macros. Yes, the
......@@ -53,7 +55,7 @@
# if IS_IN (libc) || IS_IN (rtld)
/* In libc.so or ld.so all futexes are private. */
# define __lll_private_flag(fl, private) \
# define __lll_private_flag_old(fl, private) \
({ \
/* Prevent warnings in callers of this macro. */ \
int __lll_private_flag_priv __attribute__ ((unused)); \
......@@ -61,10 +63,25 @@
((fl) | FUTEX_PRIVATE_FLAG); \
})
# else
# define __lll_private_flag(fl, private) \
# define __lll_private_flag_old(fl, private) \
(((fl) | FUTEX_PRIVATE_FLAG) ^ (private))
# endif
# if IS_IN (libc) || IS_IN (rtld)
static inline unsigned int __lll_private_flag(unsigned int flag)
{
return flag & ~FUTEX_PRIVATE_FLAG;
}
# else
static inline unsigned int __lll_private_flag(unsigned int flag)
{
unsigned int ret = flag & ~FUTEX_PRIVATE_FLAG;
ret |= (flag & FUTEX_PRIVATE_FLAG) ? FUTEX_SHARED_FLAG : 0;
return ret;
}
# endif
# define lll_futex_syscall(nargs, futexp, op, ...) \
({ \
long int __ret = INTERNAL_SYSCALL (futex, nargs, futexp, op, \
......@@ -84,10 +101,14 @@
# define lll_futex_wait(futexp, val, private) \
lll_futex_timed_wait (futexp, val, NULL, private)
# define lll_futex_timed_wait(futexp, val, timeout, private) \
lll_futex_syscall (4, futexp, \
__lll_private_flag (FUTEX_WAIT, private), \
val, timeout)
# define lll_futex_timed_wait(futexp, val, timeout, flags) \
({ \
long int __ret = INTERNAL_SYSCALL (futex_wait, 4, futexp, \
val, __lll_private_flag(flags) | FUTEX_32, \
timeout); \
(__glibc_unlikely (INTERNAL_SYSCALL_ERROR_P (__ret)) \
? -INTERNAL_SYSCALL_ERRNO (__ret) : 0); \
})
/* Verify whether the supplied clockid is supported by
lll_futex_clock_wait_bitset. */
......@@ -104,12 +125,9 @@
{ \
const unsigned int clockbit = \
(clockid == CLOCK_REALTIME) ? FUTEX_CLOCK_REALTIME : 0; \
const int op = \
__lll_private_flag (FUTEX_WAIT_BITSET | clockbit, private); \
const int flags = private | clockbit; \
\
__ret = lll_futex_syscall (6, futexp, op, val, \
timeout, NULL /* Unused. */, \
FUTEX_BITSET_MATCH_ANY); \
__ret = lll_futex_timed_wait (futexp, val, timeout, flags); \
} \
else \
__ret = -EINVAL; \
......@@ -118,22 +136,25 @@
/* Wake up up to NR waiters on FUTEXP. */
# define lll_futex_wake(futexp, nr, private) \
lll_futex_syscall (4, futexp, \
__lll_private_flag (FUTEX_WAKE, private), nr, 0)
({ \
long int __ret = INTERNAL_SYSCALL (futex_wake, 3, futexp, \
nr, __lll_private_flag(private) | FUTEX_32);\
(__glibc_unlikely (INTERNAL_SYSCALL_ERROR_P (__ret)) \
? -INTERNAL_SYSCALL_ERRNO (__ret) : 0); \
})
/* Wake up up to NR_WAKE waiters on FUTEXP. Move up to NR_MOVE of the
rest from waiting on FUTEXP to waiting on MUTEX (a different futex).
Returns non-zero if error happened, zero if success. */
# define lll_futex_requeue(futexp, nr_wake, nr_move, mutex, val, private) \
lll_futex_syscall (6, futexp, \
__lll_private_flag (FUTEX_CMP_REQUEUE, private), \
__lll_private_flag_old (FUTEX_CMP_REQUEUE, private), \
nr_wake, nr_move, mutex, val)
/* Wake up up to NR_WAKE waiters on FUTEXP and NR_WAKE2 on FUTEXP2.
Returns non-zero if error happened, zero if success. */
# define lll_futex_wake_unlock(futexp, nr_wake, nr_wake2, futexp2, private) \
lll_futex_syscall (6, futexp, \
__lll_private_flag (FUTEX_WAKE_OP, private), \
__lll_private_flag_old (FUTEX_WAKE_OP, private), \
nr_wake, nr_wake2, futexp2, \
FUTEX_OP_CLEAR_WAKE_IF_GT_ONE)
......@@ -141,12 +162,12 @@
/* Priority Inheritance support. */
#define lll_futex_timed_lock_pi(futexp, abstime, private) \
lll_futex_syscall (4, futexp, \
__lll_private_flag (FUTEX_LOCK_PI, private), \
__lll_private_flag_old (FUTEX_LOCK_PI, private), \
0, abstime)
#define lll_futex_timed_unlock_pi(futexp, private) \
lll_futex_syscall (4, futexp, \
__lll_private_flag (FUTEX_UNLOCK_PI, private), \
__lll_private_flag_old (FUTEX_UNLOCK_PI, private), \
0, 0)
/* Like lll_futex_wait (FUTEXP, VAL, PRIVATE) but with the expectation
......@@ -160,7 +181,7 @@
# define lll_futex_timed_wait_requeue_pi(futexp, val, timeout, clockbit, \
mutex, private) \
lll_futex_syscall (5, futexp, \
__lll_private_flag (FUTEX_WAIT_REQUEUE_PI \
__lll_private_flag_old (FUTEX_WAIT_REQUEUE_PI \
| (clockbit), private), \
val, timeout, mutex)
......@@ -169,7 +190,7 @@
# define lll_futex_cmp_requeue_pi(futexp, nr_wake, nr_move, mutex, \
val, private) \
lll_futex_syscall (6, futexp, \
__lll_private_flag (FUTEX_CMP_REQUEUE_PI, \
__lll_private_flag_old (FUTEX_CMP_REQUEUE_PI, \
private), \
nr_wake, nr_move, mutex, val)
......
......@@ -20,7 +20,7 @@
#define _LOWLEVELLOCK_H 1
#include <atomic.h>
#include <lowlevellock-futex.h>
#include <lowlevellock-futex2.h>
#include <time.h>
/* Low-level locks use a combination of atomic operations (to acquire and
......
......@@ -16,6 +16,7 @@
License along with the GNU C Library; if not, see
<https://www.gnu.org/licenses/>. */
#include <stdio.h>
#include "thrd_priv.h"
int
......@@ -23,7 +24,7 @@ thrd_create (thrd_t *thr, thrd_start_t func, void *arg)
{
_Static_assert (sizeof (thrd_t) == sizeof (pthread_t),
"sizeof (thrd_t) != sizeof (pthread_t)");
puts("hacked");
int err_code = __pthread_create (thr, ATTR_C11_THREAD,
(void* (*) (void*))func, arg);
return thrd_err_map (err_code);
......
......@@ -348,3 +348,6 @@
#define __NR_waitid 247
#define __NR_write 1
#define __NR_writev 20
#define __NR_futex_wait 442
#define __NR_futex_wake 443
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment