diff options
author | Samuel Thibault <samuel.thibault@ens-lyon.org> | 2020-02-09 19:17:51 +0000 |
---|---|---|
committer | Samuel Thibault <samuel.thibault@ens-lyon.org> | 2020-02-09 19:24:44 +0000 |
commit | d8f1f2d9ab2144b589fdac3e381cd86e71871e43 (patch) | |
tree | 586832da5c77a4635006cfecb4515e23956ddaa6 /sysdeps/pthread | |
parent | htl: make pthread_cond_destroy return EBUSY on waiters (diff) | |
download | glibc-d8f1f2d9ab2144b589fdac3e381cd86e71871e43.tar.gz glibc-d8f1f2d9ab2144b589fdac3e381cd86e71871e43.tar.bz2 glibc-d8f1f2d9ab2144b589fdac3e381cd86e71871e43.zip |
pthread: Move most cond tests from nptl to sysdeps/pthread
So they can be checked with htl too.
Diffstat (limited to 'sysdeps/pthread')
29 files changed, 3778 insertions, 0 deletions
diff --git a/sysdeps/pthread/Makefile b/sysdeps/pthread/Makefile index 5117110210..2c33c5c904 100644 --- a/sysdeps/pthread/Makefile +++ b/sysdeps/pthread/Makefile @@ -45,7 +45,17 @@ tests += tst-cnd-basic tst-mtx-trylock tst-cnd-broadcast \ tst-attr1 \ tst-basic1 tst-basic2 tst-basic3 tst-basic4 tst-basic5 tst-basic6 \ tst-basic7 \ + tst-cond1 tst-cond2 tst-cond3 tst-cond4 tst-cond5 tst-cond6 tst-cond7 \ + tst-cond8 tst-cond9 tst-cond10 tst-cond12 tst-cond13 \ + tst-cond14 tst-cond15 tst-cond16 tst-cond17 tst-cond18 tst-cond19 \ + tst-cond23 tst-cond24 tst-cond25 \ + tst-cond-except \ tst-mutex1 tst-mutex2 tst-mutex3 tst-mutex4 tst-mutex6 tst-mutex10 \ tst-spin1 tst-spin2 tst-spin3 tst-spin4 +ifeq ($(build-shared),yes) +tests-static += tst-cond8-static +tests += tst-cond8-static +endif + endif diff --git a/sysdeps/pthread/tst-cond-except.c b/sysdeps/pthread/tst-cond-except.c new file mode 100644 index 0000000000..8526e241e6 --- /dev/null +++ b/sysdeps/pthread/tst-cond-except.c @@ -0,0 +1,109 @@ +/* Verify that exception table for pthread_cond_wait is correct. + Copyright (C) 2012-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 <stdint.h> +#include <string.h> +#include <unistd.h> + +pthread_mutex_t mutex; +pthread_cond_t cond; + +#define CHECK_RETURN_VAL_OR_FAIL(ret,str) \ + ({ if ((ret) != 0) \ + { \ + printf ("%s failed: %s\n", (str), strerror (ret)); \ + ret = 1; \ + goto out; \ + } \ + }) + + +void +clean (void *arg) +{ + puts ("clean: Unlocking mutex..."); + pthread_mutex_unlock ((pthread_mutex_t *) arg); + puts ("clean: Mutex unlocked..."); +} + +void * +thr (void *arg) +{ + int ret = 0; + pthread_mutexattr_t mutexAttr; + ret = pthread_mutexattr_init (&mutexAttr); + CHECK_RETURN_VAL_OR_FAIL (ret, "pthread_mutexattr_init"); + + ret = pthread_mutexattr_setprotocol (&mutexAttr, PTHREAD_PRIO_INHERIT); + CHECK_RETURN_VAL_OR_FAIL (ret, "pthread_mutexattr_setprotocol"); + + ret = pthread_mutex_init (&mutex, &mutexAttr); + CHECK_RETURN_VAL_OR_FAIL (ret, "pthread_mutex_init"); + + ret = pthread_cond_init (&cond, 0); + CHECK_RETURN_VAL_OR_FAIL (ret, "pthread_cond_init"); + + puts ("th: Init done, entering wait..."); + + pthread_cleanup_push (clean, (void *) &mutex); + ret = pthread_mutex_lock (&mutex); + CHECK_RETURN_VAL_OR_FAIL (ret, "pthread_mutex_lock"); + while (1) + { + ret = pthread_cond_wait (&cond, &mutex); + CHECK_RETURN_VAL_OR_FAIL (ret, "pthread_cond_wait"); + } + pthread_cleanup_pop (1); + +out: + return (void *) (uintptr_t) ret; +} + +int +do_test (void) +{ + pthread_t thread; + int ret = 0; + void *thr_ret = 0; + ret = pthread_create (&thread, 0, thr, &thr_ret); + CHECK_RETURN_VAL_OR_FAIL (ret, "pthread_create"); + + puts ("main: Thread created, waiting a bit..."); + sleep (2); + + puts ("main: Cancelling thread..."); + ret = pthread_cancel (thread); + CHECK_RETURN_VAL_OR_FAIL (ret, "pthread_cancel"); + + puts ("main: Joining th..."); + ret = pthread_join (thread, NULL); + CHECK_RETURN_VAL_OR_FAIL (ret, "pthread_join"); + + if (thr_ret != NULL) + return 1; + + puts ("main: Joined thread, done!"); + +out: + return ret; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/sysdeps/pthread/tst-cond1.c b/sysdeps/pthread/tst-cond1.c new file mode 100644 index 0000000000..47c68d443b --- /dev/null +++ b/sysdeps/pthread/tst-cond1.c @@ -0,0 +1,96 @@ +/* Copyright (C) 2002-2020 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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 <error.h> +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> + + +static pthread_cond_t cond = PTHREAD_COND_INITIALIZER; +static pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER; + + +static void * +tf (void *p) +{ + int err; + + err = pthread_mutex_lock (&mut); + if (err != 0) + error (EXIT_FAILURE, err, "child: cannot get mutex"); + + puts ("child: got mutex; signalling"); + + pthread_cond_signal (&cond); + + puts ("child: unlock"); + + err = pthread_mutex_unlock (&mut); + if (err != 0) + error (EXIT_FAILURE, err, "child: cannot unlock"); + + puts ("child: done"); + + return NULL; +} + + +static int +do_test (void) +{ + pthread_t th; + int err; + + printf ("&cond = %p\n&mut = %p\n", &cond, &mut); + + puts ("parent: get mutex"); + + err = pthread_mutex_lock (&mut); + if (err != 0) + error (EXIT_FAILURE, err, "parent: cannot get mutex"); + + puts ("parent: create child"); + + err = pthread_create (&th, NULL, tf, NULL); + if (err != 0) + error (EXIT_FAILURE, err, "parent: cannot create thread"); + + puts ("parent: wait for condition"); + + /* This test will fail on spurious wake-ups, which are allowed; however, + the current implementation shouldn't produce spurious wake-ups in the + scenario we are testing here. */ + err = pthread_cond_wait (&cond, &mut); + if (err != 0) + error (EXIT_FAILURE, err, "parent: cannot wait fir signal"); + + puts ("parent: got signal"); + + err = pthread_join (th, NULL); + if (err != 0) + error (EXIT_FAILURE, err, "parent: failed to join"); + + puts ("done"); + + return 0; +} + + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/sysdeps/pthread/tst-cond10.c b/sysdeps/pthread/tst-cond10.c new file mode 100644 index 0000000000..b89c452467 --- /dev/null +++ b/sysdeps/pthread/tst-cond10.c @@ -0,0 +1,172 @@ +/* Copyright (C) 2003-2020 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + + 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 <error.h> +#include <pthread.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> + + +#define N 10 +#define ROUNDS 100 + +static pthread_cond_t cond = PTHREAD_COND_INITIALIZER; +static pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER; +static pthread_barrier_t bN1; +static pthread_barrier_t b2; + + +static void * +tf (void *p) +{ + if (pthread_mutex_lock (&mut) != 0) + { + puts ("child: 1st mutex_lock failed"); + exit (1); + } + + int e = pthread_barrier_wait (&b2); + if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("child: 1st barrier_wait failed"); + exit (1); + } + + if (pthread_cond_wait (&cond, &mut) != 0) + { + puts ("child: cond_wait failed"); + exit (1); + } + + if (pthread_mutex_unlock (&mut) != 0) + { + puts ("child: mutex_unlock failed"); + exit (1); + } + + e = pthread_barrier_wait (&bN1); + if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("child: 2nd barrier_wait failed"); + exit (1); + } + + return NULL; +} + + +static int +do_test (void) +{ + if (pthread_barrier_init (&bN1, NULL, N + 1) != 0) + { + puts ("barrier_init failed"); + exit (1); + } + + if (pthread_barrier_init (&b2, NULL, 2) != 0) + { + puts ("barrier_init failed"); + exit (1); + } + + pthread_attr_t at; + + if (pthread_attr_init (&at) != 0) + { + puts ("attr_init failed"); + return 1; + } + + if (pthread_attr_setstacksize (&at, 1 * 1024 * 1024) != 0) + { + puts ("attr_setstacksize failed"); + return 1; + } + + int r; + for (r = 0; r < ROUNDS; ++r) + { + printf ("round %d\n", r + 1); + + int i; + pthread_t th[N]; + for (i = 0; i < N; ++i) + { + if (pthread_create (&th[i], &at, tf, NULL) != 0) + { + puts ("create failed"); + exit (1); + } + + int e = pthread_barrier_wait (&b2); + if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("parent: 1st barrier_wait failed"); + exit (1); + } + } + + if (pthread_mutex_lock (&mut) != 0) + { + puts ("parent: mutex_lock failed"); + exit (1); + } + if (pthread_mutex_unlock (&mut) != 0) + { + puts ("parent: mutex_unlock failed"); + exit (1); + } + + /* N single signal calls. Without locking. This tests that no + signal gets lost. */ + for (i = 0; i < N; ++i) + if (pthread_cond_signal (&cond) != 0) + { + puts ("cond_signal failed"); + exit (1); + } + + int e = pthread_barrier_wait (&bN1); + if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("parent: 2nd barrier_wait failed"); + exit (1); + } + + for (i = 0; i < N; ++i) + if (pthread_join (th[i], NULL) != 0) + { + puts ("join failed"); + exit (1); + } + } + + if (pthread_attr_destroy (&at) != 0) + { + puts ("attr_destroy failed"); + return 1; + } + + return 0; +} + + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/sysdeps/pthread/tst-cond11-static.c b/sysdeps/pthread/tst-cond11-static.c new file mode 100644 index 0000000000..9bccb8ec8b --- /dev/null +++ b/sysdeps/pthread/tst-cond11-static.c @@ -0,0 +1 @@ +#include "tst-cond11.c" diff --git a/sysdeps/pthread/tst-cond11.c b/sysdeps/pthread/tst-cond11.c new file mode 100644 index 0000000000..209e2f0c8d --- /dev/null +++ b/sysdeps/pthread/tst-cond11.c @@ -0,0 +1,122 @@ +/* Copyright (C) 2003-2020 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + + 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 <time.h> +#include <unistd.h> +#include <support/check.h> +#include <support/test-driver.h> +#include <support/timespec.h> +#include <support/xthread.h> +#include <support/xtime.h> + +/* A bogus clock value that tells run_test to use pthread_cond_timedwait + rather than pthread_condclockwait. */ +#define CLOCK_USE_ATTR_CLOCK (-1) + +#if defined _POSIX_CLOCK_SELECTION && _POSIX_CLOCK_SELECTION >= 0 +static int +run_test (clockid_t attr_clock, clockid_t wait_clock) +{ + pthread_condattr_t condattr; + pthread_cond_t cond; + pthread_mutexattr_t mutattr; + pthread_mutex_t mut; + + verbose_printf ("attr_clock = %d\n", (int) attr_clock); + + TEST_COMPARE (pthread_condattr_init (&condattr), 0); + TEST_COMPARE (pthread_condattr_setclock (&condattr, attr_clock), 0); + + clockid_t attr_clock_read; + TEST_COMPARE (pthread_condattr_getclock (&condattr, &attr_clock_read), 0); + TEST_COMPARE (attr_clock, attr_clock_read); + + TEST_COMPARE (pthread_cond_init (&cond, &condattr), 0); + TEST_COMPARE (pthread_condattr_destroy (&condattr), 0); + + xpthread_mutexattr_init (&mutattr); + xpthread_mutexattr_settype (&mutattr, PTHREAD_MUTEX_ERRORCHECK); + xpthread_mutex_init (&mut, &mutattr); + xpthread_mutexattr_destroy (&mutattr); + + xpthread_mutex_lock (&mut); + TEST_COMPARE (pthread_mutex_lock (&mut), EDEADLK); + + struct timespec ts_timeout; + xclock_gettime (wait_clock == CLOCK_USE_ATTR_CLOCK ? attr_clock : wait_clock, + &ts_timeout); + + /* Wait one second. */ + ++ts_timeout.tv_sec; + + if (wait_clock == CLOCK_USE_ATTR_CLOCK) { + TEST_COMPARE (pthread_cond_timedwait (&cond, &mut, &ts_timeout), ETIMEDOUT); + TEST_TIMESPEC_BEFORE_NOW (ts_timeout, attr_clock); + } else { + TEST_COMPARE (pthread_cond_clockwait (&cond, &mut, wait_clock, &ts_timeout), + ETIMEDOUT); + TEST_TIMESPEC_BEFORE_NOW (ts_timeout, wait_clock); + } + + xpthread_mutex_unlock (&mut); + xpthread_mutex_destroy (&mut); + TEST_COMPARE (pthread_cond_destroy (&cond), 0); + + return 0; +} +#endif + + +static int +do_test (void) +{ +#if !defined _POSIX_CLOCK_SELECTION || _POSIX_CLOCK_SELECTION == -1 + + FAIL_UNSUPPORTED ("_POSIX_CLOCK_SELECTION not supported, test skipped"); + +#else + + run_test (CLOCK_REALTIME, CLOCK_USE_ATTR_CLOCK); + +# if defined _POSIX_MONOTONIC_CLOCK && _POSIX_MONOTONIC_CLOCK >= 0 +# if _POSIX_MONOTONIC_CLOCK == 0 + int e = sysconf (_SC_MONOTONIC_CLOCK); + if (e < 0) + puts ("CLOCK_MONOTONIC not supported"); + else if (e == 0) + FAIL_RET ("sysconf (_SC_MONOTONIC_CLOCK) must not return 0"); + else + { +# endif + run_test (CLOCK_MONOTONIC, CLOCK_USE_ATTR_CLOCK); + run_test (CLOCK_REALTIME, CLOCK_MONOTONIC); + run_test (CLOCK_MONOTONIC, CLOCK_MONOTONIC); + run_test (CLOCK_MONOTONIC, CLOCK_REALTIME); + } +# else + puts ("_POSIX_MONOTONIC_CLOCK not defined"); +# endif + + return 0; +#endif +} + +#include <support/test-driver.c> diff --git a/sysdeps/pthread/tst-cond12.c b/sysdeps/pthread/tst-cond12.c new file mode 100644 index 0000000000..474bedc39c --- /dev/null +++ b/sysdeps/pthread/tst-cond12.c @@ -0,0 +1,195 @@ +/* Copyright (C) 2003-2020 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + + 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 <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <sys/mman.h> +#include <sys/wait.h> + + +static char fname[] = "/tmp/tst-cond12-XXXXXX"; +static int fd; + + +static void prepare (void); +#define PREPARE(argc, argv) prepare () + +static int do_test (void); +#define TEST_FUNCTION do_test () + +#include "../test-skeleton.c" + + +static void +prepare (void) +{ + fd = mkstemp (fname); + if (fd == -1) + { + printf ("mkstemp failed: %m\n"); + exit (1); + } + add_temp_file (fname); + if (ftruncate (fd, 1000) < 0) + { + printf ("ftruncate failed: %m\n"); + exit (1); + } +} + + +static int +do_test (void) +{ + struct + { + pthread_mutex_t m; + pthread_cond_t c; + int var; + } *p = mmap (NULL, sizeof (*p), PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); + if (p == MAP_FAILED) + { + printf ("initial mmap failed: %m\n"); + return 1; + } + + pthread_mutexattr_t ma; + if (pthread_mutexattr_init (&ma) != 0) + { + puts ("mutexattr_init failed"); + return 1; + } + if (pthread_mutexattr_setpshared (&ma, 1) != 0) + { + puts ("mutexattr_setpshared failed"); + return 1; + } + if (pthread_mutex_init (&p->m, &ma) != 0) + { + puts ("mutex_init failed"); + return 1; + } + if (pthread_mutexattr_destroy (&ma) != 0) + { + puts ("mutexattr_destroy failed"); + return 1; + } + + pthread_condattr_t ca; + if (pthread_condattr_init (&ca) != 0) + { + puts ("condattr_init failed"); + return 1; + } + if (pthread_condattr_setpshared (&ca, 1) != 0) + { + puts ("condattr_setpshared failed"); + return 1; + } + if (pthread_cond_init (&p->c, &ca) != 0) + { + puts ("mutex_init failed"); + return 1; + } + if (pthread_condattr_destroy (&ca) != 0) + { + puts ("condattr_destroy failed"); + return 1; + } + + if (pthread_mutex_lock (&p->m) != 0) + { + puts ("initial mutex_lock failed"); + return 1; + } + + p->var = 42; + + pid_t pid = fork (); + if (pid == -1) + { + printf ("fork failed: %m\n"); + return 1; + } + + if (pid == 0) + { + void *oldp = p; + p = mmap (NULL, sizeof (*p), PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); + + if (p == oldp) + { + puts ("child: mapped to same address"); + kill (getppid (), SIGKILL); + exit (1); + } + + munmap (oldp, sizeof (*p)); + + if (pthread_mutex_lock (&p->m) != 0) + { + puts ("child: mutex_lock failed"); + kill (getppid (), SIGKILL); + exit (1); + } + + p->var = 0; + +#ifndef USE_COND_SIGNAL + if (pthread_cond_broadcast (&p->c) != 0) + { + puts ("child: cond_broadcast failed"); + kill (getppid (), SIGKILL); + exit (1); + } +#else + if (pthread_cond_signal (&p->c) != 0) + { + puts ("child: cond_signal failed"); + kill (getppid (), SIGKILL); + exit (1); + } +#endif + + if (pthread_mutex_unlock (&p->m) != 0) + { + puts ("child: mutex_unlock failed"); + kill (getppid (), SIGKILL); + exit (1); + } + + exit (0); + } + + do + pthread_cond_wait (&p->c, &p->m); + while (p->var != 0); + + if (TEMP_FAILURE_RETRY (waitpid (pid, NULL, 0)) != pid) + { + printf ("waitpid failed: %m\n"); + kill (pid, SIGKILL); + return 1; + } + + return 0; +} diff --git a/sysdeps/pthread/tst-cond13.c b/sysdeps/pthread/tst-cond13.c new file mode 100644 index 0000000000..29d79b533e --- /dev/null +++ b/sysdeps/pthread/tst-cond13.c @@ -0,0 +1,2 @@ +#define USE_COND_SIGNAL 1 +#include "tst-cond12.c" diff --git a/sysdeps/pthread/tst-cond14.c b/sysdeps/pthread/tst-cond14.c new file mode 100644 index 0000000000..e2d897ac3b --- /dev/null +++ b/sysdeps/pthread/tst-cond14.c @@ -0,0 +1,116 @@ +/* Copyright (C) 2004-2020 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2004. + + 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 <unistd.h> + + +static pthread_cond_t cond = PTHREAD_COND_INITIALIZER; +static pthread_mutex_t mut = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP; +static pthread_mutex_t mut2 = PTHREAD_MUTEX_INITIALIZER; + +static void * +tf (void *p) +{ + if (pthread_mutex_lock (&mut) != 0) + { + printf ("%s: 1st mutex_lock failed\n", __func__); + exit (1); + } + if (pthread_mutex_lock (&mut) != 0) + { + printf ("%s: 2nd mutex_lock failed\n", __func__); + exit (1); + } + if (pthread_mutex_lock (&mut) != 0) + { + printf ("%s: 3rd mutex_lock failed\n", __func__); + exit (1); + } + + if (pthread_mutex_unlock (&mut2) != 0) + { + printf ("%s: mutex_unlock failed\n", __func__); + exit (1); + } + + if (pthread_cond_wait (&cond, &mut) != 0) + { + printf ("%s: cond_wait failed\n", __func__); + exit (1); + } + + puts ("child: done"); + + return NULL; +} + + +static int +do_test (void) +{ + if (pthread_mutex_lock (&mut2) != 0) + { + puts ("1st mutex_lock failed"); + return 1; + } + + puts ("parent: create child"); + + pthread_t th; + int err = pthread_create (&th, NULL, tf, NULL); + if (err != 0) + { + printf ("parent: cannot create thread: %s\n", strerror (err)); + return 1; + } + + /* We have to synchronize with the child. */ + if (pthread_mutex_lock (&mut2) != 0) + { + puts ("2nd mutex_lock failed"); + return 1; + } + + /* Give the child to reach to pthread_cond_wait. */ + sleep (1); + + if (pthread_cond_signal (&cond) != 0) + { + puts ("cond_signal failed"); + return 1; + } + + err = pthread_join (th, NULL); + if (err != 0) + { + printf ("parent: failed to join: %s\n", strerror (err)); + return 1; + } + + puts ("done"); + + return 0; +} + + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/sysdeps/pthread/tst-cond15.c b/sysdeps/pthread/tst-cond15.c new file mode 100644 index 0000000000..fefab95996 --- /dev/null +++ b/sysdeps/pthread/tst-cond15.c @@ -0,0 +1,158 @@ +/* Copyright (C) 2004-2020 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2004. + + 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> +#include <string.h> +#include <unistd.h> +#include <sys/time.h> + + +static pthread_cond_t cond = PTHREAD_COND_INITIALIZER; +static pthread_mutex_t mut = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP; +static pthread_mutex_t mut2 = PTHREAD_MUTEX_INITIALIZER; + +static void * +tf (void *p) +{ + if (pthread_mutex_lock (&mut) != 0) + { + printf ("%s: 1st mutex_lock failed\n", __func__); + exit (1); + } + if (pthread_mutex_lock (&mut) != 0) + { + printf ("%s: 2nd mutex_lock failed\n", __func__); + exit (1); + } + if (pthread_mutex_lock (&mut) != 0) + { + printf ("%s: 3rd mutex_lock failed\n", __func__); + exit (1); + } + + if (pthread_mutex_unlock (&mut2) != 0) + { + printf ("%s: mutex_unlock failed\n", __func__); + exit (1); + } + + struct timeval tv; + gettimeofday (&tv, NULL); + struct timespec ts; + TIMEVAL_TO_TIMESPEC (&tv, &ts); + ts.tv_sec += p == NULL ? 100 : 1; + + int err = pthread_cond_timedwait (&cond, &mut, &ts); + if ((err != 0 && p == NULL) || (err != ETIMEDOUT && p != NULL)) + { + printf ("%s: cond_wait failed\n", __func__); + exit (1); + } + + if (pthread_mutex_unlock (&mut) != 0) + { + printf ("%s: 1st mutex_unlock failed\n", __func__); + exit (1); + } + if (pthread_mutex_unlock (&mut) != 0) + { + printf ("%s: 2nd mutex_unlock failed\n", __func__); + exit (1); + } + if (pthread_mutex_unlock (&mut) != 0) + { + printf ("%s: 3rd mutex_unlock failed\n", __func__); + exit (1); + } + + puts ("child: done"); + + return NULL; +} + + +static int +do_test (void) +{ + if (pthread_mutex_lock (&mut2) != 0) + { + puts ("1st mutex_lock failed"); + return 1; + } + + puts ("parent: create 1st child"); + + pthread_t th; + int err = pthread_create (&th, NULL, tf, NULL); + if (err != 0) + { + printf ("parent: cannot 1st create thread: %s\n", strerror (err)); + return 1; + } + + /* We have to synchronize with the child. */ + if (pthread_mutex_lock (&mut2) != 0) + { + puts ("2nd mutex_lock failed"); + return 1; + } + + /* Give the child to reach to pthread_cond_wait. */ + sleep (1); + + if (pthread_cond_signal (&cond) != 0) + { + puts ("cond_signal failed"); + return 1; + } + + err = pthread_join (th, NULL); + if (err != 0) + { + printf ("parent: failed to join: %s\n", strerror (err)); + return 1; + } + + + puts ("parent: create 2nd child"); + + err = pthread_create (&th, NULL, tf, (void *) 1l); + if (err != 0) + { + printf ("parent: cannot 2nd create thread: %s\n", strerror (err)); + return 1; + } + + err = pthread_join (th, NULL); + if (err != 0) + { + printf ("parent: failed to join: %s\n", strerror (err)); + return 1; + } + + puts ("done"); + + return 0; +} + + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/sysdeps/pthread/tst-cond16.c b/sysdeps/pthread/tst-cond16.c new file mode 100644 index 0000000000..daadd87860 --- /dev/null +++ b/sysdeps/pthread/tst-cond16.c @@ -0,0 +1,108 @@ +/* Copyright (C) 2004-2020 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@redhat.com>, 2004. + + 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 <limits.h> +#include <pthread.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + +pthread_cond_t cv = PTHREAD_COND_INITIALIZER; +pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; +bool n, exiting; +FILE *f; +enum { count = 8 }; /* Number of worker threads. */ + +void * +tf (void *dummy) +{ + bool loop = true; + + while (loop) + { + pthread_mutex_lock (&lock); + while (n && !exiting) + pthread_cond_wait (&cv, &lock); + n = true; + pthread_mutex_unlock (&lock); + + fputs (".", f); + + pthread_mutex_lock (&lock); + n = false; + if (exiting) + loop = false; +#ifdef UNLOCK_AFTER_BROADCAST + pthread_cond_broadcast (&cv); + pthread_mutex_unlock (&lock); +#else + pthread_mutex_unlock (&lock); + pthread_cond_broadcast (&cv); +#endif + } + + return NULL; +} + +int +do_test (void) +{ + f = fopen ("/dev/null", "w"); + if (f == NULL) + { + printf ("couldn't open /dev/null, %m\n"); + return 1; + } + + pthread_t th[count]; + pthread_attr_t attr; + int i, ret, sz; + pthread_attr_init (&attr); + sz = sysconf (_SC_PAGESIZE); +#ifdef PTHREAD_STACK_MIN + if (sz < PTHREAD_STACK_MIN) + sz = PTHREAD_STACK_MIN; +#endif + pthread_attr_setstacksize (&attr, sz); + for (i = 0; i < count; ++i) + if ((ret = pthread_create (&th[i], &attr, tf, NULL)) != 0) + { + errno = ret; + printf ("pthread_create %d failed: %m\n", i); + return 1; + } + + struct timespec ts = { .tv_sec = 20, .tv_nsec = 0 }; + while (nanosleep (&ts, &ts) != 0); + + pthread_mutex_lock (&lock); + exiting = true; + pthread_mutex_unlock (&lock); + + for (i = 0; i < count; ++i) + pthread_join (th[i], NULL); + + fclose (f); + return 0; +} + +#define TEST_FUNCTION do_test () +#define TIMEOUT 40 +#include "../test-skeleton.c" diff --git a/sysdeps/pthread/tst-cond17.c b/sysdeps/pthread/tst-cond17.c new file mode 100644 index 0000000000..0586fa59ac --- /dev/null +++ b/sysdeps/pthread/tst-cond17.c @@ -0,0 +1,2 @@ +#define UNLOCK_AFTER_BROADCAST 1 +#include "tst-cond16.c" diff --git a/sysdeps/pthread/tst-cond18.c b/sysdeps/pthread/tst-cond18.c new file mode 100644 index 0000000000..38c35d7602 --- /dev/null +++ b/sysdeps/pthread/tst-cond18.c @@ -0,0 +1,121 @@ +/* Copyright (C) 2004-2020 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@redhat.com>, 2004. + + 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 <limits.h> +#include <fcntl.h> +#include <pthread.h> +#include <stdbool.h> +#include <stdlib.h> +#include <stdio.h> +#include <unistd.h> + +pthread_cond_t cv = PTHREAD_COND_INITIALIZER; +pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; +bool exiting; +int fd, spins, nn; +enum { count = 8 }; /* Number of worker threads. */ + +void * +tf (void *id) +{ + pthread_mutex_lock (&lock); + + if ((long) id == 0) + { + while (!exiting) + { + if ((spins++ % 1000) == 0) + write (fd, ".", 1); + pthread_mutex_unlock (&lock); + + pthread_mutex_lock (&lock); + int njobs = rand () % (count + 1); + nn = njobs; + if ((rand () % 30) == 0) + pthread_cond_broadcast (&cv); + else + while (njobs--) + pthread_cond_signal (&cv); + } + + pthread_cond_broadcast (&cv); + } + else + { + while (!exiting) + { + while (!nn && !exiting) + pthread_cond_wait (&cv, &lock); + --nn; + pthread_mutex_unlock (&lock); + + pthread_mutex_lock (&lock); + } + } + + pthread_mutex_unlock (&lock); + return NULL; +} + +int +do_test (void) +{ + fd = open ("/dev/null", O_WRONLY); + if (fd < 0) + { + printf ("couldn't open /dev/null, %m\n"); + return 1; + } + + pthread_t th[count + 1]; + pthread_attr_t attr; + int i, ret, sz; + pthread_attr_init (&attr); + sz = sysconf (_SC_PAGESIZE); +#ifdef PTHREAD_STACK_MIN + if (sz < PTHREAD_STACK_MIN) + sz = PTHREAD_STACK_MIN; +#endif + pthread_attr_setstacksize (&attr, sz); + + for (i = 0; i <= count; ++i) + if ((ret = pthread_create (&th[i], &attr, tf, (void *) (long) i)) != 0) + { + errno = ret; + printf ("pthread_create %d failed: %m\n", i); + return 1; + } + + struct timespec ts = { .tv_sec = 20, .tv_nsec = 0 }; + while (nanosleep (&ts, &ts) != 0); + + pthread_mutex_lock (&lock); + exiting = true; + pthread_mutex_unlock (&lock); + + for (i = 0; i < count; ++i) + pthread_join (th[i], NULL); + + close (fd); + return 0; +} + +#define TEST_FUNCTION do_test () +#define TIMEOUT 40 +#include "../test-skeleton.c" diff --git a/sysdeps/pthread/tst-cond19.c b/sysdeps/pthread/tst-cond19.c new file mode 100644 index 0000000000..e6c1caeeea --- /dev/null +++ b/sysdeps/pthread/tst-cond19.c @@ -0,0 +1,75 @@ +/* Copyright (C) 2004-2020 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2004. + + 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> +#include <time.h> + + +static pthread_cond_t cond = PTHREAD_COND_INITIALIZER; +static pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER; + + +static int +do_test (void) +{ + int result = 0; + struct timespec ts; + + if (clock_gettime (CLOCK_REALTIME, &ts) != 0) + { + puts ("clock_gettime failed"); + return 1; + } + + ts.tv_nsec = -1; + + int e = pthread_cond_timedwait (&cond, &mut, &ts); + if (e == 0) + { + puts ("first cond_timedwait did not fail"); + result = 1; + } + else if (e != EINVAL) + { + puts ("first cond_timedwait did not return EINVAL"); + result = 1; + } + + ts.tv_nsec = 2000000000; + + e = pthread_cond_timedwait (&cond, &mut, &ts); + if (e == 0) + { + puts ("second cond_timedwait did not fail"); + result = 1; + } + else if (e != EINVAL) + { + puts ("second cond_timedwait did not return EINVAL"); + result = 1; + } + + return result; +} + + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/sysdeps/pthread/tst-cond2.c b/sysdeps/pthread/tst-cond2.c new file mode 100644 index 0000000000..6752cca05f --- /dev/null +++ b/sysdeps/pthread/tst-cond2.c @@ -0,0 +1,162 @@ +/* Copyright (C) 2002-2020 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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 <error.h> +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> + + +static pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER; +static pthread_cond_t cond = PTHREAD_COND_INITIALIZER; + +static pthread_barrier_t bar; + + +static void * +tf (void *a) +{ + int i = (long int) a; + int err; + + printf ("child %d: lock\n", i); + + err = pthread_mutex_lock (&mut); + if (err != 0) + error (EXIT_FAILURE, err, "locking in child failed"); + + printf ("child %d: sync\n", i); + + int e = pthread_barrier_wait (&bar); + if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("child: barrier_wait failed"); + exit (1); + } + + printf ("child %d: wait\n", i); + + err = pthread_cond_wait (&cond, &mut); + if (err != 0) + error (EXIT_FAILURE, err, "child %d: failed to wait", i); + + printf ("child %d: woken up\n", i); + + err = pthread_mutex_unlock (&mut); + if (err != 0) + error (EXIT_FAILURE, err, "child %d: unlock[2] failed", i); + + printf ("child %d: done\n", i); + + return NULL; +} + + +#define N 10 + + +static int +do_test (void) +{ + pthread_t th[N]; + int i; + int err; + + printf ("&cond = %p\n&mut = %p\n", &cond, &mut); + + if (pthread_barrier_init (&bar, NULL, 2) != 0) + { + puts ("barrier_init failed"); + exit (1); + } + + pthread_attr_t at; + + if (pthread_attr_init (&at) != 0) + { + puts ("attr_init failed"); + return 1; + } + + if (pthread_attr_setstacksize (&at, 1 * 1024 * 1024) != 0) + { + puts ("attr_setstacksize failed"); + return 1; + } + + for (i = 0; i < N; ++i) + { + printf ("create thread %d\n", i); + + err = pthread_create (&th[i], &at, tf, (void *) (long int) i); + if (err != 0) + error (EXIT_FAILURE, err, "cannot create thread %d", i); + + printf ("wait for child %d\n", i); + + /* Wait for the child to start up and get the mutex for the + conditional variable. */ + int e = pthread_barrier_wait (&bar); + if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("barrier_wait failed"); + exit (1); + } + } + + if (pthread_attr_destroy (&at) != 0) + { + puts ("attr_destroy failed"); + return 1; + } + + puts ("get lock outselves"); + + err = pthread_mutex_lock (&mut); + if (err != 0) + error (EXIT_FAILURE, err, "mut locking failed"); + + puts ("broadcast"); + + /* Wake up all threads. */ + err = pthread_cond_broadcast (&cond); + if (err != 0) + error (EXIT_FAILURE, err, "parent: broadcast failed"); + + err = pthread_mutex_unlock (&mut); + if (err != 0) + error (EXIT_FAILURE, err, "mut unlocking failed"); + + /* Join all threads. */ + for (i = 0; i < N; ++i) + { + printf ("join thread %d\n", i); + + err = pthread_join (th[i], NULL); + if (err != 0) + error (EXIT_FAILURE, err, "join of child %d failed", i); + } + + puts ("done"); + + return 0; +} + + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/sysdeps/pthread/tst-cond22.c b/sysdeps/pthread/tst-cond22.c new file mode 100644 index 0000000000..64f19ea0a5 --- /dev/null +++ b/sysdeps/pthread/tst-cond22.c @@ -0,0 +1,162 @@ +#include <pthread.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 = PTHREAD_MUTEX_INITIALIZER; + + +static void +cl (void *arg) +{ + pthread_mutex_unlock (&m); +} + + +static void * +tf (void *arg) +{ + if (pthread_mutex_lock (&m) != 0) + { + printf ("%s: mutex_lock failed\n", __func__); + exit (1); + } + int e = pthread_barrier_wait (&b); + if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("%s: barrier_wait failed\n", __func__); + exit (1); + } + pthread_cleanup_push (cl, NULL); + /* We have to loop here because the cancellation might come after + the cond_wait call left the cancelable area and is then waiting + on the mutex. In this case the beginning of the second cond_wait + call will cause the cancellation to happen. */ + do + if (pthread_cond_wait (&c, &m) != 0) + { + printf ("%s: cond_wait failed\n", __func__); + exit (1); + } + while (arg == NULL); + pthread_cleanup_pop (0); + if (pthread_mutex_unlock (&m) != 0) + { + printf ("%s: mutex_unlock failed\n", __func__); + exit (1); + } + return NULL; +} + + +static int +do_test (void) +{ + int status = 0; + + if (pthread_barrier_init (&b, NULL, 2) != 0) + { + puts ("barrier_init failed"); + return 1; + } + + pthread_t th; + if (pthread_create (&th, NULL, tf, NULL) != 0) + { + puts ("1st create failed"); + return 1; + } + int e = pthread_barrier_wait (&b); + if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("1st barrier_wait failed"); + return 1; + } + if (pthread_mutex_lock (&m) != 0) + { + puts ("1st mutex_lock failed"); + return 1; + } + if (pthread_cond_signal (&c) != 0) + { + puts ("1st cond_signal failed"); + return 1; + } + if (pthread_cancel (th) != 0) + { + puts ("cancel failed"); + return 1; + } + if (pthread_mutex_unlock (&m) != 0) + { + puts ("1st mutex_unlock failed"); + return 1; + } + void *res; + if (pthread_join (th, &res) != 0) + { + puts ("1st join failed"); + return 1; + } + if (res != PTHREAD_CANCELED) + { + puts ("first thread not canceled"); + status = 1; + } + + printf ("cond = { %llu, %llu, %u/%u/%u, %u/%u/%u, %u, %u }\n", + c.__data.__wseq, c.__data.__g1_start, + c.__data.__g_signals[0], c.__data.__g_refs[0], c.__data.__g_size[0], + c.__data.__g_signals[1], c.__data.__g_refs[1], c.__data.__g_size[1], + c.__data.__g1_orig_size, c.__data.__wrefs); + + if (pthread_create (&th, NULL, tf, (void *) 1l) != 0) + { + puts ("2nd create failed"); + return 1; + } + e = pthread_barrier_wait (&b); + if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("2nd barrier_wait failed"); + return 1; + } + if (pthread_mutex_lock (&m) != 0) + { + puts ("2nd mutex_lock failed"); + return 1; + } + if (pthread_cond_signal (&c) != 0) + { + puts ("2nd cond_signal failed"); + return 1; + } + if (pthread_mutex_unlock (&m) != 0) + { + puts ("2nd mutex_unlock failed"); + return 1; + } + if (pthread_join (th, &res) != 0) + { + puts ("2nd join failed"); + return 1; + } + if (res != NULL) + { + puts ("2nd thread canceled"); + status = 1; + } + + printf ("cond = { %llu, %llu, %u/%u/%u, %u/%u/%u, %u, %u }\n", + c.__data.__wseq, c.__data.__g1_start, + c.__data.__g_signals[0], c.__data.__g_refs[0], c.__data.__g_size[0], + c.__data.__g_signals[1], c.__data.__g_refs[1], c.__data.__g_size[1], + c.__data.__g1_orig_size, c.__data.__wrefs); + + return status; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/sysdeps/pthread/tst-cond23.c b/sysdeps/pthread/tst-cond23.c new file mode 100644 index 0000000000..7ffe2ec1a9 --- /dev/null +++ b/sysdeps/pthread/tst-cond23.c @@ -0,0 +1,183 @@ +/* Copyright (C) 2008-2020 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@redhat.com>, 2008. + + 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 <time.h> +#include <unistd.h> + + +#if defined _POSIX_CLOCK_SELECTION && _POSIX_CLOCK_SELECTION >= 0 +static int +check (pthread_condattr_t *condattr, int pshared, clockid_t cl) +{ + clockid_t cl2; + if (pthread_condattr_getclock (condattr, &cl2) != 0) + { + puts ("condattr_getclock failed"); + return 1; + } + if (cl != cl2) + { + printf ("condattr_getclock returned wrong value: %d, expected %d\n", + (int) cl2, (int) cl); + return 1; + } + + int p; + if (pthread_condattr_getpshared (condattr, &p) != 0) + { + puts ("condattr_getpshared failed"); + return 1; + } + else if (p != pshared) + { + printf ("condattr_getpshared returned wrong value: %d, expected %d\n", + p, pshared); + return 1; + } + + return 0; +} + +static int +run_test (clockid_t cl) +{ + pthread_condattr_t condattr; + + printf ("clock = %d\n", (int) cl); + + if (pthread_condattr_init (&condattr) != 0) + { + puts ("condattr_init failed"); + return 1; + } + + if (check (&condattr, PTHREAD_PROCESS_PRIVATE, CLOCK_REALTIME)) + return 1; + + if (pthread_condattr_setpshared (&condattr, PTHREAD_PROCESS_SHARED) != 0) + { + puts ("1st condattr_setpshared failed"); + return 1; + } + + if (check (&condattr, PTHREAD_PROCESS_SHARED, CLOCK_REALTIME)) + return 1; + + if (pthread_condattr_setclock (&condattr, cl) != 0) + { + puts ("1st condattr_setclock failed"); + return 1; + } + + if (check (&condattr, PTHREAD_PROCESS_SHARED, cl)) + return 1; + + if (pthread_condattr_setpshared (&condattr, PTHREAD_PROCESS_PRIVATE) != 0) + { + puts ("2nd condattr_setpshared failed"); + return 1; + } + + if (check (&condattr, PTHREAD_PROCESS_PRIVATE, cl)) + return 1; + + if (pthread_condattr_setclock (&condattr, CLOCK_REALTIME) != 0) + { + puts ("2nd condattr_setclock failed"); + return 1; + } + + if (check (&condattr, PTHREAD_PROCESS_PRIVATE, CLOCK_REALTIME)) + return 1; + + if (pthread_condattr_setclock (&condattr, cl) != 0) + { + puts ("3rd condattr_setclock failed"); + return 1; + } + + if (check (&condattr, PTHREAD_PROCESS_PRIVATE, cl)) + return 1; + + if (pthread_condattr_setpshared (&condattr, PTHREAD_PROCESS_SHARED) != 0) + { + puts ("3rd condattr_setpshared failed"); + return 1; + } + + if (check (&condattr, PTHREAD_PROCESS_SHARED, cl)) + return 1; + + if (pthread_condattr_setclock (&condattr, CLOCK_REALTIME) != 0) + { + puts ("4th condattr_setclock failed"); + return 1; + } + + if (check (&condattr, PTHREAD_PROCESS_SHARED, CLOCK_REALTIME)) + return 1; + + if (pthread_condattr_destroy (&condattr) != 0) + { + puts ("condattr_destroy failed"); + return 1; + } + + return 0; +} +#endif + + +static int +do_test (void) +{ +#if !defined _POSIX_CLOCK_SELECTION || _POSIX_CLOCK_SELECTION == -1 + + puts ("_POSIX_CLOCK_SELECTION not supported, test skipped"); + return 0; + +#else + + int res = run_test (CLOCK_REALTIME); + +# if defined _POSIX_MONOTONIC_CLOCK && _POSIX_MONOTONIC_CLOCK >= 0 +# if _POSIX_MONOTONIC_CLOCK == 0 + int e = sysconf (_SC_MONOTONIC_CLOCK); + if (e < 0) + puts ("CLOCK_MONOTONIC not supported"); + else if (e == 0) + { + puts ("sysconf (_SC_MONOTONIC_CLOCK) must not return 0"); + res = 1; + } + else +# endif + res |= run_test (CLOCK_MONOTONIC); +# else + puts ("_POSIX_MONOTONIC_CLOCK not defined"); +# endif + + return res; +#endif +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/sysdeps/pthread/tst-cond24.c b/sysdeps/pthread/tst-cond24.c new file mode 100644 index 0000000000..a2896f32cc --- /dev/null +++ b/sysdeps/pthread/tst-cond24.c @@ -0,0 +1,248 @@ +/* Verify that condition variables synchronized by PI mutexes don't hang. + Copyright (C) 2012-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> +#include <sys/types.h> +#include <sys/syscall.h> +#include <unistd.h> +#include <sys/time.h> +#include <time.h> + +#define THREADS_NUM 5 +#define MAXITER 50000 + +static pthread_mutex_t mutex; +static pthread_mutexattr_t mutex_attr; +static pthread_cond_t cond; +static pthread_t threads[THREADS_NUM]; +static int pending = 0; + +typedef void * (*threadfunc) (void *); + +void * +thread_fun_timed (void *arg) +{ + int *ret = arg; + int rv, i; + + printf ("Started thread_fun_timed[%d]\n", *ret); + + for (i = 0; i < MAXITER / THREADS_NUM; i++) + { + rv = pthread_mutex_lock (&mutex); + if (rv) + { + printf ("pthread_mutex_lock: %s(%d)\n", strerror (rv), rv); + *ret = 1; + goto out; + } + + while (!pending) + { + struct timespec ts; + clock_gettime(CLOCK_REALTIME, &ts); + ts.tv_sec += 20; + rv = pthread_cond_timedwait (&cond, &mutex, &ts); + + /* There should be no timeout either. */ + if (rv) + { + printf ("pthread_cond_wait: %s(%d)\n", strerror (rv), rv); + *ret = 1; + goto out; + } + } + + pending--; + + rv = pthread_mutex_unlock (&mutex); + if (rv) + { + printf ("pthread_mutex_unlock: %s(%d)\n", strerror (rv), rv); + *ret = 1; + goto out; + } + } + + *ret = 0; + +out: + return ret; +} + +void * +thread_fun (void *arg) +{ + int *ret = arg; + int rv, i; + + printf ("Started thread_fun[%d]\n", *ret); + + for (i = 0; i < MAXITER / THREADS_NUM; i++) + { + rv = pthread_mutex_lock (&mutex); + if (rv) + { + printf ("pthread_mutex_lock: %s(%d)\n", strerror (rv), rv); + *ret = 1; + goto out; + } + + while (!pending) + { + rv = pthread_cond_wait (&cond, &mutex); + + if (rv) + { + printf ("pthread_cond_wait: %s(%d)\n", strerror (rv), rv); + *ret = 1; + goto out; + } + } + + pending--; + + rv = pthread_mutex_unlock (&mutex); + if (rv) + { + printf ("pthread_mutex_unlock: %s(%d)\n", strerror (rv), rv); + *ret = 1; + goto out; + } + } + + *ret = 0; + +out: + return ret; +} + +static int +do_test_wait (threadfunc f) +{ + int i; + int rv; + int counter = 0; + int retval[THREADS_NUM]; + + puts ("Starting test"); + + rv = pthread_mutexattr_init (&mutex_attr); + if (rv) + { + printf ("pthread_mutexattr_init: %s(%d)\n", strerror (rv), rv); + return 1; + } + + rv = pthread_mutexattr_setprotocol (&mutex_attr, PTHREAD_PRIO_INHERIT); + if (rv) + { + printf ("pthread_mutexattr_setprotocol: %s(%d)\n", strerror (rv), rv); + return 1; + } + + rv = pthread_mutex_init (&mutex, &mutex_attr); + if (rv) + { + printf ("pthread_mutex_init: %s(%d)\n", strerror (rv), rv); + return 1; + } + + rv = pthread_cond_init (&cond, NULL); + if (rv) + { + printf ("pthread_cond_init: %s(%d)\n", strerror (rv), rv); + return 1; + } + + for (i = 0; i < THREADS_NUM; i++) + { + retval[i] = i; + rv = pthread_create (&threads[i], NULL, f, &retval[i]); + if (rv) + { + printf ("pthread_create: %s(%d)\n", strerror (rv), rv); + return 1; + } + } + + for (; counter < MAXITER; counter++) + { + rv = pthread_mutex_lock (&mutex); + if (rv) + { + printf ("pthread_mutex_lock: %s(%d)\n", strerror (rv), rv); + return 1; + } + + if (!(counter % 100)) + printf ("counter: %d\n", counter); + pending += 1; + + rv = pthread_cond_signal (&cond); + if (rv) + { + printf ("pthread_cond_signal: %s(%d)\n", strerror (rv), rv); + return 1; + } + + rv = pthread_mutex_unlock (&mutex); + if (rv) + { + printf ("pthread_mutex_unlock: %s(%d)\n", strerror (rv), rv); + return 1; + } + } + + for (i = 0; i < THREADS_NUM; i++) + { + void *ret; + rv = pthread_join (threads[i], &ret); + if (rv) + { + printf ("pthread_join: %s(%d)\n", strerror (rv), rv); + return 1; + } + if (ret && *(int *)ret) + { + printf ("Thread %d returned with an error\n", i); + return 1; + } + } + + return 0; +} + +static int +do_test (void) +{ + puts ("Testing pthread_cond_wait"); + int ret = do_test_wait (thread_fun); + if (ret) + return ret; + + puts ("Testing pthread_cond_timedwait"); + return do_test_wait (thread_fun_timed); +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/sysdeps/pthread/tst-cond25.c b/sysdeps/pthread/tst-cond25.c new file mode 100644 index 0000000000..72954f893c --- /dev/null +++ b/sysdeps/pthread/tst-cond25.c @@ -0,0 +1,288 @@ +/* Verify that condition variables synchronized by PI mutexes don't hang on + on cancellation. + Copyright (C) 2012-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 <stdint.h> +#include <string.h> +#include <errno.h> +#include <sys/types.h> +#include <sys/syscall.h> +#include <unistd.h> +#include <sys/time.h> +#include <time.h> + +#define NUM 5 +#define ITERS 10000 +#define COUNT 100 + +typedef void *(*thr_func) (void *); + +pthread_mutex_t mutex; +pthread_cond_t cond; + +void cleanup (void *u) +{ + /* pthread_cond_wait should always return with the mutex locked. The + pthread_mutex_unlock implementation does not actually check whether we + own the mutex for several mutex kinds, so check this explicitly. */ + int ret = pthread_mutex_trylock (&mutex); + if (ret != EDEADLK && ret != EBUSY) + { + printf ("mutex not locked in cleanup %d\n", ret); + abort (); + } + if (pthread_mutex_unlock (&mutex)) + abort (); +} + +void * +signaller (void *u) +{ + int i, ret = 0; + void *tret = NULL; + + for (i = 0; i < ITERS; i++) + { + if ((ret = pthread_mutex_lock (&mutex)) != 0) + { + tret = (void *)1; + printf ("signaller:mutex_lock failed: %s\n", strerror (ret)); + goto out; + } + if ((ret = pthread_cond_signal (&cond)) != 0) + { + tret = (void *)1; + printf ("signaller:signal failed: %s\n", strerror (ret)); + goto unlock_out; + } + if ((ret = pthread_mutex_unlock (&mutex)) != 0) + { + tret = (void *)1; + printf ("signaller:mutex_unlock failed: %s\n", strerror (ret)); + goto out; + } + pthread_testcancel (); + } + +out: + return tret; + +unlock_out: + if ((ret = pthread_mutex_unlock (&mutex)) != 0) + printf ("signaller:mutex_unlock[2] failed: %s\n", strerror (ret)); + goto out; +} + +void * +waiter (void *u) +{ + int i, ret = 0; + void *tret = NULL; + int seq = (uintptr_t) u; + + for (i = 0; i < ITERS / NUM; i++) + { + if ((ret = pthread_mutex_lock (&mutex)) != 0) + { + tret = (void *) (uintptr_t) 1; + printf ("waiter[%u]:mutex_lock failed: %s\n", seq, strerror (ret)); + goto out; + } + pthread_cleanup_push (cleanup, NULL); + + if ((ret = pthread_cond_wait (&cond, &mutex)) != 0) + { + tret = (void *) (uintptr_t) 1; + printf ("waiter[%u]:wait failed: %s\n", seq, strerror (ret)); + goto unlock_out; + } + + if ((ret = pthread_mutex_unlock (&mutex)) != 0) + { + tret = (void *) (uintptr_t) 1; + printf ("waiter[%u]:mutex_unlock failed: %s\n", seq, strerror (ret)); + goto out; + } + pthread_cleanup_pop (0); + } + +out: + puts ("waiter tests done"); + return tret; + +unlock_out: + if ((ret = pthread_mutex_unlock (&mutex)) != 0) + printf ("waiter:mutex_unlock[2] failed: %s\n", strerror (ret)); + goto out; +} + +void * +timed_waiter (void *u) +{ + int i, ret; + void *tret = NULL; + int seq = (uintptr_t) u; + + for (i = 0; i < ITERS / NUM; i++) + { + struct timespec ts; + + if ((ret = clock_gettime(CLOCK_REALTIME, &ts)) != 0) + { + tret = (void *) (uintptr_t) 1; + printf ("%u:clock_gettime failed: %s\n", seq, strerror (errno)); + goto out; + } + ts.tv_sec += 20; + + if ((ret = pthread_mutex_lock (&mutex)) != 0) + { + tret = (void *) (uintptr_t) 1; + printf ("waiter[%u]:mutex_lock failed: %s\n", seq, strerror (ret)); + goto out; + } + pthread_cleanup_push (cleanup, NULL); + + /* We should not time out either. */ + if ((ret = pthread_cond_timedwait (&cond, &mutex, &ts)) != 0) + { + tret = (void *) (uintptr_t) 1; + printf ("waiter[%u]:timedwait failed: %s\n", seq, strerror (ret)); + goto unlock_out; + } + if ((ret = pthread_mutex_unlock (&mutex)) != 0) + { + tret = (void *) (uintptr_t) 1; + printf ("waiter[%u]:mutex_unlock failed: %s\n", seq, strerror (ret)); + goto out; + } + pthread_cleanup_pop (0); + } + +out: + puts ("timed_waiter tests done"); + return tret; + +unlock_out: + if ((ret = pthread_mutex_unlock (&mutex)) != 0) + printf ("waiter[%u]:mutex_unlock[2] failed: %s\n", seq, strerror (ret)); + goto out; +} + +int +do_test_wait (thr_func f) +{ + pthread_t w[NUM]; + pthread_t s; + pthread_mutexattr_t attr; + int i, j, ret = 0; + void *thr_ret; + + for (i = 0; i < COUNT; i++) + { + if ((ret = pthread_mutexattr_init (&attr)) != 0) + { + printf ("mutexattr_init failed: %s\n", strerror (ret)); + goto out; + } + + if ((ret = pthread_mutexattr_setprotocol (&attr, + PTHREAD_PRIO_INHERIT)) != 0) + { + printf ("mutexattr_setprotocol failed: %s\n", strerror (ret)); + goto out; + } + + if ((ret = pthread_cond_init (&cond, NULL)) != 0) + { + printf ("cond_init failed: %s\n", strerror (ret)); + goto out; + } + + if ((ret = pthread_mutex_init (&mutex, &attr)) != 0) + { + printf ("mutex_init failed: %s\n", strerror (ret)); + goto out; + } + + for (j = 0; j < NUM; j++) + if ((ret = pthread_create (&w[j], NULL, + f, (void *) (uintptr_t) j)) != 0) + { + printf ("waiter[%d]: create failed: %s\n", j, strerror (ret)); + goto out; + } + + if ((ret = pthread_create (&s, NULL, signaller, NULL)) != 0) + { + printf ("signaller: create failed: %s\n", strerror (ret)); + goto out; + } + + for (j = 0; j < NUM; j++) + { + pthread_cancel (w[j]); + + if ((ret = pthread_join (w[j], &thr_ret)) != 0) + { + printf ("waiter[%d]: join failed: %s\n", j, strerror (ret)); + goto out; + } + + if (thr_ret != NULL && thr_ret != PTHREAD_CANCELED) + { + ret = 1; + goto out; + } + } + + /* The signalling thread could have ended before it was cancelled. */ + pthread_cancel (s); + + if ((ret = pthread_join (s, &thr_ret)) != 0) + { + printf ("signaller: join failed: %s\n", strerror (ret)); + goto out; + } + + if (thr_ret != NULL && thr_ret != PTHREAD_CANCELED) + { + ret = 1; + goto out; + } + } + +out: + return ret; +} + +int +do_test (int argc, char **argv) +{ + int ret = do_test_wait (waiter); + + if (ret) + return ret; + + return do_test_wait (timed_waiter); +} + +#include "../test-skeleton.c" diff --git a/sysdeps/pthread/tst-cond26.c b/sysdeps/pthread/tst-cond26.c new file mode 100644 index 0000000000..e647da00c2 --- /dev/null +++ b/sysdeps/pthread/tst-cond26.c @@ -0,0 +1,77 @@ +/* Test unsupported/bad clocks passed to pthread_cond_clockwait. + + Copyright (C) 2019-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 <errno.h> +#include <pthread.h> +#include <stdio.h> +#include <time.h> +#include <unistd.h> +#include <support/check.h> +#include <support/timespec.h> +#include <support/xthread.h> + +static pthread_cond_t cond = PTHREAD_COND_INITIALIZER; +static pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER; + +#define NOT_A_VALID_CLOCK 123456 + +static int +do_test (void) +{ + xpthread_mutex_lock (&mut); + + const struct timespec ts = make_timespec (0, 0); + + /* These clocks are meaningless to sem_clockwait. */ +#if defined(CLOCK_PROCESS_CPUTIME_ID) + TEST_COMPARE (pthread_cond_clockwait (&cond, &mut, + CLOCK_PROCESS_CPUTIME_ID, &ts), EINVAL); +#endif +#if defined(CLOCK_THREAD_CPUTIME_ID) + TEST_COMPARE (pthread_cond_clockwait (&cond, &mut, + CLOCK_THREAD_CPUTIME_ID, &ts), EINVAL); +#endif + + /* These clocks might be meaningful, but are currently unsupported + by pthread_cond_clockwait. */ +#if defined(CLOCK_REALTIME_COARSE) + TEST_COMPARE (pthread_cond_clockwait (&cond, &mut, + CLOCK_REALTIME_COARSE, &ts), EINVAL); +#endif +#if defined(CLOCK_MONOTONIC_RAW) + TEST_COMPARE (pthread_cond_clockwait (&cond, &mut, + CLOCK_MONOTONIC_RAW, &ts), EINVAL); +#endif +#if defined(CLOCK_MONOTONIC_COARSE) + TEST_COMPARE (pthread_cond_clockwait (&cond, &mut, + CLOCK_MONOTONIC_COARSE, &ts), EINVAL); +#endif +#if defined(CLOCK_BOOTTIME) + TEST_COMPARE (pthread_cond_clockwait (&cond, &mut, + CLOCK_BOOTTIME, &ts), EINVAL); +#endif + + /* This is a completely invalid clock. */ + TEST_COMPARE (pthread_cond_clockwait (&cond, &mut, + NOT_A_VALID_CLOCK, &ts), EINVAL); + + return 0; +} + +#include <support/test-driver.c> diff --git a/sysdeps/pthread/tst-cond27.c b/sysdeps/pthread/tst-cond27.c new file mode 100644 index 0000000000..c8142abf9e --- /dev/null +++ b/sysdeps/pthread/tst-cond27.c @@ -0,0 +1,66 @@ +/* Test pthread_cond_clockwait timeout. + + Copyright (C) 2019-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 <errno.h> +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> +#include <sys/time.h> +#include <support/check.h> +#include <support/timespec.h> +#include <support/xthread.h> + + +static pthread_mutex_t mut = PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP; +static pthread_cond_t cond = PTHREAD_COND_INITIALIZER; + + +static int +do_test_clock (clockid_t clockid) +{ + /* Get the mutex. */ + xpthread_mutex_lock (&mut); + + /* Waiting for the condition will fail. But we want the timeout here. */ + const struct timespec ts_now = xclock_now (clockid); + const struct timespec ts_timeout = + timespec_add (ts_now, make_timespec (0, 500000000)); + + /* In theory pthread_cond_clockwait could return zero here due to + spurious wakeup. However that can't happen without a signal or an + additional waiter. */ + TEST_COMPARE (pthread_cond_clockwait (&cond, &mut, clockid, &ts_timeout), + ETIMEDOUT); + + xpthread_mutex_unlock (&mut); + + return 0; +} + +static int +do_test (void) +{ + do_test_clock (CLOCK_MONOTONIC); + do_test_clock (CLOCK_REALTIME); + return 0; +} + +#include <support/test-driver.c> diff --git a/sysdeps/pthread/tst-cond3.c b/sysdeps/pthread/tst-cond3.c new file mode 100644 index 0000000000..fb4209d0bb --- /dev/null +++ b/sysdeps/pthread/tst-cond3.c @@ -0,0 +1,111 @@ +/* Copyright (C) 2002-2020 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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 <unistd.h> + +static int do_test (void); + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" + +/* Note that this test requires more than the standard. It is + required that there are no spurious wakeups if only more readers + are added. This is a reasonable demand. */ + + +static pthread_cond_t cond = PTHREAD_COND_INITIALIZER; +static pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER; + + +#define N 10 + + +static void * +tf (void *arg) +{ + int i = (long int) arg; + int err; + + /* Get the mutex. */ + err = pthread_mutex_lock (&mut); + if (err != 0) + { + printf ("child %d mutex_lock failed: %s\n", i, strerror (err)); + exit (1); + } + + /* This call should never return. */ + xpthread_cond_wait (&cond, &mut); + puts ("error: pthread_cond_wait in tf returned"); + + /* We should never get here. */ + exit (1); + + return NULL; +} + + +static int +do_test (void) +{ + int err; + int i; + + for (i = 0; i < N; ++i) + { + pthread_t th; + + if (i != 0) + { + /* Release the mutex. */ + err = pthread_mutex_unlock (&mut); + if (err != 0) + { + printf ("mutex_unlock %d failed: %s\n", i, strerror (err)); + return 1; + } + } + + err = pthread_create (&th, NULL, tf, (void *) (long int) i); + if (err != 0) + { + printf ("create %d failed: %s\n", i, strerror (err)); + return 1; + } + + /* Get the mutex. */ + err = pthread_mutex_lock (&mut); + if (err != 0) + { + printf ("mutex_lock %d failed: %s\n", i, strerror (err)); + return 1; + } + } + + delayed_exit (1); + + /* This call should never return. */ + xpthread_cond_wait (&cond, &mut); + + puts ("error: pthread_cond_wait in do_test returned"); + return 1; +} diff --git a/sysdeps/pthread/tst-cond4.c b/sysdeps/pthread/tst-cond4.c new file mode 100644 index 0000000000..4d4bad3a76 --- /dev/null +++ b/sysdeps/pthread/tst-cond4.c @@ -0,0 +1,263 @@ +/* Copyright (C) 2002-2020 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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 <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <sys/mman.h> +#include <sys/wait.h> + + +int *condition; + +static int +do_test (void) +{ + size_t ps = sysconf (_SC_PAGESIZE); + char tmpfname[] = "/tmp/tst-cond4.XXXXXX"; + char data[ps]; + void *mem; + int fd; + pthread_mutexattr_t ma; + pthread_mutex_t *mut1; + pthread_mutex_t *mut2; + pthread_condattr_t ca; + pthread_cond_t *cond; + pid_t pid; + int result = 0; + int p; + + fd = mkstemp (tmpfname); + if (fd == -1) + { + printf ("cannot open temporary file: %m\n"); + return 1; + } + + /* Make sure it is always removed. */ + unlink (tmpfname); + + /* Create one page of data. */ + memset (data, '\0', ps); + + /* Write the data to the file. */ + if (write (fd, data, ps) != (ssize_t) ps) + { + puts ("short write"); + return 1; + } + + mem = mmap (NULL, ps, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + if (mem == MAP_FAILED) + { + printf ("mmap failed: %m\n"); + return 1; + } + + mut1 = (pthread_mutex_t *) (((uintptr_t) mem + + __alignof (pthread_mutex_t)) + & ~(__alignof (pthread_mutex_t) - 1)); + mut2 = mut1 + 1; + + cond = (pthread_cond_t *) (((uintptr_t) (mut2 + 1) + + __alignof (pthread_cond_t)) + & ~(__alignof (pthread_cond_t) - 1)); + + condition = (int *) (((uintptr_t) (cond + 1) + __alignof (int)) + & ~(__alignof (int) - 1)); + + if (pthread_mutexattr_init (&ma) != 0) + { + puts ("mutexattr_init failed"); + return 1; + } + + if (pthread_mutexattr_getpshared (&ma, &p) != 0) + { + puts ("1st mutexattr_getpshared failed"); + return 1; + } + + if (p != PTHREAD_PROCESS_PRIVATE) + { + puts ("default pshared value wrong"); + return 1; + } + + if (pthread_mutexattr_setpshared (&ma, PTHREAD_PROCESS_SHARED) != 0) + { + puts ("mutexattr_setpshared failed"); + return 1; + } + + if (pthread_mutexattr_getpshared (&ma, &p) != 0) + { + puts ("2nd mutexattr_getpshared failed"); + return 1; + } + + if (p != PTHREAD_PROCESS_SHARED) + { + puts ("pshared value after setpshared call wrong"); + return 1; + } + + if (pthread_mutex_init (mut1, &ma) != 0) + { + puts ("1st mutex_init failed"); + return 1; + } + + if (pthread_mutex_init (mut2, &ma) != 0) + { + puts ("2nd mutex_init failed"); + return 1; + } + + if (pthread_condattr_init (&ca) != 0) + { + puts ("condattr_init failed"); + return 1; + } + + if (pthread_condattr_getpshared (&ca, &p) != 0) + { + puts ("1st condattr_getpshared failed"); + return 1; + } + + if (p != PTHREAD_PROCESS_PRIVATE) + { + puts ("default value for pshared in condattr wrong"); + return 1; + } + + if (pthread_condattr_setpshared (&ca, PTHREAD_PROCESS_SHARED) != 0) + { + puts ("condattr_setpshared failed"); + return 1; + } + + if (pthread_condattr_getpshared (&ca, &p) != 0) + { + puts ("2nd condattr_getpshared failed"); + return 1; + } + + if (p != PTHREAD_PROCESS_SHARED) + { + puts ("pshared condattr still not set"); + return 1; + } + + if (pthread_cond_init (cond, &ca) != 0) + { + puts ("cond_init failed"); + return 1; + } + + if (pthread_mutex_lock (mut1) != 0) + { + puts ("parent: 1st mutex_lock failed"); + return 1; + } + + puts ("going to fork now"); + pid = fork (); + if (pid == -1) + { + puts ("fork failed"); + return 1; + } + else if (pid == 0) + { + if (pthread_mutex_lock (mut2) != 0) + { + puts ("child: mutex_lock failed"); + return 1; + } + + if (pthread_mutex_unlock (mut1) != 0) + { + puts ("child: 1st mutex_unlock failed"); + return 1; + } + + do + if (pthread_cond_wait (cond, mut2) != 0) + { + puts ("child: cond_wait failed"); + return 1; + } + while (*condition == 0); + + if (pthread_mutex_unlock (mut2) != 0) + { + puts ("child: 2nd mutex_unlock failed"); + return 1; + } + + puts ("child done"); + } + else + { + int status; + + if (pthread_mutex_lock (mut1) != 0) + { + puts ("parent: 2nd mutex_lock failed"); + return 1; + } + + if (pthread_mutex_lock (mut2) != 0) + { + puts ("parent: 3rd mutex_lock failed"); + return 1; + } + + if (pthread_cond_signal (cond) != 0) + { + puts ("parent: cond_signal failed"); + return 1; + } + + *condition = 1; + + if (pthread_mutex_unlock (mut2) != 0) + { + puts ("parent: mutex_unlock failed"); + return 1; + } + + puts ("waiting for child"); + + waitpid (pid, &status, 0); + result |= status; + + puts ("parent done"); + } + + return result; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/sysdeps/pthread/tst-cond5.c b/sysdeps/pthread/tst-cond5.c new file mode 100644 index 0000000000..e2ea541c46 --- /dev/null +++ b/sysdeps/pthread/tst-cond5.c @@ -0,0 +1,105 @@ +/* Copyright (C) 2002-2020 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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> +#include <string.h> +#include <time.h> +#include <sys/time.h> + + +static pthread_mutex_t mut; +static pthread_cond_t cond = PTHREAD_COND_INITIALIZER; + + +static int +do_test (void) +{ + pthread_mutexattr_t ma; + int err; + struct timespec ts; + struct timeval tv; + + if (pthread_mutexattr_init (&ma) != 0) + { + puts ("mutexattr_init failed"); + exit (1); + } + + if (pthread_mutexattr_settype (&ma, PTHREAD_MUTEX_ERRORCHECK) != 0) + { + puts ("mutexattr_settype failed"); + exit (1); + } + + if (pthread_mutex_init (&mut, &ma) != 0) + { + puts ("mutex_init failed"); + exit (1); + } + + /* Get the mutex. */ + if (pthread_mutex_lock (&mut) != 0) + { + puts ("mutex_lock failed"); + exit (1); + } + + /* Waiting for the condition will fail. But we want the timeout here. */ + if (gettimeofday (&tv, NULL) != 0) + { + puts ("gettimeofday failed"); + exit (1); + } + + TIMEVAL_TO_TIMESPEC (&tv, &ts); + ts.tv_nsec += 500000000; + if (ts.tv_nsec >= 1000000000) + { + ts.tv_nsec -= 1000000000; + ++ts.tv_sec; + } + err = pthread_cond_timedwait (&cond, &mut, &ts); + if (err == 0) + { + /* This could in theory happen but here without any signal and + additional waiter it should not. */ + puts ("cond_timedwait succeeded"); + exit (1); + } + else if (err != ETIMEDOUT) + { + printf ("cond_timedwait returned with %s\n", strerror (err)); + exit (1); + } + + err = pthread_mutex_unlock (&mut); + if (err != 0) + { + printf ("mutex_unlock failed: %s\n", strerror (err)); + exit (1); + } + + return 0; +} + + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/sysdeps/pthread/tst-cond6.c b/sysdeps/pthread/tst-cond6.c new file mode 100644 index 0000000000..0c9426d0d7 --- /dev/null +++ b/sysdeps/pthread/tst-cond6.c @@ -0,0 +1,233 @@ +/* Copyright (C) 2002-2020 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2002. + + 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 <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> +#include <unistd.h> +#include <sys/mman.h> +#include <sys/time.h> +#include <sys/wait.h> + + +int *condition; + +static int +do_test (void) +{ + size_t ps = sysconf (_SC_PAGESIZE); + char tmpfname[] = "/tmp/tst-cond6.XXXXXX"; + char data[ps]; + void *mem; + int fd; + pthread_mutexattr_t ma; + pthread_mutex_t *mut1; + pthread_mutex_t *mut2; + pthread_condattr_t ca; + pthread_cond_t *cond; + pid_t pid; + int result = 0; + + fd = mkstemp (tmpfname); + if (fd == -1) + { + printf ("cannot open temporary file: %m\n"); + exit (1); + } + + /* Make sure it is always removed. */ + unlink (tmpfname); + + /* Create one page of data. */ + memset (data, '\0', ps); + + /* Write the data to the file. */ + if (write (fd, data, ps) != (ssize_t) ps) + { + puts ("short write"); + exit (1); + } + + mem = mmap (NULL, ps, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + if (mem == MAP_FAILED) + { + printf ("mmap failed: %m\n"); + exit (1); + } + + mut1 = (pthread_mutex_t *) (((uintptr_t) mem + + __alignof (pthread_mutex_t)) + & ~(__alignof (pthread_mutex_t) - 1)); + mut2 = mut1 + 1; + + cond = (pthread_cond_t *) (((uintptr_t) (mut2 + 1) + + __alignof (pthread_cond_t)) + & ~(__alignof (pthread_cond_t) - 1)); + + condition = (int *) (((uintptr_t) (cond + 1) + __alignof (int)) + & ~(__alignof (int) - 1)); + + if (pthread_mutexattr_init (&ma) != 0) + { + puts ("mutexattr_init failed"); + exit (1); + } + + if (pthread_mutexattr_setpshared (&ma, PTHREAD_PROCESS_SHARED) != 0) + { + puts ("mutexattr_setpshared failed"); + exit (1); + } + + if (pthread_mutex_init (mut1, &ma) != 0) + { + puts ("1st mutex_init failed"); + exit (1); + } + + if (pthread_mutex_init (mut2, &ma) != 0) + { + puts ("2nd mutex_init failed"); + exit (1); + } + + if (pthread_condattr_init (&ca) != 0) + { + puts ("condattr_init failed"); + exit (1); + } + + if (pthread_condattr_setpshared (&ca, PTHREAD_PROCESS_SHARED) != 0) + { + puts ("condattr_setpshared failed"); + exit (1); + } + + if (pthread_cond_init (cond, &ca) != 0) + { + puts ("cond_init failed"); + exit (1); + } + + if (pthread_mutex_lock (mut1) != 0) + { + puts ("parent: 1st mutex_lock failed"); + exit (1); + } + + puts ("going to fork now"); + pid = fork (); + if (pid == -1) + { + puts ("fork failed"); + exit (1); + } + else if (pid == 0) + { + struct timespec ts; + struct timeval tv; + + if (pthread_mutex_lock (mut2) != 0) + { + puts ("child: mutex_lock failed"); + exit (1); + } + + if (pthread_mutex_unlock (mut1) != 0) + { + puts ("child: 1st mutex_unlock failed"); + exit (1); + } + + if (gettimeofday (&tv, NULL) != 0) + { + puts ("gettimeofday failed"); + exit (1); + } + + TIMEVAL_TO_TIMESPEC (&tv, &ts); + ts.tv_nsec += 500000000; + if (ts.tv_nsec >= 1000000000) + { + ts.tv_nsec -= 1000000000; + ++ts.tv_sec; + } + + do + if (pthread_cond_timedwait (cond, mut2, &ts) != 0) + { + puts ("child: cond_wait failed"); + exit (1); + } + while (*condition == 0); + + if (pthread_mutex_unlock (mut2) != 0) + { + puts ("child: 2nd mutex_unlock failed"); + exit (1); + } + + puts ("child done"); + } + else + { + int status; + + if (pthread_mutex_lock (mut1) != 0) + { + puts ("parent: 2nd mutex_lock failed"); + exit (1); + } + + if (pthread_mutex_lock (mut2) != 0) + { + puts ("parent: 3rd mutex_lock failed"); + exit (1); + } + + if (pthread_cond_signal (cond) != 0) + { + puts ("parent: cond_signal failed"); + exit (1); + } + + *condition = 1; + + if (pthread_mutex_unlock (mut2) != 0) + { + puts ("parent: mutex_unlock failed"); + exit (1); + } + + puts ("waiting for child"); + + waitpid (pid, &status, 0); + result |= status; + + puts ("parent done"); + } + + return result; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/sysdeps/pthread/tst-cond7.c b/sysdeps/pthread/tst-cond7.c new file mode 100644 index 0000000000..48502bd720 --- /dev/null +++ b/sysdeps/pthread/tst-cond7.c @@ -0,0 +1,167 @@ +/* Copyright (C) 2003-2020 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Jakub Jelinek <jakub@redhat.com>, 2003. + + 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> +#include <string.h> +#include <time.h> +#include <sys/time.h> + + +typedef struct + { + pthread_cond_t cond; + pthread_mutex_t lock; + pthread_t h; + } T; + + +static volatile bool done; + + +static void * +tf (void *arg) +{ + puts ("child created"); + + if (pthread_setcancelstate (PTHREAD_CANCEL_ENABLE, NULL) != 0 + || pthread_setcanceltype (PTHREAD_CANCEL_DEFERRED, NULL) != 0) + { + puts ("cannot set cancellation options"); + exit (1); + } + + T *t = (T *) arg; + + if (pthread_mutex_lock (&t->lock) != 0) + { + puts ("child: lock failed"); + exit (1); + } + + done = true; + + if (pthread_cond_signal (&t->cond) != 0) + { + puts ("child: cond_signal failed"); + exit (1); + } + + if (pthread_cond_wait (&t->cond, &t->lock) != 0) + { + puts ("child: cond_wait failed"); + exit (1); + } + + if (pthread_mutex_unlock (&t->lock) != 0) + { + puts ("child: unlock failed"); + exit (1); + } + + return NULL; +} + + +static int +do_test (void) +{ + int i; +#define N 100 + T *t[N]; + for (i = 0; i < N; ++i) + { + printf ("round %d\n", i); + + t[i] = (T *) malloc (sizeof (T)); + if (t[i] == NULL) + { + puts ("out of memory"); + exit (1); + } + + if (pthread_mutex_init (&t[i]->lock, NULL) != 0 + || pthread_cond_init (&t[i]->cond, NULL) != 0) + { + puts ("an _init function failed"); + exit (1); + } + + if (pthread_mutex_lock (&t[i]->lock) != 0) + { + puts ("initial mutex_lock failed"); + exit (1); + } + + done = false; + + if (pthread_create (&t[i]->h, NULL, tf, t[i]) != 0) + { + puts ("pthread_create failed"); + exit (1); + } + + do + if (pthread_cond_wait (&t[i]->cond, &t[i]->lock) != 0) + { + puts ("cond_wait failed"); + exit (1); + } + while (! done); + + /* Release the lock since the cancel handler will get it. */ + if (pthread_mutex_unlock (&t[i]->lock) != 0) + { + puts ("mutex_unlock failed"); + exit (1); + } + + if (pthread_cancel (t[i]->h) != 0) + { + puts ("cancel failed"); + exit (1); + } + + puts ("parent: joining now"); + + void *result; + if (pthread_join (t[i]->h, &result) != 0) + { + puts ("join failed"); + exit (1); + } + + if (result != PTHREAD_CANCELED) + { + puts ("result != PTHREAD_CANCELED"); + exit (1); + } + } + + for (i = 0; i < N; ++i) + free (t[i]); + + return 0; +} + + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/sysdeps/pthread/tst-cond8-static.c b/sysdeps/pthread/tst-cond8-static.c new file mode 100644 index 0000000000..fed35db60d --- /dev/null +++ b/sysdeps/pthread/tst-cond8-static.c @@ -0,0 +1 @@ +#include "tst-cond8.c" diff --git a/sysdeps/pthread/tst-cond8.c b/sysdeps/pthread/tst-cond8.c new file mode 100644 index 0000000000..61f7583844 --- /dev/null +++ b/sysdeps/pthread/tst-cond8.c @@ -0,0 +1,276 @@ +/* Copyright (C) 2003-2020 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + + 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> +#include <time.h> +#include <sys/time.h> + + +static pthread_cond_t cond = PTHREAD_COND_INITIALIZER; +static pthread_mutex_t mut = PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP; + +static pthread_barrier_t bar; + + +static void +ch (void *arg) +{ + int e = pthread_mutex_lock (&mut); + if (e == 0) + { + puts ("mutex not locked at all by cond_wait"); + exit (1); + } + + if (e != EDEADLK) + { + puts ("no deadlock error signaled"); + exit (1); + } + + if (pthread_mutex_unlock (&mut) != 0) + { + puts ("ch: cannot unlock mutex"); + exit (1); + } + + puts ("ch done"); +} + + +static void * +tf1 (void *p) +{ + int err; + + if (pthread_setcancelstate (PTHREAD_CANCEL_ENABLE, NULL) != 0 + || pthread_setcanceltype (PTHREAD_CANCEL_DEFERRED, NULL) != 0) + { + puts ("cannot set cancellation options"); + exit (1); + } + + err = pthread_mutex_lock (&mut); + if (err != 0) + { + puts ("child: cannot get mutex"); + exit (1); + } + + err = pthread_barrier_wait (&bar); + if (err != 0 && err != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("barrier_wait returned %d\n", err); + exit (1); + } + + puts ("child: got mutex; waiting"); + + pthread_cleanup_push (ch, NULL); + + pthread_cond_wait (&cond, &mut); + + pthread_cleanup_pop (0); + + puts ("child: cond_wait should not have returned"); + + return NULL; +} + + +static void * +tf2 (void *p) +{ + int err; + + if (pthread_setcancelstate (PTHREAD_CANCEL_ENABLE, NULL) != 0 + || pthread_setcanceltype (PTHREAD_CANCEL_DEFERRED, NULL) != 0) + { + puts ("cannot set cancellation options"); + exit (1); + } + + err = pthread_mutex_lock (&mut); + if (err != 0) + { + puts ("child: cannot get mutex"); + exit (1); + } + + err = pthread_barrier_wait (&bar); + if (err != 0 && err != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("barrier_wait returned %d\n", err); + exit (1); + } + + puts ("child: got mutex; waiting"); + + pthread_cleanup_push (ch, NULL); + + /* Current time. */ + struct timeval tv; + (void) gettimeofday (&tv, NULL); + /* +1000 seconds in correct format. */ + struct timespec ts; + TIMEVAL_TO_TIMESPEC (&tv, &ts); + ts.tv_sec += 1000; + + pthread_cond_timedwait (&cond, &mut, &ts); + + pthread_cleanup_pop (0); + + puts ("child: cond_wait should not have returned"); + + return NULL; +} + + +static int +do_test (void) +{ + pthread_t th; + int err; + + printf ("&cond = %p\n&mut = %p\n", &cond, &mut); + + puts ("parent: get mutex"); + + err = pthread_barrier_init (&bar, NULL, 2); + if (err != 0) + { + puts ("parent: cannot init barrier"); + exit (1); + } + + puts ("parent: create child"); + + err = pthread_create (&th, NULL, tf1, NULL); + if (err != 0) + { + puts ("parent: cannot create thread"); + exit (1); + } + + puts ("parent: wait for child to lock mutex"); + + err = pthread_barrier_wait (&bar); + if (err != 0 && err != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("parent: cannot wait for barrier"); + exit (1); + } + + err = pthread_mutex_lock (&mut); + if (err != 0) + { + puts ("parent: mutex_lock failed"); + exit (1); + } + + err = pthread_mutex_unlock (&mut); + if (err != 0) + { + puts ("parent: mutex_unlock failed"); + exit (1); + } + + if (pthread_cancel (th) != 0) + { + puts ("cannot cancel thread"); + exit (1); + } + + void *r; + err = pthread_join (th, &r); + if (err != 0) + { + puts ("parent: failed to join"); + exit (1); + } + + if (r != PTHREAD_CANCELED) + { + puts ("child hasn't been canceled"); + exit (1); + } + + + + puts ("parent: create 2nd child"); + + err = pthread_create (&th, NULL, tf2, NULL); + if (err != 0) + { + puts ("parent: cannot create thread"); + exit (1); + } + + puts ("parent: wait for child to lock mutex"); + + err = pthread_barrier_wait (&bar); + if (err != 0 && err != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("parent: cannot wait for barrier"); + exit (1); + } + + err = pthread_mutex_lock (&mut); + if (err != 0) + { + puts ("parent: mutex_lock failed"); + exit (1); + } + + err = pthread_mutex_unlock (&mut); + if (err != 0) + { + puts ("parent: mutex_unlock failed"); + exit (1); + } + + if (pthread_cancel (th) != 0) + { + puts ("cannot cancel thread"); + exit (1); + } + + err = pthread_join (th, &r); + if (err != 0) + { + puts ("parent: failed to join"); + exit (1); + } + + if (r != PTHREAD_CANCELED) + { + puts ("child hasn't been canceled"); + exit (1); + } + + puts ("done"); + + return 0; +} + + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/sysdeps/pthread/tst-cond9.c b/sysdeps/pthread/tst-cond9.c new file mode 100644 index 0000000000..e83870d393 --- /dev/null +++ b/sysdeps/pthread/tst-cond9.c @@ -0,0 +1,149 @@ +/* Copyright (C) 2003-2020 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@redhat.com>, 2003. + + 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> +#include <time.h> +#include <sys/time.h> + + +static pthread_cond_t cond = PTHREAD_COND_INITIALIZER; +static pthread_mutex_t mut = PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP; + + +static void * +tf (void *arg) +{ + int err = pthread_cond_wait (&cond, &mut); + if (err == 0) + { + puts ("cond_wait did not fail"); + exit (1); + } + + if (err != EPERM) + { + printf ("cond_wait didn't return EPERM but %d\n", err); + exit (1); + } + + + /* Current time. */ + struct timeval tv; + (void) gettimeofday (&tv, NULL); + /* +1000 seconds in correct format. */ + struct timespec ts; + TIMEVAL_TO_TIMESPEC (&tv, &ts); + ts.tv_sec += 1000; + + err = pthread_cond_timedwait (&cond, &mut, &ts); + if (err == 0) + { + puts ("cond_timedwait did not fail"); + exit (1); + } + + if (err != EPERM) + { + printf ("cond_timedwait didn't return EPERM but %d\n", err); + exit (1); + } + + return (void *) 1l; +} + + +static int +do_test (void) +{ + pthread_t th; + int err; + + printf ("&cond = %p\n&mut = %p\n", &cond, &mut); + + err = pthread_cond_wait (&cond, &mut); + if (err == 0) + { + puts ("cond_wait did not fail"); + exit (1); + } + + if (err != EPERM) + { + printf ("cond_wait didn't return EPERM but %d\n", err); + exit (1); + } + + + /* Current time. */ + struct timeval tv; + (void) gettimeofday (&tv, NULL); + /* +1000 seconds in correct format. */ + struct timespec ts; + TIMEVAL_TO_TIMESPEC (&tv, &ts); + ts.tv_sec += 1000; + + err = pthread_cond_timedwait (&cond, &mut, &ts); + if (err == 0) + { + puts ("cond_timedwait did not fail"); + exit (1); + } + + if (err != EPERM) + { + printf ("cond_timedwait didn't return EPERM but %d\n", err); + exit (1); + } + + if (pthread_mutex_lock (&mut) != 0) + { + puts ("parent: mutex_lock failed"); + exit (1); + } + + puts ("creating thread"); + + if (pthread_create (&th, NULL, tf, NULL) != 0) + { + puts ("create failed"); + exit (1); + } + + void *r; + if (pthread_join (th, &r) != 0) + { + puts ("join failed"); + exit (1); + } + if (r != (void *) 1l) + { + puts ("thread has wrong return value"); + exit (1); + } + + puts ("done"); + + return 0; +} + + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" |