about summary refs log tree commit diff
path: root/ports/sysdeps
diff options
context:
space:
mode:
authorMaxim Kuvyrkov <maxim@codesourcery.com>2012-08-15 16:44:30 -0700
committerMaxim Kuvyrkov <maxim@codesourcery.com>2012-08-15 16:44:30 -0700
commit309becf120640bb0fdd1a16e65996c23d0542590 (patch)
tree6adbada4d391a306dd2e4558626f759a7cadbed7 /ports/sysdeps
parentef4009734b84903615be28b38638c166e5455692 (diff)
downloadglibc-309becf120640bb0fdd1a16e65996c23d0542590.tar.gz
glibc-309becf120640bb0fdd1a16e65996c23d0542590.tar.xz
glibc-309becf120640bb0fdd1a16e65996c23d0542590.zip
Optimize __libc_lock_lock and __libc_lock_trylock for MIPS.
Diffstat (limited to 'ports/sysdeps')
-rw-r--r--ports/sysdeps/unix/sysv/linux/mips/nptl/lowlevellock.h39
1 files changed, 37 insertions, 2 deletions
diff --git a/ports/sysdeps/unix/sysv/linux/mips/nptl/lowlevellock.h b/ports/sysdeps/unix/sysv/linux/mips/nptl/lowlevellock.h
index 88b601eadd..d368ae1b66 100644
--- a/ports/sysdeps/unix/sysv/linux/mips/nptl/lowlevellock.h
+++ b/ports/sysdeps/unix/sysv/linux/mips/nptl/lowlevellock.h
@@ -1,5 +1,4 @@
-/* Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008,
-   2009 Free Software Foundation, Inc.
+/* Copyright (C) 2003-2012 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
 
    The GNU C Library is free software; you can redistribute it and/or
@@ -291,4 +290,40 @@ extern int __lll_timedwait_tid (int *, const struct timespec *)
     __res;						\
   })
 
+/* Implement __libc_lock_lock using exchange_and_add, which expands into
+   a single instruction on XLP processors.  We enable this for all MIPS
+   processors as atomic_exchange_and_add_acq and
+   atomic_compare_and_exchange_acq take the same time to execute.
+   This is a simplified expansion of ({ lll_lock (NAME, LLL_PRIVATE); 0; }).
+
+   Note: __lll_lock_wait_private() resets lock value to '2', which prevents
+   unbounded increase of the lock value and [with billions of threads]
+   overflow.  */
+#define __libc_lock_lock(NAME)						\
+  ({									\
+    int *__futex = &(NAME);						\
+    if (__builtin_expect (atomic_exchange_and_add_acq (__futex, 1), 0))	\
+      __lll_lock_wait_private (__futex);				\
+    0;									\
+  })
+
+#ifdef _MIPS_ARCH_XLP
+/* The generic version using a single atomic_compare_and_exchange_acq takes
+   less time for non-XLP processors, so we use below for XLP only.  */
+# define __libc_lock_trylock(NAME)					\
+  ({									\
+  int *__futex = &(NAME);						\
+  int __result = atomic_exchange_and_add_acq (__futex, 1);		\
+  /* If __result == 0, we succeeded in acquiring the lock.		\
+     If __result == 1, we switched the lock to 'contended' state, which	\
+     will cause a [possibly unnecessary] call to lll_futex_wait.  This is \
+     unlikely, so we accept the possible inefficiency.			\
+     If __result >= 2, we need to set the lock to 'contended' state to avoid \
+     unbounded increase from subsequent trylocks.  */			\
+  if (__result >= 2)							\
+    __result = atomic_exchange_acq (__futex, 2);			\
+  __result;								\
+  })
+#endif
+
 #endif	/* lowlevellock.h */