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]

Re: [PATCH 7/9] Extend the test suite for TSX and add some new tests to test elision


On 05/10/2013 06:42 PM, Andi Kleen wrote:
> 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.

Thanks for adding new tests. I have some comments below.

> 2013-05-02  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..2d52ed0 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-<)

OK.

>  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 = GLIBC_MUTEX=none

No such test.

> +tst-mutex5-ENV = GLIBC_MUTEX=none
> +tst-mutex8-ENV = GLIBC_MUTEX=none
> +tst-mutex8-static-ENV = GLIBC_MUTEX=none
> +tst-mutex8f-ENV = GLIBC_MUTEX=none

Please document in the test what it is that is breaking elision.
This will be useful information for future reviewers, otherwise
we just have some "#ifndef ELIDED" conditionals that require the
reader to re-prove every time in their head why it matters.

> +tst-mutex8g-ENV = GLIBC_MUTEX=elision
> +tst-elision1b-ENV = GLIBC_MUTEX=none GLIBC_RWLOCK=none

Similarly.

> +# disable adaptation for abort hook test
> +tst-elision2-ENV = GLIBC_MUTEX=elision:retry_lock_internal_abort=0:retry_trylock_internal_abort=0


OK.

> +
>  $(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;

OK.

> 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"

OK.

> 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"

OK.

> 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;
> +}

OK.

> diff --git a/nptl/tst-elision1.c b/nptl/tst-elision1.c
> new file mode 100644
> index 0000000..37ad032
> --- /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>

Needs nested indenting.

http://sourceware.org/glibc/wiki/Style_and_Conventions#Nested_C_Preprocessor_Directives

> +
> +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 ("GLIBC_MUTEX");
> +  if (s)
> +    {
> +      char *o = getenv ("GLIBC_RWLOCK");
> +      if (!o || strcmp (o, s))
> +        {
> +          puts("GLIBC_MUTEX and GLIBC_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"

OK.

> 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"

OK.

> 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;
> +}

Use test-skeleton.c please. All tests need to be able to abort
or timeout.

> 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

Use #ifndef USE_ELISION.

>    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

Use USE_ELISION 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

OK.
  
>    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"
> 



Cheers,
Carlos.


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