diff options
| author | Samuel Thibault <samuel.thibault@ens-lyon.org> | 2020-02-16 14:30:17 +0000 |
|---|---|---|
| committer | Samuel Thibault <samuel.thibault@ens-lyon.org> | 2020-02-16 14:43:54 +0000 |
| commit | a25077a431758b30aa60103945fe70811e8207ef (patch) | |
| tree | c4d0fd554de8697c129b937c359f07a0f2a6af28 /sysdeps/pthread | |
| parent | f640c4231df53aecd5880b4a172981e633de2718 (diff) | |
| download | glibc-a25077a431758b30aa60103945fe70811e8207ef.tar.xz glibc-a25077a431758b30aa60103945fe70811e8207ef.zip | |
pthread: Move robust mutex tests from nptl to sysdeps/pthread
tst-robust8.c prints some mutex internals for nptl debugging, this
needed to be made conditioned by getting built with nptl.
Diffstat (limited to 'sysdeps/pthread')
| -rw-r--r-- | sysdeps/pthread/Makefile | 2 | ||||
| -rw-r--r-- | sysdeps/pthread/tst-robust1.c | 338 | ||||
| -rw-r--r-- | sysdeps/pthread/tst-robust10.c | 110 | ||||
| -rw-r--r-- | sysdeps/pthread/tst-robust2.c | 3 | ||||
| -rw-r--r-- | sysdeps/pthread/tst-robust3.c | 20 | ||||
| -rw-r--r-- | sysdeps/pthread/tst-robust4.c | 2 | ||||
| -rw-r--r-- | sysdeps/pthread/tst-robust5.c | 2 | ||||
| -rw-r--r-- | sysdeps/pthread/tst-robust6.c | 2 | ||||
| -rw-r--r-- | sysdeps/pthread/tst-robust7.c | 212 | ||||
| -rw-r--r-- | sysdeps/pthread/tst-robust8.c | 277 | ||||
| -rw-r--r-- | sysdeps/pthread/tst-robust9.c | 93 |
11 files changed, 1061 insertions, 0 deletions
diff --git a/sysdeps/pthread/Makefile b/sysdeps/pthread/Makefile index 396f2b18bf..b6491d6309 100644 --- a/sysdeps/pthread/Makefile +++ b/sysdeps/pthread/Makefile @@ -55,6 +55,8 @@ tests += tst-cnd-basic tst-mtx-trylock tst-cnd-broadcast \ tst-key1 tst-key2 tst-key3 tst-key4 \ tst-mutex1 tst-mutex2 tst-mutex3 tst-mutex4 tst-mutex6 tst-mutex10 \ tst-once1 tst-once2 tst-once3 tst-once4 \ + tst-robust1 tst-robust2 tst-robust3 tst-robust4 tst-robust5 \ + tst-robust6 tst-robust7 tst-robust8 tst-robust9 tst-robust10 \ tst-rwlock1 tst-rwlock4 tst-rwlock5 tst-rwlock13 tst-rwlock16 \ tst-rwlock-tryrdlock-stall tst-rwlock-trywrlock-stall \ tst-sem1 tst-sem2 tst-sem3 tst-sem4 tst-sem6 tst-sem7 \ diff --git a/sysdeps/pthread/tst-robust1.c b/sysdeps/pthread/tst-robust1.c new file mode 100644 index 0000000000..fc21b4f52c --- /dev/null +++ b/sysdeps/pthread/tst-robust1.c @@ -0,0 +1,338 @@ +/* Copyright (C) 2005-2020 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2005. + + 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 + <https://www.gnu.org/licenses/>. */ + +#include <errno.h> +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> + + +static pthread_mutex_t m1; +static pthread_mutex_t m2; +static pthread_barrier_t b; + + +#ifndef LOCK +# define LOCK(m) pthread_mutex_lock (m) +#endif + + +static void * +tf (void *arg) +{ + long int round = (long int) arg; + + if (pthread_setcancelstate (PTHREAD_CANCEL_ENABLE, NULL) != 0) + { + printf ("%ld: setcancelstate failed\n", round); + exit (1); + } + + int e = LOCK (&m1); + if (e != 0) + { + printf ("%ld: child: mutex_lock m1 failed with error %d\n", round, e); + exit (1); + } + + e = LOCK (&m2); + if (e != 0) + { + printf ("%ld: child: mutex_lock m2 failed with error %d\n", round, e); + exit (1); + } + + e = pthread_barrier_wait (&b); + if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%ld: child: 1st barrier_wait failed\n", round); + exit (1); + } + + e = pthread_barrier_wait (&b); + if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%ld: child: 2nd barrier_wait failed\n", round); + exit (1); + } + + pthread_testcancel (); + + printf ("%ld: testcancel returned\n", round); + exit (1); +} + + +static int +do_test (void) +{ +#ifdef PREPARE_TMO + PREPARE_TMO; +#endif + + pthread_mutexattr_t a; + if (pthread_mutexattr_init (&a) != 0) + { + puts ("mutexattr_init failed"); + return 1; + } + if (pthread_mutexattr_setrobust_np (&a, PTHREAD_MUTEX_ROBUST_NP) != 0) + { + puts ("mutexattr_setrobust failed"); + return 1; + } + +#ifdef ENABLE_PI + if (pthread_mutexattr_setprotocol (&a, PTHREAD_PRIO_INHERIT) != 0) + { + puts ("pthread_mutexattr_setprotocol failed"); + return 1; + } + else + { + int e = pthread_mutex_init (&m1, &a); + if (e == ENOTSUP) + { + puts ("PI robust mutexes not supported"); + return 0; + } + else if (e != 0) + { + puts ("mutex_init m1 failed"); + return 1; + } + pthread_mutex_destroy (&m1); + } +#endif + +#ifndef NOT_CONSISTENT + if (pthread_mutex_init (&m1, &a) != 0) + { + puts ("mutex_init m1 failed"); + return 1; + } + + if (pthread_mutex_init (&m2, &a) != 0) + { + puts ("mutex_init m2 failed"); + return 1; + } +#endif + + if (pthread_barrier_init (&b, NULL, 2) != 0) + { + puts ("barrier_init failed"); + return 1; + } + + for (long int round = 1; round < 5; ++round) + { +#ifdef NOT_CONSISTENT + if (pthread_mutex_init (&m1 , &a) != 0) + { + puts ("mutex_init m1 failed"); + return 1; + } + if (pthread_mutex_init (&m2 , &a) != 0) + { + puts ("mutex_init m2 failed"); + return 1; + } +#endif + + pthread_t th; + if (pthread_create (&th, NULL, tf, (void *) round) != 0) + { + printf ("%ld: create failed\n", round); + return 1; + } + + int e = pthread_barrier_wait (&b); + if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%ld: parent: 1st barrier_wait failed\n", round); + return 1; + } + + if (pthread_cancel (th) != 0) + { + printf ("%ld: cancel failed\n", round); + return 1; + } + + e = pthread_barrier_wait (&b); + if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%ld: parent: 2nd barrier_wait failed\n", round); + return 1; + } + +#ifndef AFTER_JOIN + if (round & 1) +#endif + { + void *res; + if (pthread_join (th, &res) != 0) + { + printf ("%ld: join failed\n", round); + return 1; + } + if (res != PTHREAD_CANCELED) + { + printf ("%ld: thread not canceled\n", round); + return 1; + } + } + + e = LOCK (&m1); + if (e == 0) + { + printf ("%ld: parent: mutex_lock m1 succeeded\n", round); + return 1; + } + if (e != EOWNERDEAD) + { + printf ("%ld: parent: mutex_lock m1 returned wrong code\n", round); + return 1; + } + + e = LOCK (&m2); + if (e == 0) + { + printf ("%ld: parent: mutex_lock m2 succeeded\n", round); + return 1; + } + if (e != EOWNERDEAD) + { + printf ("%ld: parent: mutex_lock m2 returned wrong code\n", round); + return 1; + } + +#ifndef AFTER_JOIN + if ((round & 1) == 0) + { + void *res; + if (pthread_join (th, &res) != 0) + { + printf ("%ld: join failed\n", round); + return 1; + } + if (res != PTHREAD_CANCELED) + { + printf ("%ld: thread not canceled\n", round); + return 1; + } + } +#endif + +#ifndef NOT_CONSISTENT + e = pthread_mutex_consistent_np (&m1); + if (e != 0) + { + printf ("%ld: mutex_consistent m1 failed with error %d\n", round, e); + return 1; + } + + e = pthread_mutex_consistent_np (&m2); + if (e != 0) + { + printf ("%ld: mutex_consistent m2 failed with error %d\n", round, e); + return 1; + } +#endif + + e = pthread_mutex_unlock (&m1); + if (e != 0) + { + printf ("%ld: mutex_unlock m1 failed with %d\n", round, e); + return 1; + } + + e = pthread_mutex_unlock (&m2); + if (e != 0) + { + printf ("%ld: mutex_unlock m2 failed with %d\n", round, e); + return 1; + } + +#ifdef NOT_CONSISTENT + e = LOCK (&m1); + if (e == 0) + { + printf ("%ld: locking inconsistent mutex m1 succeeded\n", round); + return 1; + } + if (e != ENOTRECOVERABLE) + { + printf ("%ld: locking inconsistent mutex m1 failed with error %d\n", + round, e); + return 1; + } + + if (pthread_mutex_destroy (&m1) != 0) + { + puts ("mutex_destroy m1 failed"); + return 1; + } + + e = LOCK (&m2); + if (e == 0) + { + printf ("%ld: locking inconsistent mutex m2 succeeded\n", round); + return 1; + } + if (e != ENOTRECOVERABLE) + { + printf ("%ld: locking inconsistent mutex m2 failed with error %d\n", + round, e); + return 1; + } + + if (pthread_mutex_destroy (&m2) != 0) + { + puts ("mutex_destroy m2 failed"); + return 1; + } +#endif + } + +#ifndef NOT_CONSISTENT + if (pthread_mutex_destroy (&m1) != 0) + { + puts ("mutex_destroy m1 failed"); + return 1; + } + + if (pthread_mutex_destroy (&m2) != 0) + { + puts ("mutex_destroy m2 failed"); + return 1; + } +#endif + + if (pthread_mutexattr_destroy (&a) != 0) + { + puts ("mutexattr_destroy failed"); + return 1; + } + + return 0; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/sysdeps/pthread/tst-robust10.c b/sysdeps/pthread/tst-robust10.c new file mode 100644 index 0000000000..db8b7e30f6 --- /dev/null +++ b/sysdeps/pthread/tst-robust10.c @@ -0,0 +1,110 @@ +/* Test that pthread_mutex_timedlock properly times out. + Copyright (C) 2016-2020 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 + <https://www.gnu.org/licenses/>. */ + +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> + +pthread_mutex_t mutex; + +static void * +thr (void *arg) +{ + struct timespec abstime; + clock_gettime (CLOCK_REALTIME, &abstime); + abstime.tv_sec += 1; + int ret = pthread_mutex_timedlock (&mutex, &abstime); + if (ret == 0) + { + puts ("mutex_timedlock didn't fail"); + exit (1); + } + if (ret != ETIMEDOUT) + { + printf ("mutex_timedlock failed: %s\n", strerror (ret)); + exit (1); + } + + return 0; +} + +static int +do_test (void) +{ + pthread_t pt; + pthread_mutexattr_t ma; + + if (pthread_mutexattr_init (&ma) != 0) + { + puts ("mutexattr_init failed"); + return 0; + } + if (pthread_mutexattr_setrobust_np (&ma, PTHREAD_MUTEX_ROBUST_NP) != 0) + { + puts ("mutexattr_setrobust failed"); + return 1; + } + if (pthread_mutex_init (&mutex, &ma)) + { + puts ("mutex_init failed"); + return 1; + } + + if (pthread_mutexattr_destroy (&ma)) + { + puts ("mutexattr_destroy failed"); + return 1; + } + + if (pthread_mutex_lock (&mutex)) + { + puts ("mutex_lock failed"); + return 1; + } + + if (pthread_create (&pt, NULL, thr, NULL)) + { + puts ("pthread_create failed"); + return 1; + } + + if (pthread_join (pt, NULL)) + { + puts ("pthread_join failed"); + return 1; + } + + if (pthread_mutex_unlock (&mutex)) + { + puts ("mutex_unlock failed"); + return 1; + } + + if (pthread_mutex_destroy (&mutex)) + { + puts ("mutex_destroy failed"); + return 1; + } + + return 0; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/sysdeps/pthread/tst-robust2.c b/sysdeps/pthread/tst-robust2.c new file mode 100644 index 0000000000..cf603feb4d --- /dev/null +++ b/sysdeps/pthread/tst-robust2.c @@ -0,0 +1,3 @@ +#define AFTER_JOIN 1 +#define LOCK(m) pthread_mutex_trylock (m) +#include "tst-robust1.c" diff --git a/sysdeps/pthread/tst-robust3.c b/sysdeps/pthread/tst-robust3.c new file mode 100644 index 0000000000..e56f2762c7 --- /dev/null +++ b/sysdeps/pthread/tst-robust3.c @@ -0,0 +1,20 @@ +#include <time.h> +#include <sys/time.h> + + +static struct timespec tmo; + + +#define PREPARE_TMO \ + do { \ + struct timeval tv; \ + gettimeofday (&tv, NULL); \ + \ + /* Define the timeout as one hour in the future. */ \ + tmo.tv_sec = tv.tv_sec + 3600; \ + tmo.tv_nsec = 0; \ + } while (0) + + +#define LOCK(m) pthread_mutex_timedlock (m, &tmo) +#include "tst-robust1.c" diff --git a/sysdeps/pthread/tst-robust4.c b/sysdeps/pthread/tst-robust4.c new file mode 100644 index 0000000000..b9c42b85b9 --- /dev/null +++ b/sysdeps/pthread/tst-robust4.c @@ -0,0 +1,2 @@ +#define NOT_CONSISTENT 1 +#include "tst-robust1.c" diff --git a/sysdeps/pthread/tst-robust5.c b/sysdeps/pthread/tst-robust5.c new file mode 100644 index 0000000000..b83d3d66cb --- /dev/null +++ b/sysdeps/pthread/tst-robust5.c @@ -0,0 +1,2 @@ +#define NOT_CONSISTENT 1 +#include "tst-robust2.c" diff --git a/sysdeps/pthread/tst-robust6.c b/sysdeps/pthread/tst-robust6.c new file mode 100644 index 0000000000..6713396de1 --- /dev/null +++ b/sysdeps/pthread/tst-robust6.c @@ -0,0 +1,2 @@ +#define NOT_CONSISTENT 1 +#include "tst-robust3.c" diff --git a/sysdeps/pthread/tst-robust7.c b/sysdeps/pthread/tst-robust7.c new file mode 100644 index 0000000000..be8e7492df --- /dev/null +++ b/sysdeps/pthread/tst-robust7.c @@ -0,0 +1,212 @@ +/* Copyright (C) 2005-2020 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2005. + + 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 + <https://www.gnu.org/licenses/>. */ + +#include <errno.h> +#include <pthread.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> + + +static pthread_barrier_t b; +static pthread_cond_t c = PTHREAD_COND_INITIALIZER; +static pthread_mutex_t m; +static bool first = true; + + +static void * +tf (void *arg) +{ + long int n = (long int) arg; + + if (pthread_mutex_lock (&m) != 0) + { + printf ("thread %ld: mutex_lock failed\n", n + 1); + exit (1); + } + + int e = pthread_barrier_wait (&b); + if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("thread %ld: barrier_wait failed\n", n + 1); + exit (1); + } + + e = pthread_cond_wait (&c, &m); + if (first) + { + if (e != 0) + { + printf ("thread %ld: cond_wait failed\n", n + 1); + exit (1); + } + first = false; + } + else + { + if (e != EOWNERDEAD) + { + printf ("thread %ld: cond_wait did not return EOWNERDEAD\n", n + 1); + exit (1); + } + } + + if (pthread_cancel (pthread_self ()) != 0) + { + printf ("thread %ld: cancel failed\n", n + 1); + exit (1); + } + + pthread_testcancel (); + + printf ("thread %ld: testcancel returned\n", n + 1); + exit (1); +} + + +static int +do_test (void) +{ + pthread_mutexattr_t a; + if (pthread_mutexattr_init (&a) != 0) + { + puts ("mutexattr_init failed"); + return 1; + } + + if (pthread_mutexattr_setrobust_np (&a, PTHREAD_MUTEX_ROBUST_NP) != 0) + { + puts ("mutexattr_setrobust failed"); + return 1; + } + +#ifdef ENABLE_PI + if (pthread_mutexattr_setprotocol (&a, PTHREAD_PRIO_INHERIT) != 0) + { + puts ("pthread_mutexattr_setprotocol failed"); + return 1; + } +#endif + + int e; + e = pthread_mutex_init (&m, &a); + if (e != 0) + { +#ifdef ENABLE_PI + if (e == ENOTSUP) + { + puts ("PI robust mutexes not supported"); + return 0; + } +#endif + puts ("mutex_init failed"); + return 1; + } + + if (pthread_mutexattr_destroy (&a) != 0) + { + puts ("mutexattr_destroy failed"); + return 1; + } + + if (pthread_barrier_init (&b, NULL, 2) != 0) + { + puts ("barrier_init failed"); + return 1; + } + +#define N 5 + pthread_t th[N]; + for (long int n = 0; n < N; ++n) + { + if (pthread_create (&th[n], NULL, tf, (void *) n) != 0) + { + printf ("pthread_create loop %ld failed\n", n + 1); + return 1; + } + + e = pthread_barrier_wait (&b); + if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("parent: barrier_wait failed in round %ld\n", n + 1); + return 1; + } + } + + if (pthread_mutex_lock (&m) != 0) + { + puts ("parent: mutex_lock failed"); + return 1; + } + + if (pthread_mutex_unlock (&m) != 0) + { + puts ("parent: mutex_unlock failed"); + return 1; + } + + if (pthread_cond_broadcast (&c) != 0) + { + puts ("cond_broadcast failed"); + return 1; + } + + for (int n = 0; n < N; ++n) + { + void *res; + if (pthread_join (th[n], &res) != 0) + { + printf ("join round %d failed\n", n + 1); + return 1; + } + if (res != PTHREAD_CANCELED) + { + printf ("thread %d not canceled\n", n + 1); + return 1; + } + } + + e = pthread_mutex_lock (&m); + if (e == 0) + { + puts ("parent: 2nd mutex_lock succeeded"); + return 1; + } + if (e != EOWNERDEAD) + { + puts ("parent: mutex_lock did not return EOWNERDEAD"); + return 1; + } + + if (pthread_mutex_unlock (&m) != 0) + { + puts ("parent: 2nd mutex_unlock failed"); + return 1; + } + + if (pthread_mutex_destroy (&m) != 0) + { + puts ("mutex_destroy fa |
