From: Siddhesh Poyarekar Date: Mon, 5 Nov 2012 15:42:10 +0000 (+0530) Subject: [S390,PPC] Implement FUTEX_WAIT_BITSET for timedwait functions X-Git-Tag: upstream/2.30~10010 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=8f861542dd0603bef99e126e509ece89514c1eeb;p=external%2Fglibc.git [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. --- diff --git a/nptl/ChangeLog b/nptl/ChangeLog index a7b741f..0e01675 100644 --- a/nptl/ChangeLog +++ b/nptl/ChangeLog @@ -1,3 +1,20 @@ +2012-11-05 Siddhesh Poyarekar + + * 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 * sysdeps/unix/sysv/linux/sparc/lowlevellock.h (BUSY_WAIT_NOP): diff --git a/nptl/pthread_cond_timedwait.c b/nptl/pthread_cond_timedwait.c index 51a34ba..2fcbc57 100644 --- a/nptl/pthread_cond_timedwait.c +++ b/nptl/pthread_cond_timedwait.c @@ -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); diff --git a/nptl/pthread_rwlock_timedrdlock.c b/nptl/pthread_rwlock_timedrdlock.c index be8216d..b7622ab 100644 --- a/nptl/pthread_rwlock_timedrdlock.c +++ b/nptl/pthread_rwlock_timedrdlock.c @@ -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 , 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); diff --git a/nptl/pthread_rwlock_timedwrlock.c b/nptl/pthread_rwlock_timedwrlock.c index 8eb31cf..5f2399f 100644 --- a/nptl/pthread_rwlock_timedwrlock.c +++ b/nptl/pthread_rwlock_timedwrlock.c @@ -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 , 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); diff --git a/nptl/sysdeps/unix/sysv/linux/lowlevelrobustlock.c b/nptl/sysdeps/unix/sysv/linux/lowlevelrobustlock.c index 7b4e843..9a9e673 100644 --- a/nptl/sysdeps/unix/sysv/linux/lowlevelrobustlock.c +++ b/nptl/sysdeps/unix/sysv/linux/lowlevelrobustlock.c @@ -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 , 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: ; diff --git a/nptl/sysdeps/unix/sysv/linux/powerpc/lowlevellock.h b/nptl/sysdeps/unix/sysv/linux/powerpc/lowlevellock.h index 406c290..17e63c6 100644 --- a/nptl/sysdeps/unix/sysv/linux/powerpc/lowlevellock.h +++ b/nptl/sysdeps/unix/sysv/linux/powerpc/lowlevellock.h @@ -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); \ diff --git a/nptl/sysdeps/unix/sysv/linux/s390/lowlevellock.h b/nptl/sysdeps/unix/sysv/linux/s390/lowlevellock.h index 9709282..0b7110f 100644 --- a/nptl/sysdeps/unix/sysv/linux/s390/lowlevellock.h +++ b/nptl/sysdeps/unix/sysv/linux/s390/lowlevellock.h @@ -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) \ ({ \