diff options
author | Samuel Thibault <samuel.thibault@ens-lyon.org> | 2020-02-09 23:14:35 +0000 |
---|---|---|
committer | Samuel Thibault <samuel.thibault@ens-lyon.org> | 2020-02-10 01:03:55 +0000 |
commit | 6acd77229adda7e772bf5783145500f6cd074fd3 (patch) | |
tree | 46d03d0aec8858ee9de87f6a16c46348dbcb2563 /sysdeps | |
parent | f3a7ff069f74e4d6a89aba5fb9bba74f38d249c7 (diff) | |
download | glibc-6acd77229adda7e772bf5783145500f6cd074fd3.tar.gz glibc-6acd77229adda7e772bf5783145500f6cd074fd3.tar.xz glibc-6acd77229adda7e772bf5783145500f6cd074fd3.zip |
pthread: Move most barrier tests from nptl to sysdeps/pthread
So they can be checked with htl too.
Diffstat (limited to 'sysdeps')
-rw-r--r-- | sysdeps/mach/hurd/i386/Makefile | 1 | ||||
-rw-r--r-- | sysdeps/pthread/Makefile | 1 | ||||
-rw-r--r-- | sysdeps/pthread/tst-barrier1.c | 71 | ||||
-rw-r--r-- | sysdeps/pthread/tst-barrier2.c | 185 | ||||
-rw-r--r-- | sysdeps/pthread/tst-barrier3.c | 152 | ||||
-rw-r--r-- | sysdeps/pthread/tst-barrier4.c | 121 |
6 files changed, 531 insertions, 0 deletions
diff --git a/sysdeps/mach/hurd/i386/Makefile b/sysdeps/mach/hurd/i386/Makefile index a5ccab0956..445724f85f 100644 --- a/sysdeps/mach/hurd/i386/Makefile +++ b/sysdeps/mach/hurd/i386/Makefile @@ -112,6 +112,7 @@ test-xfail-tst-cond23 = yes test-xfail-tst-rwlock4 = yes test-xfail-tst-rwlock12 = yes test-xfail-tst-sem3 = yes +test-xfail-tst-barrier2 = yes endif # For bug 25522 diff --git a/sysdeps/pthread/Makefile b/sysdeps/pthread/Makefile index 2f07c0cfe6..c102f45b6a 100644 --- a/sysdeps/pthread/Makefile +++ b/sysdeps/pthread/Makefile @@ -43,6 +43,7 @@ tests += tst-cnd-basic tst-mtx-trylock tst-cnd-broadcast \ tst-cnd-timedwait tst-thrd-detach tst-mtx-basic tst-thrd-sleep \ tst-mtx-recursive tst-tss-basic tst-call-once tst-mtx-timedlock \ tst-attr1 \ + tst-barrier1 tst-barrier2 tst-barrier3 tst-barrier4 \ 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 \ diff --git a/sysdeps/pthread/tst-barrier1.c b/sysdeps/pthread/tst-barrier1.c new file mode 100644 index 0000000000..d60f22f63d --- /dev/null +++ b/sysdeps/pthread/tst-barrier1.c @@ -0,0 +1,71 @@ +/* Tests barrier initialization. + 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> + + +static int +do_test (void) +{ + pthread_barrier_t b; + int e; + int cnt; + + e = pthread_barrier_init (&b, NULL, 0); + if (e == 0) + { + puts ("barrier_init with count 0 succeeded"); + return 1; + } + if (e != EINVAL) + { + puts ("barrier_init with count 0 didn't return EINVAL"); + return 1; + } + + if (pthread_barrier_init (&b, NULL, 1) != 0) + { + puts ("real barrier_init failed"); + return 1; + } + + for (cnt = 0; cnt < 10; ++cnt) + { + e = pthread_barrier_wait (&b); + + if (e != PTHREAD_BARRIER_SERIAL_THREAD) + { + puts ("barrier_wait didn't return PTHREAD_BARRIER_SERIAL_THREAD"); + return 1; + } + } + + if (pthread_barrier_destroy (&b) != 0) + { + puts ("barrier_destroy failed"); + return 1; + } + + return 0; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/sysdeps/pthread/tst-barrier2.c b/sysdeps/pthread/tst-barrier2.c new file mode 100644 index 0000000000..d32c632ae0 --- /dev/null +++ b/sysdeps/pthread/tst-barrier2.c @@ -0,0 +1,185 @@ +/* Tests process-shared barriers. + 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> + + +static int +do_test (void) +{ + size_t ps = sysconf (_SC_PAGESIZE); + char tmpfname[] = "/tmp/tst-barrier2.XXXXXX"; + char data[ps]; + void *mem; + int fd; + pthread_barrier_t *b; + pthread_barrierattr_t a; + pid_t pid; + int serials = 0; + int cnt; + int status; + 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; + } + + b = (pthread_barrier_t *) (((uintptr_t) mem + __alignof (pthread_barrier_t)) + & ~(__alignof (pthread_barrier_t) - 1)); + + if (pthread_barrierattr_init (&a) != 0) + { + puts ("barrierattr_init failed"); + return 1; + } + + if (pthread_barrierattr_getpshared (&a, &p) != 0) + { + puts ("1st barrierattr_getpshared failed"); + return 1; + } + + if (p != PTHREAD_PROCESS_PRIVATE) + { + puts ("default pshared value wrong"); + return 1; + } + + if (pthread_barrierattr_setpshared (&a, PTHREAD_PROCESS_SHARED) != 0) + { + puts ("barrierattr_setpshared failed"); + return 1; + } + + if (pthread_barrierattr_getpshared (&a, &p) != 0) + { + puts ("2nd barrierattr_getpshared failed"); + return 1; + } + + if (p != PTHREAD_PROCESS_SHARED) + { + puts ("pshared value after setpshared call wrong"); + return 1; + } + + if (pthread_barrier_init (b, &a, 2) != 0) + { + puts ("barrier_init failed"); + return 1; + } + + if (pthread_barrierattr_destroy (&a) != 0) + { + puts ("barrierattr_destroy failed"); + return 1; + } + + puts ("going to fork now"); + pid = fork (); + if (pid == -1) + { + puts ("fork failed"); + return 1; + } + + /* Just to be sure we don't hang forever. */ + alarm (4); + +#define N 30 + for (cnt = 0; cnt < N; ++cnt) + { + int e; + + e = pthread_barrier_wait (b); + if (e == PTHREAD_BARRIER_SERIAL_THREAD) + ++serials; + else if (e != 0) + { + printf ("%s: barrier_wait returned value %d != 0 and PTHREAD_BARRIER_SERIAL_THREAD\n", + pid == 0 ? "child" : "parent", e); + return 1; + } + } + + alarm (0); + + printf ("%s: was %d times the serial thread\n", + pid == 0 ? "child" : "parent", serials); + + if (pid == 0) + /* The child. Pass the number of times we had the serializing + thread back to the parent. */ + exit (serials); + + if (waitpid (pid, &status, 0) != pid) + { + puts ("waitpid failed"); + return 1; + } + + if (!WIFEXITED (status)) + { + puts ("child exited abnormally"); + return 1; + } + + if (WEXITSTATUS (status) + serials != N) + { + printf ("total number of serials is %d, expected %d\n", + WEXITSTATUS (status) + serials, N); + return 1; + } + + return 0; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/sysdeps/pthread/tst-barrier3.c b/sysdeps/pthread/tst-barrier3.c new file mode 100644 index 0000000000..3e3066f352 --- /dev/null +++ b/sysdeps/pthread/tst-barrier3.c @@ -0,0 +1,152 @@ +/* Test of POSIX barriers. + 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> + +#define NTHREADS 20 + +#define ROUNDS 20 + +static pthread_barrier_t barriers[NTHREADS]; + +static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; +static int counters[NTHREADS]; +static int serial[NTHREADS]; + +static void * +worker (void *arg) +{ + void *result = NULL; + int nr = (long int) arg; + int i; + + for (i = 0; i < ROUNDS; ++i) + { + int j; + int retval; + + if (nr == 0) + { + memset (counters, '\0', sizeof (counters)); + memset (serial, '\0', sizeof (serial)); + } + + retval = pthread_barrier_wait (&barriers[NTHREADS - 1]); + if (retval != 0 && retval != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("thread %d failed to wait for all the others\n", nr); + result = (void *) 1; + } + + for (j = nr; j < NTHREADS; ++j) + { + /* Increment the counter for this round. */ + pthread_mutex_lock (&lock); + ++counters[j]; + pthread_mutex_unlock (&lock); + + /* Wait for the rest. */ + retval = pthread_barrier_wait (&barriers[j]); + + /* Test the result. */ + if (nr == 0 && counters[j] != j + 1) + { + printf ("barrier in round %d released but count is %d\n", + j, counters[j]); + result = (void *) 1; + } + + if (retval != 0) + { + if (retval != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf ("thread %d in round %d has nonzero return value != PTHREAD_BARRIER_SERIAL_THREAD\n", + nr, j); + result = (void *) 1; + } + else + { + pthread_mutex_lock (&lock); + ++serial[j]; + pthread_mutex_unlock (&lock); + } + } + + /* Wait for the rest again. */ + retval = pthread_barrier_wait (&barriers[j]); + + /* Now we can check whether exactly one thread was serializing. */ + if (nr == 0 && serial[j] != 1) + { + printf ("not exactly one serial thread in round %d\n", j); + result = (void *) 1; + } + } + } + + return result; +} + + +#define TEST_FUNCTION do_test () +#define TIMEOUT 60 +static int +do_test (void) +{ + pthread_t threads[NTHREADS]; + int i; + void *res; + int result = 0; + + /* Initialized the barrier variables. */ + for (i = 0; i < NTHREADS; ++i) + if (pthread_barrier_init (&barriers[i], NULL, i + 1) != 0) + { + printf ("Failed to initialize barrier %d\n", i); + exit (1); + } + + /* Start the threads. */ + for (i = 0; i < NTHREADS; ++i) + if (pthread_create (&threads[i], NULL, worker, (void *) (long int) i) != 0) + { + printf ("Failed to start thread %d\n", i); + exit (1); + } + + /* And wait for them. */ + for (i = 0; i < NTHREADS; ++i) + if (pthread_join (threads[i], &res) != 0 || res != NULL) + { + printf ("thread %d returned a failure\n", i); + result = 1; + } + else + printf ("joined threads %d\n", i); + + if (result == 0) + puts ("all OK"); + + return result; +} + +#include "../test-skeleton.c" diff --git a/sysdeps/pthread/tst-barrier4.c b/sysdeps/pthread/tst-barrier4.c new file mode 100644 index 0000000000..fdf6c40a37 --- /dev/null +++ b/sysdeps/pthread/tst-barrier4.c @@ -0,0 +1,121 @@ +/* This tests destruction of a barrier right after waiting on it. + 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> + + +static pthread_barrier_t b1; +static pthread_barrier_t b2; + + +#define N 20 + +static void * +tf (void *arg) +{ + int round = 0; + + while (round++ < 30) + { + if (pthread_barrier_wait (&b1) == PTHREAD_BARRIER_SERIAL_THREAD) + { + pthread_barrier_destroy (&b1); + if (pthread_barrier_init (&b1, NULL, N) != 0) + { + puts ("tf: 1st barrier_init failed"); + exit (1); + } + } + + if (pthread_barrier_wait (&b2) == PTHREAD_BARRIER_SERIAL_THREAD) + { + pthread_barrier_destroy (&b2); + if (pthread_barrier_init (&b2, NULL, N) != 0) + { + puts ("tf: 2nd barrier_init failed"); + exit (1); + } + } + } + + return NULL; +} + + +static int +do_test (void) +{ + pthread_attr_t at; + int cnt; + + 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; + } + + if (pthread_barrier_init (&b1, NULL, N) != 0) + { + puts ("1st barrier_init failed"); + return 1; + } + + if (pthread_barrier_init (&b2, NULL, N) != 0) + { + puts ("2nd barrier_init failed"); + return 1; + } + + pthread_t th[N - 1]; + for (cnt = 0; cnt < N - 1; ++cnt) + if (pthread_create (&th[cnt], &at, tf, NULL) != 0) + { + puts ("pthread_create failed"); + return 1; + } + + if (pthread_attr_destroy (&at) != 0) + { + puts ("attr_destroy failed"); + return 1; + } + + tf (NULL); + + for (cnt = 0; cnt < N - 1; ++cnt) + if (pthread_join (th[cnt], NULL) != 0) + { + puts ("pthread_join failed"); + return 1; + } + + return 0; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" |