[S390,PPC] Implement FUTEX_WAIT_BITSET for timedwait functions
Since the FUTEX_WAIT operation takes a relative timeout, the pthread_cond_timedwait and other timed function implementations have to get a relative timeout from the absolute timeout parameter it gets before it makes the futex syscall. This value is then converted back into an absolute timeout within the kernel. This is a waste and has hence been improved upon by a FUTEX_WAIT_BITSET operation (OR'd with FUTEX_CLOCK_REALTIME to make the kernel use the realtime clock instead of the default monotonic clock). This was implemented only in the x86 and sh assembly code and not in the C code. This patch implements support for FUTEX_WAIT_BITSET whenever available (since linux-2.6.29) for s390 and powerpc.
This commit is contained in:
parent
155ee340b8
commit
8f861542dd
|
@ -1,3 +1,20 @@
|
|||
2012-11-05 Siddhesh Poyarekar <siddhesh@redhat.com>
|
||||
|
||||
* pthread_cond_timedwait.c (__pthread_cond_timedwait): Time out
|
||||
if absolute timeout is negative.
|
||||
[__ASSUME_FUTEX_CLOCK_REALTIME &&
|
||||
lll_futex_timed_wait_bitset]: Use lll_futex_timed_wait_bitset.
|
||||
* pthread_rwlock_timedrdlock.c (pthread_rwlock_timedrdlock):
|
||||
Likewise.
|
||||
* pthread_rwlock_timedwrlock.c (pthread_rwlock_timedwrlock):
|
||||
Likewise.
|
||||
* sysdeps/unix/sysv/linux/lowlevelrobustlock.c
|
||||
(__lll_robust_timedlock_wait): Likewise.
|
||||
* sysdeps/unix/sysv/linux/powerpc/lowlevellock.h
|
||||
(lll_futex_timed_wait_bitset): New macro.
|
||||
* sysdeps/unix/sysv/linux/s390/lowlevellock.h
|
||||
(lll_futex_timed_wait_bitset): Likewise.
|
||||
|
||||
2012-11-03 David S. Miller <davem@davemloft.net>
|
||||
|
||||
* sysdeps/unix/sysv/linux/sparc/lowlevellock.h (BUSY_WAIT_NOP):
|
||||
|
|
|
@ -80,6 +80,11 @@ __pthread_cond_timedwait (cond, mutex, abstime)
|
|||
++cond->__data.__futex;
|
||||
cond->__data.__nwaiters += 1 << COND_NWAITERS_SHIFT;
|
||||
|
||||
/* Work around the fact that the kernel rejects negative timeout values
|
||||
despite them being valid. */
|
||||
if (__builtin_expect (abstime->tv_sec < 0, 0))
|
||||
goto timeout;
|
||||
|
||||
/* Remember the mutex we are using here. If there is already a
|
||||
different address store this is a bad user bug. Do not store
|
||||
anything for pshared condvars. */
|
||||
|
@ -104,9 +109,11 @@ __pthread_cond_timedwait (cond, mutex, abstime)
|
|||
|
||||
while (1)
|
||||
{
|
||||
#if (!defined __ASSUME_FUTEX_CLOCK_REALTIME \
|
||||
|| !defined lll_futex_timed_wait_bitset)
|
||||
struct timespec rt;
|
||||
{
|
||||
#ifdef __NR_clock_gettime
|
||||
# ifdef __NR_clock_gettime
|
||||
INTERNAL_SYSCALL_DECL (err);
|
||||
int ret;
|
||||
ret = INTERNAL_VSYSCALL (clock_gettime, err, 2,
|
||||
|
@ -116,7 +123,7 @@ __pthread_cond_timedwait (cond, mutex, abstime)
|
|||
/* Convert the absolute timeout value to a relative timeout. */
|
||||
rt.tv_sec = abstime->tv_sec - rt.tv_sec;
|
||||
rt.tv_nsec = abstime->tv_nsec - rt.tv_nsec;
|
||||
#else
|
||||
# else
|
||||
/* Get the current time. So far we support only one clock. */
|
||||
struct timeval tv;
|
||||
(void) gettimeofday (&tv, NULL);
|
||||
|
@ -124,7 +131,7 @@ __pthread_cond_timedwait (cond, mutex, abstime)
|
|||
/* Convert the absolute timeout value to a relative timeout. */
|
||||
rt.tv_sec = abstime->tv_sec - tv.tv_sec;
|
||||
rt.tv_nsec = abstime->tv_nsec - tv.tv_usec * 1000;
|
||||
#endif
|
||||
# endif
|
||||
}
|
||||
if (rt.tv_nsec < 0)
|
||||
{
|
||||
|
@ -139,6 +146,7 @@ __pthread_cond_timedwait (cond, mutex, abstime)
|
|||
|
||||
goto timeout;
|
||||
}
|
||||
#endif
|
||||
|
||||
unsigned int futex_val = cond->__data.__futex;
|
||||
|
||||
|
@ -148,9 +156,17 @@ __pthread_cond_timedwait (cond, mutex, abstime)
|
|||
/* Enable asynchronous cancellation. Required by the standard. */
|
||||
cbuffer.oldtype = __pthread_enable_asynccancel ();
|
||||
|
||||
#if (!defined __ASSUME_FUTEX_CLOCK_REALTIME \
|
||||
|| !defined lll_futex_timed_wait_bitset)
|
||||
/* Wait until woken by signal or broadcast. */
|
||||
err = lll_futex_timed_wait (&cond->__data.__futex,
|
||||
futex_val, &rt, pshared);
|
||||
#else
|
||||
unsigned int clockbit = (cond->__data.__nwaiters & 1
|
||||
? 0 : FUTEX_CLOCK_REALTIME);
|
||||
err = lll_futex_timed_wait_bitset (&cond->__data.__futex, futex_val,
|
||||
abstime, clockbit, pshared);
|
||||
#endif
|
||||
|
||||
/* Disable asynchronous cancellation. */
|
||||
__pthread_disable_asynccancel (cbuffer.oldtype);
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* Copyright (C) 2003,2004,2007,2011 Free Software Foundation, Inc.
|
||||
/* Copyright (C) 2003-2012 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
Contributed by Martin Schwidefsky <schwidefsky@de.ibm.com>, 2003.
|
||||
|
||||
|
@ -76,6 +76,16 @@ pthread_rwlock_timedrdlock (rwlock, abstime)
|
|||
break;
|
||||
}
|
||||
|
||||
/* Work around the fact that the kernel rejects negative timeout values
|
||||
despite them being valid. */
|
||||
if (__builtin_expect (abstime->tv_sec < 0, 0))
|
||||
{
|
||||
result = ETIMEDOUT;
|
||||
break;
|
||||
}
|
||||
|
||||
#if (!defined __ASSUME_FUTEX_CLOCK_REALTIME \
|
||||
|| !defined lll_futex_timed_wait_bitset)
|
||||
/* Get the current time. So far we support only one clock. */
|
||||
struct timeval tv;
|
||||
(void) gettimeofday (&tv, NULL);
|
||||
|
@ -96,6 +106,7 @@ pthread_rwlock_timedrdlock (rwlock, abstime)
|
|||
result = ETIMEDOUT;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Remember that we are a reader. */
|
||||
if (++rwlock->__data.__nr_readers_queued == 0)
|
||||
|
@ -112,8 +123,16 @@ pthread_rwlock_timedrdlock (rwlock, abstime)
|
|||
lll_unlock (rwlock->__data.__lock, rwlock->__data.__shared);
|
||||
|
||||
/* Wait for the writer to finish. */
|
||||
#if (!defined __ASSUME_FUTEX_CLOCK_REALTIME \
|
||||
|| !defined lll_futex_timed_wait_bitset)
|
||||
err = lll_futex_timed_wait (&rwlock->__data.__readers_wakeup,
|
||||
waitval, &rt, rwlock->__data.__shared);
|
||||
#else
|
||||
err = lll_futex_timed_wait_bitset (&rwlock->__data.__readers_wakeup,
|
||||
waitval, abstime,
|
||||
FUTEX_CLOCK_REALTIME,
|
||||
rwlock->__data.__shared);
|
||||
#endif
|
||||
|
||||
/* Get the lock. */
|
||||
lll_lock (rwlock->__data.__lock, rwlock->__data.__shared);
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* Copyright (C) 2003,2004,2007,2011 Free Software Foundation, Inc.
|
||||
/* Copyright (C) 2003-2012 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
Contributed by Martin Schwidefsky <schwidefsky@de.ibm.com>, 2003.
|
||||
|
||||
|
@ -67,6 +67,16 @@ pthread_rwlock_timedwrlock (rwlock, abstime)
|
|||
break;
|
||||
}
|
||||
|
||||
/* Work around the fact that the kernel rejects negative timeout values
|
||||
despite them being valid. */
|
||||
if (__builtin_expect (abstime->tv_sec < 0, 0))
|
||||
{
|
||||
result = ETIMEDOUT;
|
||||
break;
|
||||
}
|
||||
|
||||
#if (!defined __ASSUME_FUTEX_CLOCK_REALTIME \
|
||||
|| !defined lll_futex_timed_wait_bitset)
|
||||
/* Get the current time. So far we support only one clock. */
|
||||
struct timeval tv;
|
||||
(void) gettimeofday (&tv, NULL);
|
||||
|
@ -86,6 +96,7 @@ pthread_rwlock_timedwrlock (rwlock, abstime)
|
|||
result = ETIMEDOUT;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Remember that we are a writer. */
|
||||
if (++rwlock->__data.__nr_writers_queued == 0)
|
||||
|
@ -102,8 +113,16 @@ pthread_rwlock_timedwrlock (rwlock, abstime)
|
|||
lll_unlock (rwlock->__data.__lock, rwlock->__data.__shared);
|
||||
|
||||
/* Wait for the writer or reader(s) to finish. */
|
||||
#if (!defined __ASSUME_FUTEX_CLOCK_REALTIME \
|
||||
|| !defined lll_futex_timed_wait_bitset)
|
||||
err = lll_futex_timed_wait (&rwlock->__data.__writer_wakeup,
|
||||
waitval, &rt, rwlock->__data.__shared);
|
||||
#else
|
||||
err = lll_futex_timed_wait_bitset (&rwlock->__data.__writer_wakeup,
|
||||
waitval, abstime,
|
||||
FUTEX_CLOCK_REALTIME,
|
||||
rwlock->__data.__shared);
|
||||
#endif
|
||||
|
||||
/* Get the lock. */
|
||||
lll_lock (rwlock->__data.__lock, rwlock->__data.__shared);
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* Copyright (C) 2006, 2007 Free Software Foundation, Inc.
|
||||
/* Copyright (C) 2006-2012 Free Software Foundation, Inc.
|
||||
This file is part of the GNU C Library.
|
||||
Contributed by Jakub Jelinek <jakub@redhat.com>, 2006.
|
||||
|
||||
|
@ -70,8 +70,15 @@ __lll_robust_timedlock_wait (int *futex, const struct timespec *abstime,
|
|||
if (oldval == 0)
|
||||
goto try;
|
||||
|
||||
/* Work around the fact that the kernel rejects negative timeout values
|
||||
despite them being valid. */
|
||||
if (__builtin_expect (abstime->tv_sec < 0, 0))
|
||||
return ETIMEDOUT;
|
||||
|
||||
do
|
||||
{
|
||||
#if (!defined __ASSUME_FUTEX_CLOCK_REALTIME \
|
||||
|| !defined lll_futex_timed_wait_bitset)
|
||||
struct timeval tv;
|
||||
struct timespec rt;
|
||||
|
||||
|
@ -90,6 +97,7 @@ __lll_robust_timedlock_wait (int *futex, const struct timespec *abstime,
|
|||
/* Already timed out? */
|
||||
if (rt.tv_sec < 0)
|
||||
return ETIMEDOUT;
|
||||
#endif
|
||||
|
||||
/* Wait. */
|
||||
if (__builtin_expect (oldval & FUTEX_OWNER_DIED, 0))
|
||||
|
@ -100,7 +108,13 @@ __lll_robust_timedlock_wait (int *futex, const struct timespec *abstime,
|
|||
&& atomic_compare_and_exchange_bool_acq (futex, newval, oldval))
|
||||
continue;
|
||||
|
||||
#if (!defined __ASSUME_FUTEX_CLOCK_REALTIME \
|
||||
|| !defined lll_futex_timed_wait_bitset)
|
||||
lll_futex_timed_wait (futex, newval, &rt, private);
|
||||
#else
|
||||
lll_futex_timed_wait_bitset (futex, newval, abstime,
|
||||
FUTEX_CLOCK_REALTIME, private);
|
||||
#endif
|
||||
|
||||
try:
|
||||
;
|
||||
|
|
|
@ -88,6 +88,19 @@
|
|||
INTERNAL_SYSCALL_ERROR_P (__ret, __err) ? -__ret : __ret; \
|
||||
})
|
||||
|
||||
#define lll_futex_timed_wait_bitset(futexp, val, timespec, clockbit, private) \
|
||||
({ \
|
||||
INTERNAL_SYSCALL_DECL (__err); \
|
||||
long int __ret; \
|
||||
int __op = FUTEX_WAIT_BITSET | clockbit; \
|
||||
\
|
||||
__ret = INTERNAL_SYSCALL (futex, __err, 6, (futexp), \
|
||||
__lll_private_flag (__op, private), \
|
||||
(val), (timespec), NULL /* Unused. */, \
|
||||
FUTEX_BITSET_MATCH_ANY); \
|
||||
INTERNAL_SYSCALL_ERROR_P (__ret, __err) ? -__ret : __ret; \
|
||||
})
|
||||
|
||||
#define lll_futex_wake(futexp, nr, private) \
|
||||
({ \
|
||||
INTERNAL_SYSCALL_DECL (__err); \
|
||||
|
|
|
@ -93,6 +93,26 @@
|
|||
__result; \
|
||||
})
|
||||
|
||||
#define lll_futex_timed_wait_bitset(futexp, val, timespec, clockbit, private) \
|
||||
({ \
|
||||
register unsigned long int __r2 asm ("2") = (unsigned long int) (futexp); \
|
||||
register unsigned long int __r3 asm ("3") \
|
||||
= __lll_private_flag ((FUTEX_WAIT_BITSET | clockbit), private); \
|
||||
register unsigned long int __r4 asm ("4") = (long int) (val); \
|
||||
register unsigned long int __r5 asm ("5") = (long int) (timespec); \
|
||||
register unsigned long int __r6 asm ("6") = (unsigned long int) (NULL); \
|
||||
register unsigned long int __r7 asm ("7") \
|
||||
= (unsigned int) (FUTEX_BITSET_MATCH_ANY); \
|
||||
register unsigned long __result asm ("2"); \
|
||||
\
|
||||
__asm __volatile ("svc %b1" \
|
||||
: "=d" (__result) \
|
||||
: "i" (SYS_futex), "0" (__r2), "d" (__r3), \
|
||||
"d" (__r4), "d" (__r5), "d" (__r6), "d" (__r7) \
|
||||
: "cc", "memory" ); \
|
||||
__result; \
|
||||
})
|
||||
|
||||
|
||||
#define lll_futex_wake(futex, nr, private) \
|
||||
({ \
|
||||
|
|
Loading…
Reference in New Issue