From c0463e8b79ca650b60badc5b9c0d574b91aa8d01 Mon Sep 17 00:00:00 2001 From: Samuel Thibault Date: Mon, 10 Feb 2020 01:21:46 +0000 Subject: pthread: Move some join tests from nptl to sysdeps/pthread So they can be checked with htl too. --- sysdeps/pthread/Makefile | 8 ++ sysdeps/pthread/tst-join1.c | 82 ++++++++++++++++++ sysdeps/pthread/tst-join4.c | 124 ++++++++++++++++++++++++++ sysdeps/pthread/tst-join5.c | 191 +++++++++++++++++++++++++++++++++++++++++ sysdeps/pthread/tst-join6.c | 2 + sysdeps/pthread/tst-join7.c | 46 ++++++++++ sysdeps/pthread/tst-join7mod.c | 63 ++++++++++++++ 7 files changed, 516 insertions(+) create mode 100644 sysdeps/pthread/tst-join1.c create mode 100644 sysdeps/pthread/tst-join4.c create mode 100644 sysdeps/pthread/tst-join5.c create mode 100644 sysdeps/pthread/tst-join6.c create mode 100644 sysdeps/pthread/tst-join7.c create mode 100644 sysdeps/pthread/tst-join7mod.c (limited to 'sysdeps/pthread') diff --git a/sysdeps/pthread/Makefile b/sysdeps/pthread/Makefile index c102f45..396f2b1 100644 --- a/sysdeps/pthread/Makefile +++ b/sysdeps/pthread/Makefile @@ -51,6 +51,7 @@ tests += tst-cnd-basic tst-mtx-trylock tst-cnd-broadcast \ tst-cond14 tst-cond15 tst-cond16 tst-cond17 tst-cond18 tst-cond19 \ tst-cond23 tst-cond24 tst-cond25 \ tst-cond-except \ + tst-join1 tst-join4 tst-join5 tst-join6 tst-join7 \ tst-key1 tst-key2 tst-key3 tst-key4 \ tst-mutex1 tst-mutex2 tst-mutex3 tst-mutex4 tst-mutex6 tst-mutex10 \ tst-once1 tst-once2 tst-once3 tst-once4 \ @@ -62,6 +63,8 @@ tests += tst-cnd-basic tst-mtx-trylock tst-cnd-broadcast \ tests += tst-oncex3 tst-oncex4 +modules-names += tst-join7mod + ifeq ($(build-shared),yes) tests-static += tst-cond8-static tests += tst-cond8-static @@ -70,4 +73,9 @@ endif CFLAGS-tst-oncex3.c += -fexceptions CFLAGS-tst-oncex4.c += -fexceptions +$(objpfx)tst-join7: $(libdl) $(shared-thread-library) +$(objpfx)tst-join7.out: $(objpfx)tst-join7mod.so +$(objpfx)tst-join7mod.so: $(shared-thread-library) +LDFLAGS-tst-join7mod.so = -Wl,-soname,tst-join7mod.so + endif diff --git a/sysdeps/pthread/tst-join1.c b/sysdeps/pthread/tst-join1.c new file mode 100644 index 0000000..05bf5e4 --- /dev/null +++ b/sysdeps/pthread/tst-join1.c @@ -0,0 +1,82 @@ +/* Copyright (C) 2002-2020 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper , 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 + . */ + +#include +#include +#include + + +static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; + + +static void * +tf (void *arg) +{ + pthread_t mh = (pthread_t) arg; + void *result; + + if (pthread_mutex_unlock (&lock) != 0) + { + puts ("unlock failed"); + exit (1); + } + + if (pthread_join (mh, &result) != 0) + { + puts ("join failed"); + exit (1); + } + + if (result != (void *) 42l) + { + printf ("result wrong: expected %p, got %p\n", (void *) 42, result); + exit (1); + } + + exit (0); +} + + +static int +do_test (void) +{ + pthread_t th; + + if (pthread_mutex_lock (&lock) != 0) + { + puts ("1st lock failed"); + exit (1); + } + + if (pthread_create (&th, NULL, tf, (void *) pthread_self ()) != 0) + { + puts ("create failed"); + exit (1); + } + + if (pthread_mutex_lock (&lock) != 0) + { + puts ("2nd lock failed"); + exit (1); + } + + pthread_exit ((void *) 42); +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/sysdeps/pthread/tst-join4.c b/sysdeps/pthread/tst-join4.c new file mode 100644 index 0000000..18af45a --- /dev/null +++ b/sysdeps/pthread/tst-join4.c @@ -0,0 +1,124 @@ +/* Copyright (C) 2003-2020 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper , 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 + . */ + +#include +#include +#include +#include + + +static pthread_barrier_t bar; + + +static void * +tf (void *arg) +{ + if (pthread_barrier_wait (&bar) != 0) + { + puts ("tf: barrier_wait failed"); + exit (1); + } + + return (void *) 1l; +} + + +static int +do_test (void) +{ + if (pthread_barrier_init (&bar, NULL, 3) != 0) + { + puts ("barrier_init failed"); + exit (1); + } + + pthread_attr_t a; + + if (pthread_attr_init (&a) != 0) + { + puts ("attr_init failed"); + exit (1); + } + + if (pthread_attr_setstacksize (&a, 1 * 1024 * 1024) != 0) + { + puts ("attr_setstacksize failed"); + return 1; + } + + pthread_t th[2]; + + if (pthread_create (&th[0], &a, tf, NULL) != 0) + { + puts ("1st create failed"); + exit (1); + } + + if (pthread_attr_setdetachstate (&a, PTHREAD_CREATE_DETACHED) != 0) + { + puts ("attr_setdetachstate failed"); + exit (1); + } + + if (pthread_create (&th[1], &a, tf, NULL) != 0) + { + puts ("1st create failed"); + exit (1); + } + + if (pthread_attr_destroy (&a) != 0) + { + puts ("attr_destroy failed"); + exit (1); + } + + if (pthread_detach (th[0]) != 0) + { + puts ("could not detach 1st thread"); + exit (1); + } + + int err = pthread_detach (th[0]); + if (err == 0) + { + puts ("second detach of 1st thread succeeded"); + exit (1); + } + if (err != EINVAL) + { + printf ("second detach of 1st thread returned %d, not EINVAL\n", err); + exit (1); + } + + err = pthread_detach (th[1]); + if (err == 0) + { + puts ("detach of 2nd thread succeeded"); + exit (1); + } + if (err != EINVAL) + { + printf ("detach of 2nd thread returned %d, not EINVAL\n", err); + exit (1); + } + + exit (0); +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/sysdeps/pthread/tst-join5.c b/sysdeps/pthread/tst-join5.c new file mode 100644 index 0000000..acdc365 --- /dev/null +++ b/sysdeps/pthread/tst-join5.c @@ -0,0 +1,191 @@ +/* Copyright (C) 2003-2020 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper , 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 + . */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +static void +wait_code (void) +{ + struct timespec ts = { .tv_sec = 0, .tv_nsec = 200000000 }; + while (nanosleep (&ts, &ts) < 0) + ; +} + + +#ifdef WAIT_IN_CHILD +static pthread_barrier_t b; +#endif + +static int +thread_join (pthread_t thread, void **retval) +{ +#if defined USE_PTHREAD_TIMEDJOIN_NP + const struct timespec ts = timespec_add (xclock_now (CLOCK_REALTIME), + make_timespec (1000, 0)); + return pthread_timedjoin_np (thread, retval, &ts); +#elif defined USE_PTHREAD_CLOCKJOIN_NP_REALTIME + const struct timespec ts = timespec_add (xclock_now (CLOCK_REALTIME), + make_timespec (1000, 0)); + return pthread_clockjoin_np (thread, retval, CLOCK_REALTIME, &ts); +#elif defined USE_PTHREAD_CLOCKJOIN_NP_MONOTONIC + const struct timespec ts = timespec_add (xclock_now (CLOCK_MONOTONIC), + make_timespec (1000, 0)); + return pthread_clockjoin_np (thread, retval, CLOCK_MONOTONIC, &ts); +#else + return pthread_join (thread, retval); +#endif +} + + +static void * +tf1 (void *arg) +{ +#ifdef WAIT_IN_CHILD + xpthread_barrier_wait (&b); + + wait_code (); +#endif + + thread_join ((pthread_t) arg, NULL); + + exit (42); +} + + +static void * +tf2 (void *arg) +{ +#ifdef WAIT_IN_CHILD + xpthread_barrier_wait (&b); + + wait_code (); +#endif + + thread_join ((pthread_t) arg, NULL); + + exit (43); +} + + +static int +do_test (void) +{ +#ifdef WAIT_IN_CHILD + xpthread_barrier_init (&b, NULL, 2); +#endif + + pthread_t th; + + int err = thread_join (pthread_self (), NULL); + if (err == 0) + { + puts ("1st circular join succeeded"); + return 1; + } + if (err != EDEADLK) + { + printf ("1st circular join %d, not EDEADLK\n", err); + return 1; + } + + th = xpthread_create (NULL, tf1, (void *) pthread_self ()); + +#ifndef WAIT_IN_CHILD + wait_code (); +#endif + + xpthread_cancel (th); + +#ifdef WAIT_IN_CHILD + xpthread_barrier_wait (&b); +#endif + + void *r; + err = thread_join (th, &r); + if (err != 0) + { + printf ("cannot join 1st thread: %d\n", err); + return 1; + } + if (r != PTHREAD_CANCELED) + { + puts ("1st thread not canceled"); + return 1; + } + + err = thread_join (pthread_self (), NULL); + if (err == 0) + { + puts ("2nd circular join succeeded"); + return 1; + } + if (err != EDEADLK) + { + printf ("2nd circular join %d, not EDEADLK\n", err); + return 1; + } + + th = xpthread_create (NULL, tf2, (void *) pthread_self ()); + +#ifndef WAIT_IN_CHILD + wait_code (); +#endif + + xpthread_cancel (th); + +#ifdef WAIT_IN_CHILD + xpthread_barrier_wait (&b); +#endif + + if (thread_join (th, &r) != 0) + { + puts ("cannot join 2nd thread"); + return 1; + } + if (r != PTHREAD_CANCELED) + { + puts ("2nd thread not canceled"); + return 1; + } + + err = thread_join (pthread_self (), NULL); + if (err == 0) + { + puts ("3rd circular join succeeded"); + return 1; + } + if (err != EDEADLK) + { + printf ("3rd circular join %d, not EDEADLK\n", err); + return 1; + } + + return 0; +} + +#include diff --git a/sysdeps/pthread/tst-join6.c b/sysdeps/pthread/tst-join6.c new file mode 100644 index 0000000..0c9e7c0 --- /dev/null +++ b/sysdeps/pthread/tst-join6.c @@ -0,0 +1,2 @@ +#define WAIT_IN_CHILD 1 +#include "tst-join5.c" diff --git a/sysdeps/pthread/tst-join7.c b/sysdeps/pthread/tst-join7.c new file mode 100644 index 0000000..c077d3c --- /dev/null +++ b/sysdeps/pthread/tst-join7.c @@ -0,0 +1,46 @@ +/* Verify that TLS access in separate thread in a dlopened library does not + deadlock. + Copyright (C) 2015-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 + . */ + +#include + +/* When one dynamically loads a module, which spawns a thread to perform some + activities, it could be possible that TLS storage is accessed for the first + time in that thread. This results in an allocation request within the + thread, which could result in an attempt to take the rtld load_lock. This + is a problem because it would then deadlock with the dlopen (which owns the + lock), if the main thread is waiting for the spawned thread to exit. We can + at least ensure that this problem does not occur due to accesses within + libc.so, by marking TLS variables within libc.so as IE. The problem of an + arbitrary variable being accessed and constructed within such a thread still + exists but this test case does not verify that. */ + +int +do_test (void) +{ + void *f = dlopen ("tst-join7mod.so", RTLD_NOW | RTLD_GLOBAL); + if (f) + dlclose (f); + else + return 1; + + return 0; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" diff --git a/sysdeps/pthread/tst-join7mod.c b/sysdeps/pthread/tst-join7mod.c new file mode 100644 index 0000000..934087d --- /dev/null +++ b/sysdeps/pthread/tst-join7mod.c @@ -0,0 +1,63 @@ +/* Verify that TLS access in separate thread in a dlopened library does not + deadlock - the module. + Copyright (C) 2015-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 + . */ + +#include +#include +#include +#include +#include + +static pthread_t th; +static int running = 1; + +static void * +test_run (void *p) +{ + while (atomic_load_relaxed (&running)) + printf ("Test running\n"); + printf ("Test finished\n"); + return NULL; +} + +static void __attribute__ ((constructor)) +do_init (void) +{ + int ret = pthread_create (&th, NULL, test_run, NULL); + + if (ret != 0) + { + printf ("failed to create thread: %s (%d)\n", strerror (ret), ret); + exit (1); + } +} + +static void __attribute__ ((destructor)) +do_end (void) +{ + atomic_store_relaxed (&running, 0); + int ret = pthread_join (th, NULL); + + if (ret != 0) + { + printf ("pthread_join: %s(%d)\n", strerror (ret), ret); + exit (1); + } + + printf ("Thread joined\n"); +} -- cgit v1.1