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 6/8] Extend the test suite for TSX and add some new tests to test elision


From: Andi Kleen <ak@linux.intel.com>

- Some of the existing mutex tests do not work with lock elision
semantics. We run them with PTHREAD_MUTEX=none PTHREAD_RWLOCK=none,
but do not otherwise modify it.

This is expected behaviour, related to RTM lock elision's inability
to track the owner of lock (see the original description for more
details). It's not expected that these changes will break any programs,
it's mostly related to obscure behaviour.
- I added some ifdefs to these tests and add new variants that
set the defines to test elision behaviour.
- Add new tests that explicitely check for elision.
Note strictly this violates the TSX spec which never guarantees any transaction
ever succeeding. However we assume simple transactions will succeed and will
fail if not.
- Add tests covering the new lock kinds.

2013-01-30  Andi Kleen  <ak@linux.intel.com>

	* Makefile: Add elision tests. Disable elision for some existing
        tests.
	* tst-abstime.c: Fix for elision.
	* tst-abstime1b.c: New file for lock elision code.
	* tst-abstime1c.c:dito.
	* tst-elision-common.c: dito.
	* tst-elision1.c: dito.
	* tst-elision1b.c: dito.
	* tst-elision2.c: dito.
	* tst-initializers2-c89.c: Handle lock elision
	* tst-initializers2-c99.c: dito.
	* tst-initializers2-gnu89.c: dito.
	* tst-initializers2-gnu99.c: dito.
	* tst-initializers2.c: dito.
	* tst-mutex5.c: Handle lock elision.
	* tst-mutex5b.c: New file.
	* tst-mutex5c.c: dito.
	* tst-mutex5d.c: dito
	* tst-mutex5e.c: dito.
	* tst-mutex7b.c: dito.
	* tst-mutex7c.c: dito.
	* tst-mutex7d.c: dito.
	* tst-mutex7e.c: dito.
	* tst-mutex8.c: Handle lock elision.
	* tst-mutex8b.c: New file.
	* tst-mutex8c.c: dito.
	* tst-mutex8d.c: dito.
	* tst-mutex8e.c: dito.
	* tst-mutex8f.c: dito.
	* tst-mutex8g.c: dito.
---
 nptl/Makefile                  |   26 ++++-
 nptl/tst-abstime.c             |    8 +-
 nptl/tst-abstime1b.c           |    2 +
 nptl/tst-abstime1c.c           |    2 +
 nptl/tst-elision-common.c      |  242 ++++++++++++++++++++++++++++++++++++++++
 nptl/tst-elision1.c            |  121 ++++++++++++++++++++
 nptl/tst-elision1b.c           |    1 +
 nptl/tst-elision2.c            |   88 +++++++++++++++
 nptl/tst-initializers2-c89.c   |    1 +
 nptl/tst-initializers2-c99.c   |    1 +
 nptl/tst-initializers2-gnu89.c |    1 +
 nptl/tst-initializers2-gnu99.c |    1 +
 nptl/tst-initializers2.c       |   50 ++++++++
 nptl/tst-mutex5.c              |    2 +
 nptl/tst-mutex5b.c             |    6 +
 nptl/tst-mutex5c.c             |    2 +
 nptl/tst-mutex5d.c             |    2 +
 nptl/tst-mutex5e.c             |    6 +
 nptl/tst-mutex7b.c             |    2 +
 nptl/tst-mutex7c.c             |    2 +
 nptl/tst-mutex7d.c             |    2 +
 nptl/tst-mutex7e.c             |    2 +
 nptl/tst-mutex8.c              |   37 ++++++-
 nptl/tst-mutex8b.c             |    7 +
 nptl/tst-mutex8c.c             |    7 +
 nptl/tst-mutex8d.c             |    3 +
 nptl/tst-mutex8e.c             |    3 +
 nptl/tst-mutex8f.c             |    3 +
 nptl/tst-mutex8g.c             |    5 +
 29 files changed, 627 insertions(+), 8 deletions(-)
 create mode 100644 nptl/tst-abstime1b.c
 create mode 100644 nptl/tst-abstime1c.c
 create mode 100644 nptl/tst-elision-common.c
 create mode 100644 nptl/tst-elision1.c
 create mode 100644 nptl/tst-elision1b.c
 create mode 100644 nptl/tst-elision2.c
 create mode 100644 nptl/tst-initializers2-c89.c
 create mode 100644 nptl/tst-initializers2-c99.c
 create mode 100644 nptl/tst-initializers2-gnu89.c
 create mode 100644 nptl/tst-initializers2-gnu99.c
 create mode 100644 nptl/tst-initializers2.c
 create mode 100644 nptl/tst-mutex5b.c
 create mode 100644 nptl/tst-mutex5c.c
 create mode 100644 nptl/tst-mutex5d.c
 create mode 100644 nptl/tst-mutex5e.c
 create mode 100644 nptl/tst-mutex7b.c
 create mode 100644 nptl/tst-mutex7c.c
 create mode 100644 nptl/tst-mutex7d.c
 create mode 100644 nptl/tst-mutex7e.c
 create mode 100644 nptl/tst-mutex8b.c
 create mode 100644 nptl/tst-mutex8c.c
 create mode 100644 nptl/tst-mutex8d.c
 create mode 100644 nptl/tst-mutex8e.c
 create mode 100644 nptl/tst-mutex8f.c
 create mode 100644 nptl/tst-mutex8g.c

diff --git a/nptl/Makefile b/nptl/Makefile
index 6af4b37..b898006 100644
--- a/nptl/Makefile
+++ b/nptl/Makefile
@@ -204,6 +204,9 @@ tests = tst-typesizes \
 	tst-attr1 tst-attr2 tst-attr3 \
 	tst-mutex1 tst-mutex2 tst-mutex3 tst-mutex4 tst-mutex5 tst-mutex6 \
 	tst-mutex7 tst-mutex8 tst-mutex9 tst-mutex5a tst-mutex7a \
+	tst-mutex8b tst-mutex8c tst-mutex8d tst-mutex8e tst-mutex8f \
+	tst-mutex5b tst-mutex5c tst-mutex5d tst-mutex5e \
+	tst-mutex7b tst-mutex7c tst-mutex7d tst-mutex7e \
 	tst-mutexpi1 tst-mutexpi2 tst-mutexpi3 tst-mutexpi4 tst-mutexpi5 \
 	tst-mutexpi5a tst-mutexpi6 tst-mutexpi7 tst-mutexpi7a tst-mutexpi8 \
 	tst-mutexpi9 \
@@ -262,10 +265,12 @@ tests = tst-typesizes \
 	tst-context1 \
 	tst-sched1 \
 	tst-backtrace1 \
-	tst-abstime \
+	tst-abstime tst-abstime1b tst-abstime1c \
 	tst-vfork1 tst-vfork2 tst-vfork1x tst-vfork2x \
 	tst-getpid1 tst-getpid2 tst-getpid3 \
-	tst-initializers1 $(patsubst %,tst-initializers1-%,c89 gnu89 c99 gnu99)
+	tst-initializers1 $(patsubst %,tst-initializers1-%,c89 gnu89 c99 gnu99) \
+	tst-initializers2 $(patsubst %,tst-initializers2-%,c89 gnu89 c99 gnu99) \
+	tst-elision1 tst-elision1b tst-elision2
 xtests = tst-setuid1 tst-setuid1-static tst-mutexpp1 tst-mutexpp6 tst-mutexpp10
 test-srcs = tst-oddstacklimit
 
@@ -436,11 +441,28 @@ CFLAGS-tst-initializers1-c89.c = $(CFLAGS-tst-initializers1-<)
 CFLAGS-tst-initializers1-c99.c = $(CFLAGS-tst-initializers1-<)
 CFLAGS-tst-initializers1-gnu89.c = $(CFLAGS-tst-initializers1-<)
 CFLAGS-tst-initializers1-gnu99.c = $(CFLAGS-tst-initializers1-<)
+CFLAGS-tst-initializers2.c = -W -Wall -Werror
+CFLAGS-tst-initializers2-< = $(CFLAGS-tst-initializers2.c) \
+			     $(patsubst tst-initializers2-%.c,-std=%,$<)
+CFLAGS-tst-initializers2-c89.c = $(CFLAGS-tst-initializers2-<)
+CFLAGS-tst-initializers2-c99.c = $(CFLAGS-tst-initializers2-<)
+CFLAGS-tst-initializers2-gnu89.c = $(CFLAGS-tst-initializers2-<)
+CFLAGS-tst-initializers2-gnu99.c = $(CFLAGS-tst-initializers2-<)
 
 tst-cancel7-ARGS = --command "exec $(host-test-program-cmd)"
 tst-cancelx7-ARGS = $(tst-cancel7-ARGS)
 tst-umask1-ARGS = $(objpfx)tst-umask1.temp
 
+tst-abstime1-ENV = PTHREAD_MUTEX=none
+tst-mutex5-ENV = PTHREAD_MUTEX=none
+tst-mutex8-ENV = PTHREAD_MUTEX=none
+tst-mutex8-static-ENV = PTHREAD_MUTEX=none
+tst-mutex8f-ENV = PTHREAD_MUTEX=none
+tst-mutex8g-ENV = PTHREAD_MUTEX=elision
+tst-elision1b-ENV = PTHREAD_MUTEX=none PTHREAD_RWLOCK=none
+# disable adaptation for abort hook test
+tst-elision2-ENV = PTHREAD_MUTEX=elision:retry_lock_internal_abort=0:retry_trylock_internal_abort=0
+
 $(objpfx)tst-atfork2: $(libdl) $(shared-thread-library)
 LDFLAGS-tst-atfork2 = -rdynamic
 tst-atfork2-ENV = MALLOC_TRACE=$(objpfx)tst-atfork2.mtrace
diff --git a/nptl/tst-abstime.c b/nptl/tst-abstime.c
index 99fc7c1..3c91c66 100644
--- a/nptl/tst-abstime.c
+++ b/nptl/tst-abstime.c
@@ -21,9 +21,13 @@
 #include <semaphore.h>
 #include <stdio.h>
 
+#ifndef MUTEX_TYPE
+#define MUTEX_TYPE PTHREAD_MUTEX_INITIALIZER
+#endif
+
 static pthread_cond_t c = PTHREAD_COND_INITIALIZER;
-static pthread_mutex_t m1 = PTHREAD_MUTEX_INITIALIZER;
-static pthread_mutex_t m2 = PTHREAD_MUTEX_INITIALIZER;
+static pthread_mutex_t m1 = MUTEX_TYPE;
+static pthread_mutex_t m2 = MUTEX_TYPE;
 static pthread_rwlock_t rw1 = PTHREAD_RWLOCK_INITIALIZER;
 static pthread_rwlock_t rw2 = PTHREAD_RWLOCK_INITIALIZER;
 static sem_t sem;
diff --git a/nptl/tst-abstime1b.c b/nptl/tst-abstime1b.c
new file mode 100644
index 0000000..9a2953a
--- /dev/null
+++ b/nptl/tst-abstime1b.c
@@ -0,0 +1,2 @@
+#define MUTEX_TYPE PTHREAD_MUTEX_INIT_NP(PTHREAD_MUTEX_TIMED_NP|PTHREAD_MUTEX_NO_ELISION_NP)
+#include "tst-abstime.c"
diff --git a/nptl/tst-abstime1c.c b/nptl/tst-abstime1c.c
new file mode 100644
index 0000000..22ae9a3
--- /dev/null
+++ b/nptl/tst-abstime1c.c
@@ -0,0 +1,2 @@
+#define MUTEX_TYPE PTHREAD_MUTEX_INIT_NP(PTHREAD_MUTEX_ADAPTIVE_NP|PTHREAD_MUTEX_NO_ELISION_NP)
+#include "tst-abstime.c"
diff --git a/nptl/tst-elision-common.c b/nptl/tst-elision-common.c
new file mode 100644
index 0000000..8ddf391
--- /dev/null
+++ b/nptl/tst-elision-common.c
@@ -0,0 +1,242 @@
+/* tst-elision-common: Elision test harness.
+   Copyright (C) 2013 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
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <stdio.h>
+
+#define CPUID_FEATURE_RTM (1U << 11)
+
+static int
+cpu_has_rtm (void)
+{
+  if (__get_cpuid_max (0, NULL) >= 7)
+    {
+      unsigned a, b, c, d;
+
+      __cpuid_count (7, 0, a, b, c, d);
+      if (b & CPUID_FEATURE_RTM)
+	return 1;
+    }
+  return 0;
+}
+
+#define ITER 10
+#define MAXTRY 100
+
+pthread_mutex_t lock;
+
+#ifndef TRYLOCK_ONLY
+static int
+pthread_mutex_timedlock_wrapper(pthread_mutex_t *l)
+{
+  struct timespec wait = { 0, 0 };
+  return pthread_mutex_timedlock (l, &wait);
+}
+#endif
+
+/* Note this test program will fail when single stepped.
+   It also assumes that simple transactions always work. There is no
+   guarantee in the architecture that this is the case. We do some
+   retries to handle random abort cases like interrupts. But it's
+   not fully guaranteed. However when this fails it is somewhat worrying. */
+
+int
+run_mutex (int expected, const char *name, int force)
+{
+  int i;
+  int try = 0;
+  int txn __attribute__((unused));
+  int err;
+
+#ifndef TRYLOCK_ONLY
+  TESTLOCK(lock, pthread_mutex_lock, pthread_mutex_unlock, force);
+  TESTLOCK(lock, pthread_mutex_timedlock_wrapper, pthread_mutex_unlock, force);
+  TESTLOCK(lock, pthread_mutex_trylock, pthread_mutex_unlock, force);
+#else
+  TESTTRYLOCK(lock, pthread_mutex_lock, pthread_mutex_trylock, pthread_mutex_unlock, force);
+#endif
+
+  err = pthread_mutex_destroy (&lock);
+  if (err != 0)
+    {
+      printf ("destroy for %s failed: %d\n", name, err);
+      return 1;
+    }
+  return 0;
+}
+
+static int
+run_mutex_init (int iter, const char *name, int type, int has_type, int force)
+{
+  pthread_mutexattr_t attr;
+
+  pthread_mutexattr_init (&attr);
+  pthread_mutexattr_settype (&attr, type);
+  pthread_mutex_init (&lock, has_type ? &attr : NULL);
+  return run_mutex (iter, name, force);
+}
+
+/* This assumes elision is enabled by default. If that changes change
+   the first arguments of the default cases to 0. */
+
+int
+mutex_test (void)
+{
+  int ret = 0;
+
+  lock = (pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER;
+  ret += run_mutex (ITER, "default initializer timed", 0);
+  lock = (pthread_mutex_t) PTHREAD_MUTEX_INIT_NP(PTHREAD_MUTEX_TIMED_NP|
+						 PTHREAD_MUTEX_ELISION_NP),
+  ret += run_mutex (ITER, "timed initializer elision", 1);
+  lock = (pthread_mutex_t) PTHREAD_MUTEX_INIT_NP(PTHREAD_MUTEX_TIMED_NP|
+						 PTHREAD_MUTEX_NO_ELISION_NP);
+  ret += run_mutex (0, "timed initializer no elision", 2);
+
+  lock = (pthread_mutex_t) PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP;
+  run_mutex (ITER, "adaptive initializer default", 0);
+  lock = (pthread_mutex_t) PTHREAD_MUTEX_INIT_NP(PTHREAD_MUTEX_ADAPTIVE_NP|
+						 PTHREAD_MUTEX_ELISION_NP);
+  ret += run_mutex (ITER, "adaptive initializer elision", 1);
+  lock = (pthread_mutex_t) PTHREAD_MUTEX_INIT_NP(PTHREAD_MUTEX_ADAPTIVE_NP|
+						 PTHREAD_MUTEX_NO_ELISION_NP);
+  ret += run_mutex (0, "adaptive initializer no elision", 2);
+
+  ret += run_mutex_init (ITER, "timed init default", 0, 0, 0);
+  ret += run_mutex_init (ITER, "timed init elision",
+                         PTHREAD_MUTEX_TIMED_NP|PTHREAD_MUTEX_ELISION_NP, 1, 1);
+  ret += run_mutex_init (0, "timed init no elision",
+			 PTHREAD_MUTEX_TIMED_NP|PTHREAD_MUTEX_NO_ELISION_NP, 1, 2);
+
+  ret += run_mutex_init (ITER, "adaptive init default", 0, 0, 0);
+  ret += run_mutex_init (ITER, "adaptive init elision",
+                         PTHREAD_MUTEX_ADAPTIVE_NP|PTHREAD_MUTEX_ELISION_NP, 1, 1);
+  ret += run_mutex_init (0, "adaptive init no elision",
+		         PTHREAD_MUTEX_ADAPTIVE_NP|PTHREAD_MUTEX_NO_ELISION_NP,
+			  1, 2);
+
+  return ret;
+}
+
+pthread_rwlock_t rwlock;
+
+#ifndef TRYLOCK_ONLY
+static int
+pthread_rwlock_timedwrlock_wrapper(pthread_rwlock_t *l)
+{
+  struct timespec wait = { 0, 0 };
+  return pthread_rwlock_timedwrlock (l, &wait);
+}
+
+static int
+pthread_rwlock_timedrdlock_wrapper(pthread_rwlock_t *l)
+{
+  struct timespec wait = { 0, 0 };
+  return pthread_rwlock_timedrdlock (l, &wait);
+}
+#endif
+
+int
+run_rwlock (int expected, const char *name, int force)
+{
+  int i;
+  int try = 0;
+  int txn __attribute__((unused));
+  int err;
+
+#ifndef TRYLOCK_ONLY
+  TESTLOCK(rwlock, pthread_rwlock_rdlock, pthread_rwlock_unlock, force);
+  TESTLOCK(rwlock, pthread_rwlock_wrlock, pthread_rwlock_unlock, force);
+  TESTLOCK(rwlock, pthread_rwlock_rdlock, pthread_rwlock_unlock, force);
+  TESTLOCK(rwlock, pthread_rwlock_tryrdlock, pthread_rwlock_unlock, force);
+  TESTLOCK(rwlock, pthread_rwlock_trywrlock, pthread_rwlock_unlock, force);
+  TESTLOCK(rwlock, pthread_rwlock_timedrdlock_wrapper,
+	   pthread_rwlock_unlock, force);
+  TESTLOCK(rwlock, pthread_rwlock_timedwrlock_wrapper,
+	   pthread_rwlock_unlock, force);
+#else
+  TESTTRYLOCK(rwlock, pthread_rwlock_wrlock, pthread_rwlock_trywrlock,
+	      pthread_rwlock_unlock, force);
+#endif
+
+  err = pthread_rwlock_destroy (&rwlock);
+  if (err != 0)
+    {
+      printf ("pthread_rwlock_destroy for %s failed: %d\n", name, err);
+      return 1;
+    }
+  return 0;
+}
+
+int
+run_rwlock_attr (int iter, const char *name, int type, int force)
+{
+  pthread_rwlockattr_t attr;
+  pthread_rwlockattr_init (&attr);
+  pthread_rwlockattr_setkind_np (&attr, type);
+  pthread_rwlock_init (&rwlock, &attr);
+  return run_rwlock (iter, name, force);
+}
+
+int
+run_rwlock_attr_set (int iter, const char *extra, int flag, int force)
+{
+  char str[100];
+  int ret = 0;
+
+  snprintf(str, sizeof str, "rwlock attr prefer reader %s", extra);
+  ret += run_rwlock_attr (ITER, str,
+                          PTHREAD_RWLOCK_PREFER_READER_NP | flag, force);
+  snprintf(str, sizeof str, "rwlock attr prefer writer %s", extra);
+  ret += run_rwlock_attr (ITER, str,
+                          PTHREAD_RWLOCK_PREFER_WRITER_NP | flag, force);
+  snprintf(str, sizeof str, "rwlock attr prefer writer non recursive %s", extra);
+  ret += run_rwlock_attr (ITER, str,
+		          PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP | flag, force);
+  return ret;
+}
+
+
+int
+rwlock_test (void)
+{
+  int ret = 0;
+
+  pthread_rwlock_init (&rwlock, NULL);
+  ret += run_rwlock (ITER, "rwlock created", 0);
+
+  rwlock = (pthread_rwlock_t)PTHREAD_RWLOCK_INITIALIZER;
+  ret += run_rwlock (ITER, "rwlock initialized", 0);
+
+  rwlock = (pthread_rwlock_t)PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP;
+  ret += run_rwlock (ITER, "rwlock initialized writer non recursive", 0);
+
+  rwlock = (pthread_rwlock_t)PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP;
+  ret += run_rwlock (ITER, "rwlock initialized writer non recursive", 0);
+
+#ifdef PTHREAD_RWLOCK_WRITER_INITIALIZER_NP
+  // XXX includes are missing PTHREAD_RWLOCK_WRITER_INITIALIZER_NP
+  rwlock = (pthread_rwlock_t)PTHREAD_RWLOCK_WRITER_INITIALIZER_NP;
+  ret += run_rwlock (ITER, "rwlock initialized writer", 0);
+#endif
+
+  ret += run_rwlock_attr_set (ITER, "", 0, 0);
+  ret += run_rwlock_attr_set (ITER, "eliding", PTHREAD_RWLOCK_ELISION_NP, 1);
+  ret += run_rwlock_attr_set (ITER, "not eliding", PTHREAD_RWLOCK_NO_ELISION_NP, 2);
+
+  return ret;
+}
diff --git a/nptl/tst-elision1.c b/nptl/tst-elision1.c
new file mode 100644
index 0000000..aad06ec
--- /dev/null
+++ b/nptl/tst-elision1.c
@@ -0,0 +1,121 @@
+/* tst-elision1: Test basic elision success.
+   Copyright (C) 2013 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
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <elision-conf.h>
+#if (defined(__i386__) || defined(__x86_64__)) && defined(SUPPORTS_ELISION)
+#include <pthread.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <hle.h>
+
+int disabled;
+int forced;
+
+int
+check (const char *name, const char *lock, int try, int txn, int max,
+       int override)
+{
+  int should_run = 1;
+
+  if (override == 0)
+    should_run = disabled == 0;
+  else if (override == 1)
+    should_run = 1;
+  else if (override == 2)
+    should_run = 0;
+
+  /* forced noop right now, so not tested. But test if the defaults change */
+  if (!should_run)
+    {
+      if (txn != 0)
+	{
+	  printf ("%s %s transaction run unexpected\n", name, lock);
+	  return 1;
+	}
+    }
+  else
+    {
+      if (try == max)
+	{
+	  printf ("%s %s no transactions when expected\n", name, lock);
+	  return 1;
+	}
+    }
+  return 0;
+}
+
+#define TESTLOCK(l, lock, unlock, force)\
+  do					\
+    {					\
+      txn = 0;				\
+      for (i = 0; i < ITER; i++)	\
+	{				\
+	  lock (&l);			\
+	  if (_xtest ())		\
+	    txn++;			\
+	  unlock (&l);			\
+	}				\
+    }						\
+  while (try++ < MAXTRY && txn != expected);	\
+  if (check (name, #lock, try, txn, MAXTRY, force))	\
+    return 1;
+
+#include "tst-elision-common.c"
+
+int
+do_test (void)
+{
+  if (!cpu_has_rtm ())
+    {
+      printf ("elision test requires RTM capable CPU. not tested\n");
+      return 0;
+    }
+
+  char *s = getenv ("PTHREAD_MUTEX");
+  if (s)
+    {
+      char *o = getenv ("PTHREAD_RWLOCK");
+      if (!o || strcmp (o, s))
+        {
+          puts("PTHREAD_MUTEX and PTHREAD_RWLOCK must match for test!\n");
+          return 1;
+	}
+      if (!strcmp (s, "none"))
+        disabled = 1;
+      if (!strcmp (s, "elision"))
+	forced = 1;
+    }
+
+  if (mutex_test ())
+    return 1;
+
+  if (rwlock_test ())
+    return 1;
+
+  return 0;
+}
+#else
+int do_test (void)
+{
+  return 0;
+}
+#endif
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/nptl/tst-elision1b.c b/nptl/tst-elision1b.c
new file mode 100644
index 0000000..9f5ec3d
--- /dev/null
+++ b/nptl/tst-elision1b.c
@@ -0,0 +1 @@
+#include "tst-elision1.c"
diff --git a/nptl/tst-elision2.c b/nptl/tst-elision2.c
new file mode 100644
index 0000000..45b4a75
--- /dev/null
+++ b/nptl/tst-elision2.c
@@ -0,0 +1,88 @@
+/* tst-elision3: Test elided trylock semantics
+   Copyright (C) 2013 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
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#if defined(__i386__) || defined(__x86_64__)
+#include <pthread.h>
+#include <stdio.h>
+#include <hle.h>
+#include <cpuid.h>
+
+int check (int success, int force)
+{
+  switch (force)
+    {
+    case 2:
+    case 0:
+      return success == 0;
+    case 1:
+      return success == 1;
+    }
+  return 0;
+}
+
+#define TESTTRYLOCK(l, lock, trylock, unlock, force)	\
+   do					\
+    {					\
+      txn = 0;				\
+      for (i = 0; i < ITER; i++)	\
+	{				\
+	  lock (&l);			\
+	  if (trylock (&l) == 0)	\
+	    {				\
+	      txn++;			\
+	      unlock (&l);		\
+	    }				\
+	  unlock (&l);			\
+	}				\
+    }					\
+   while (try++ < MAXTRY && txn == ITER);				\
+   if (!check (txn == ITER, force))					\
+     {									\
+       printf ("%s %s nested trylock check failed\n", name, #lock);	\
+       return 1;							\
+     }
+
+#define TRYLOCK_ONLY 1
+#include "tst-elision-common.c"
+
+int
+do_test (void)
+{
+  if (!cpu_has_rtm ())
+    {
+      printf ("elision test requires RTM capable CPU. not tested\n");
+      return 0;
+    }
+
+  if (mutex_test ())
+    return 1;
+
+  if (rwlock_test ())
+    return 1;
+
+  return 0;
+}
+#else
+int do_test (void)
+{
+  return 0;
+}
+#endif
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/nptl/tst-initializers2-c89.c b/nptl/tst-initializers2-c89.c
new file mode 100644
index 0000000..1fb8af6
--- /dev/null
+++ b/nptl/tst-initializers2-c89.c
@@ -0,0 +1 @@
+#include "tst-initializers2.c"
diff --git a/nptl/tst-initializers2-c99.c b/nptl/tst-initializers2-c99.c
new file mode 100644
index 0000000..1fb8af6
--- /dev/null
+++ b/nptl/tst-initializers2-c99.c
@@ -0,0 +1 @@
+#include "tst-initializers2.c"
diff --git a/nptl/tst-initializers2-gnu89.c b/nptl/tst-initializers2-gnu89.c
new file mode 100644
index 0000000..1fb8af6
--- /dev/null
+++ b/nptl/tst-initializers2-gnu89.c
@@ -0,0 +1 @@
+#include "tst-initializers2.c"
diff --git a/nptl/tst-initializers2-gnu99.c b/nptl/tst-initializers2-gnu99.c
new file mode 100644
index 0000000..1fb8af6
--- /dev/null
+++ b/nptl/tst-initializers2-gnu99.c
@@ -0,0 +1 @@
+#include "tst-initializers2.c"
diff --git a/nptl/tst-initializers2.c b/nptl/tst-initializers2.c
new file mode 100644
index 0000000..42a5033
--- /dev/null
+++ b/nptl/tst-initializers2.c
@@ -0,0 +1,50 @@
+/* Copyright (C) 2005, 2006, 2007, 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
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+/* We test the code undef conditions outside of glibc.  */
+#undef _LIBC
+
+#include <pthread.h>
+
+/* Test initializers for elided locks */
+
+pthread_mutex_t mtx_timed_elision = PTHREAD_MUTEX_INIT_NP(PTHREAD_MUTEX_TIMED_NP|
+							  PTHREAD_MUTEX_ELISION_NP);
+pthread_mutex_t mtx_timed_no_elision = PTHREAD_MUTEX_INIT_NP(PTHREAD_MUTEX_TIMED_NP|
+							     PTHREAD_MUTEX_NO_ELISION_NP);
+pthread_mutex_t mtx_adaptive_elision = PTHREAD_MUTEX_INIT_NP(PTHREAD_MUTEX_ADAPTIVE_NP|
+							     PTHREAD_MUTEX_ELISION_NP);
+pthread_mutex_t mtx_adaptive_no_elision = PTHREAD_MUTEX_INIT_NP(PTHREAD_MUTEX_ADAPTIVE_NP|
+								PTHREAD_MUTEX_NO_ELISION_NP);
+
+int
+main (void)
+{
+  if (mtx_timed_elision.__data.__kind !=
+      (PTHREAD_MUTEX_TIMED_NP|PTHREAD_MUTEX_ELISION_NP))
+    return 1;
+  if (mtx_timed_no_elision.__data.__kind !=
+      (PTHREAD_MUTEX_TIMED_NP|PTHREAD_MUTEX_NO_ELISION_NP))
+    return 2;
+  if (mtx_adaptive_elision.__data.__kind !=
+      (PTHREAD_MUTEX_ADAPTIVE_NP|PTHREAD_MUTEX_ELISION_NP))
+    return 3;
+  if (mtx_adaptive_no_elision.__data.__kind !=
+      (PTHREAD_MUTEX_ADAPTIVE_NP|PTHREAD_MUTEX_NO_ELISION_NP))
+    return 4;
+  return 0;
+}
diff --git a/nptl/tst-mutex5.c b/nptl/tst-mutex5.c
index f19cd8c..4410a47 100644
--- a/nptl/tst-mutex5.c
+++ b/nptl/tst-mutex5.c
@@ -85,6 +85,7 @@ do_test (void)
       return 1;
     }
 
+#ifndef ELIDED
   if (pthread_mutex_trylock (&m) == 0)
     {
       puts ("mutex_trylock succeeded");
@@ -186,6 +187,7 @@ do_test (void)
       puts ("final mutex_unlock failed");
       return 1;
     }
+#endif
 
   if (pthread_mutex_destroy (&m) != 0)
     {
diff --git a/nptl/tst-mutex5b.c b/nptl/tst-mutex5b.c
new file mode 100644
index 0000000..af9cca8
--- /dev/null
+++ b/nptl/tst-mutex5b.c
@@ -0,0 +1,6 @@
+#define TYPE PTHREAD_MUTEX_TIMED_NP|PTHREAD_MUTEX_ELISION_NP
+#include <elision-conf.h>
+#ifdef SUPPORTS_ELISION
+#define ELIDED 1
+#endif
+#include "tst-mutex5.c"
diff --git a/nptl/tst-mutex5c.c b/nptl/tst-mutex5c.c
new file mode 100644
index 0000000..ae92173
--- /dev/null
+++ b/nptl/tst-mutex5c.c
@@ -0,0 +1,2 @@
+#define TYPE PTHREAD_MUTEX_TIMED_NP|PTHREAD_MUTEX_NO_ELISION_NP
+#include "tst-mutex5.c"
diff --git a/nptl/tst-mutex5d.c b/nptl/tst-mutex5d.c
new file mode 100644
index 0000000..328c4c7
--- /dev/null
+++ b/nptl/tst-mutex5d.c
@@ -0,0 +1,2 @@
+#define TYPE PTHREAD_MUTEX_ADAPTIVE_NP|PTHREAD_MUTEX_NO_ELISION_NP
+#include "tst-mutex5.c"
diff --git a/nptl/tst-mutex5e.c b/nptl/tst-mutex5e.c
new file mode 100644
index 0000000..bf5a109
--- /dev/null
+++ b/nptl/tst-mutex5e.c
@@ -0,0 +1,6 @@
+#define TYPE PTHREAD_MUTEX_ADAPTIVE_NP|PTHREAD_MUTEX_ELISION_NP
+#include <elision-conf.h>
+#ifdef SUPPORTS_ELISION
+#define ELIDED 1
+#endif
+#include "tst-mutex5.c"
diff --git a/nptl/tst-mutex7b.c b/nptl/tst-mutex7b.c
new file mode 100644
index 0000000..be39fe2
--- /dev/null
+++ b/nptl/tst-mutex7b.c
@@ -0,0 +1,2 @@
+#define TYPE PTHREAD_MUTEX_TIMED_NP|PTHREAD_MUTEX_ELISION_NP
+#include "tst-mutex7.c"
diff --git a/nptl/tst-mutex7c.c b/nptl/tst-mutex7c.c
new file mode 100644
index 0000000..ab23c42
--- /dev/null
+++ b/nptl/tst-mutex7c.c
@@ -0,0 +1,2 @@
+#define TYPE PTHREAD_MUTEX_TIMED_NP|PTHREAD_MUTEX_NO_ELISION_NP
+#include "tst-mutex7.c"
diff --git a/nptl/tst-mutex7d.c b/nptl/tst-mutex7d.c
new file mode 100644
index 0000000..1b67110
--- /dev/null
+++ b/nptl/tst-mutex7d.c
@@ -0,0 +1,2 @@
+#define TYPE PTHREAD_MUTEX_ADAPTIVE_NP|PTHREAD_MUTEX_NO_ELISION_NP
+#include "tst-mutex7.c"
diff --git a/nptl/tst-mutex7e.c b/nptl/tst-mutex7e.c
new file mode 100644
index 0000000..eab165e
--- /dev/null
+++ b/nptl/tst-mutex7e.c
@@ -0,0 +1,2 @@
+#define TYPE PTHREAD_MUTEX_ADAPTIVE_NP|PTHREAD_MUTEX_ELISION_NP
+#include "tst-mutex7.c"
diff --git a/nptl/tst-mutex8.c b/nptl/tst-mutex8.c
index 72dc9d4..e7446a5 100644
--- a/nptl/tst-mutex8.c
+++ b/nptl/tst-mutex8.c
@@ -23,6 +23,9 @@
 #include <stdio.h>
 #include <stdlib.h>
 
+#ifndef NAME
+#define NAME "normal"
+#endif
 
 static pthread_mutex_t *m;
 static pthread_barrier_t b;
@@ -93,6 +96,8 @@ tf (void *arg)
 static int
 check_type (const char *mas, pthread_mutexattr_t *ma)
 {
+  int e __attribute__((unused));
+
   if (pthread_mutex_init (m, ma) != 0)
     {
       printf ("1st mutex_init failed for %s\n", mas);
@@ -117,7 +122,8 @@ check_type (const char *mas, pthread_mutexattr_t *ma)
       return 1;
     }
 
-  int e = pthread_mutex_destroy (m);
+#ifndef ELIDED
+  e = pthread_mutex_destroy (m);
   if (e == 0)
     {
       printf ("mutex_destroy of self-locked mutex succeeded for %s\n", mas);
@@ -129,6 +135,7 @@ check_type (const char *mas, pthread_mutexattr_t *ma)
 	      mas);
       return 1;
     }
+#endif
 
   if (pthread_mutex_unlock (m) != 0)
     {
@@ -142,6 +149,7 @@ check_type (const char *mas, pthread_mutexattr_t *ma)
       return 1;
     }
 
+#ifndef ELIDED
   e = pthread_mutex_destroy (m);
   if (e == 0)
     {
@@ -155,6 +163,7 @@ mutex_destroy of self-trylocked mutex did not return EBUSY %s\n",
 	      mas);
       return 1;
     }
+#endif
 
   if (pthread_mutex_unlock (m) != 0)
     {
@@ -189,6 +198,7 @@ mutex_destroy of self-trylocked mutex did not return EBUSY %s\n",
       return 1;
     }
 
+#ifndef ELIDED
   e = pthread_mutex_destroy (m);
   if (e == 0)
     {
@@ -201,6 +211,7 @@ mutex_destroy of self-trylocked mutex did not return EBUSY %s\n",
 mutex_destroy of condvar-used mutex did not return EBUSY for %s\n", mas);
       return 1;
     }
+#endif
 
   done = true;
   if (pthread_cond_signal (&c) != 0)
@@ -259,6 +270,7 @@ mutex_destroy of condvar-used mutex did not return EBUSY for %s\n", mas);
       return 1;
     }
 
+#ifndef ELIDED
   e = pthread_mutex_destroy (m);
   if (e == 0)
     {
@@ -273,6 +285,7 @@ mutex_destroy of condvar-used mutex did not return EBUSY for %s\n", mas);
 	      mas);
       return 1;
     }
+#endif
 
   if (pthread_cancel (th) != 0)
     {
@@ -304,6 +317,7 @@ mutex_destroy of condvar-used mutex did not return EBUSY for %s\n", mas);
 static int
 do_test (void)
 {
+  pthread_mutexattr_t ma;
   pthread_mutex_t mm;
   m = &mm;
 
@@ -319,10 +333,25 @@ do_test (void)
       return 1;
     }
 
-  puts ("check normal mutex");
-  int res = check_type ("normal", NULL);
+#ifdef TYPE
+  if (pthread_mutexattr_init (&ma) != 0)
+    {
+      puts ("0th mutexattr_init failed");
+      return 1;
+    }
+  if (pthread_mutexattr_settype (&ma, TYPE) != 0)
+    {
+      puts ("0th mutexattr_settype failed");
+      return 1;
+    }
+
+  puts ("check " NAME " mutex");
+  int res = check_type (NAME, &ma);
+#else
+  puts ("check " NAME " mutex");
+  int res = check_type (NAME, NULL);
+#endif
 
-  pthread_mutexattr_t ma;
   if (pthread_mutexattr_init (&ma) != 0)
     {
       puts ("1st mutexattr_init failed");
diff --git a/nptl/tst-mutex8b.c b/nptl/tst-mutex8b.c
new file mode 100644
index 0000000..ed8570d
--- /dev/null
+++ b/nptl/tst-mutex8b.c
@@ -0,0 +1,7 @@
+#define NAME "timed elided"
+#include <elision-conf.h>
+#ifdef SUPPORTS_ELISION
+#define ELIDED 1
+#endif
+#define TYPE PTHREAD_MUTEX_TIMED_NP|PTHREAD_MUTEX_ELISION_NP
+#include "tst-mutex8.c"
diff --git a/nptl/tst-mutex8c.c b/nptl/tst-mutex8c.c
new file mode 100644
index 0000000..12c41a9
--- /dev/null
+++ b/nptl/tst-mutex8c.c
@@ -0,0 +1,7 @@
+#define NAME "adaptive elided"
+#include <elision-conf.h>
+#ifdef SUPPORTS_ELISION
+#define ELIDED 1
+#endif
+#define TYPE PTHREAD_MUTEX_ADAPTIVE_NP|PTHREAD_MUTEX_ELISION_NP
+#include "tst-mutex8.c"
diff --git a/nptl/tst-mutex8d.c b/nptl/tst-mutex8d.c
new file mode 100644
index 0000000..e58d281
--- /dev/null
+++ b/nptl/tst-mutex8d.c
@@ -0,0 +1,3 @@
+#define NAME "timed not elided"
+#define TYPE PTHREAD_MUTEX_TIMED_NP|PTHREAD_MUTEX_NO_ELISION_NP
+#include "tst-mutex8.c"
diff --git a/nptl/tst-mutex8e.c b/nptl/tst-mutex8e.c
new file mode 100644
index 0000000..ef0f82f
--- /dev/null
+++ b/nptl/tst-mutex8e.c
@@ -0,0 +1,3 @@
+#define NAME "adaptive not elided"
+#define TYPE PTHREAD_MUTEX_ADAPTIVE_NP|PTHREAD_MUTEX_NO_ELISION_NP
+#include "tst-mutex8.c"
diff --git a/nptl/tst-mutex8f.c b/nptl/tst-mutex8f.c
new file mode 100644
index 0000000..9d203d2
--- /dev/null
+++ b/nptl/tst-mutex8f.c
@@ -0,0 +1,3 @@
+#define NAME "adaptive"
+#define TYPE PTHREAD_MUTEX_ADAPTIVE_NP
+#include "tst-mutex8.c"
diff --git a/nptl/tst-mutex8g.c b/nptl/tst-mutex8g.c
new file mode 100644
index 0000000..78f1395
--- /dev/null
+++ b/nptl/tst-mutex8g.c
@@ -0,0 +1,5 @@
+#include <elision-conf.h>
+#ifdef SUPPORTS_ELISION
+#define ELIDED 1
+#endif
+#include "tst-mutex8.c"
-- 
1.7.7.6


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