This is the mail archive of the libc-alpha@sourceware.org mailing list for the glibc project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH siddhesh/wait_bitset] Use FUTEX_WAIT_BITSET forpthread_cond_timedwait for non-x86: ppc, s390


Hi,

Since the FUTEX_WAIT operation takes a relative timeout, the
pthread_cond_timedwait implementation has 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.

I have access to an ia64 system as well, so I'll add ia64 once this
patch is in.  Other arch maintainers will need to add a definition for a
lll_futex_timed_wait_bitset macro similar to what I have implemented in
this patch to use this feature. If this macro is not available, the old
behaviour is compiled in.

I have verified that there are no regressions resulting from this patch
on s390 as well as on powerpc.  OK to commit?

Regards,
Siddhesh

nptl/ChangeLog:

	* pthread_cond_timedwait.c (__pthread_cond_timedwait): Timeout
	if absolute timeout is negative.
	[__ASSUME_FUTEX_CLOCK_REALTIME &&
	lll_futex_timed_wait_bitset]: Use lll_futex_timed_wait_bitset.
	* sysdeps/unix/sysv/linux/powerpc/lowlevellock.h
	(lll_futex_timed_wait_bitset); Define.
	* sysdeps/unix/sysv/linux/s390/lowlevellock.h
	(lll_futex_timed_wait_bitset); Likewise.
diff --git a/nptl/pthread_cond_timedwait.c b/nptl/pthread_cond_timedwait.c
index 51a34ba..800aa86 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
+			       ? FUTEX_CLOCK_REALTIME : 0);
+      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/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) \
   ({									      \

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]