[S390,PPC] Implement FUTEX_WAIT_BITSET for timedwait functions
authorSiddhesh Poyarekar <siddhesh@redhat.com>
Mon, 5 Nov 2012 15:42:10 +0000 (21:12 +0530)
committerSiddhesh Poyarekar <siddhesh@redhat.com>
Mon, 5 Nov 2012 15:42:52 +0000 (21:12 +0530)
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.

nptl/ChangeLog
nptl/pthread_cond_timedwait.c
nptl/pthread_rwlock_timedrdlock.c
nptl/pthread_rwlock_timedwrlock.c
nptl/sysdeps/unix/sysv/linux/lowlevelrobustlock.c
nptl/sysdeps/unix/sysv/linux/powerpc/lowlevellock.h
nptl/sysdeps/unix/sysv/linux/s390/lowlevellock.h

index a7b741f..0e01675 100644 (file)
@@ -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):
index 51a34ba..2fcbc57 100644 (file)
@@ -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);
index be8216d..b7622ab 100644 (file)
@@ -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);
index 8eb31cf..5f2399f 100644 (file)
@@ -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);
index 7b4e843..9a9e673 100644 (file)
@@ -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:
       ;
index 406c290..17e63c6 100644 (file)
     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);                                           \
index 9709282..0b7110f 100644 (file)
     __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) \
   ({                                                                         \