diff options
Diffstat (limited to 'sysdeps')
-rw-r--r-- | sysdeps/generic/ldsodefs.h | 9 | ||||
-rw-r--r-- | sysdeps/pthread/Makefile | 10 | ||||
-rw-r--r-- | sysdeps/pthread/tst-create1.c | 119 | ||||
-rw-r--r-- | sysdeps/pthread/tst-create1mod.c | 41 |
4 files changed, 176 insertions, 3 deletions
diff --git a/sysdeps/generic/ldsodefs.h b/sysdeps/generic/ldsodefs.h index d49529da0d..9ec1511bb0 100644 --- a/sysdeps/generic/ldsodefs.h +++ b/sysdeps/generic/ldsodefs.h @@ -369,6 +369,13 @@ struct rtld_global list of loaded objects while an object is added to or removed from that list. */ __rtld_lock_define_recursive (EXTERN, _dl_load_write_lock) + /* This lock protects global and module specific TLS related data. + E.g. it is held in dlopen and dlclose when GL(dl_tls_generation), + GL(dl_tls_max_dtv_idx) or GL(dl_tls_dtv_slotinfo_list) are + accessed and when TLS related relocations are processed for a + module. It was introduced to keep pthread_create accessing TLS + state that is being set up. */ + __rtld_lock_define_recursive (EXTERN, _dl_load_tls_lock) /* Incremented whenever something may have been added to dl_loaded. */ EXTERN unsigned long long _dl_load_adds; @@ -1268,7 +1275,7 @@ extern int _dl_scope_free (void *) attribute_hidden; /* Add module to slot information data. If DO_ADD is false, only the required memory is allocated. Must be called with GL - (dl_load_lock) acquired. If the function has already been called + (dl_load_tls_lock) acquired. If the function has already been called for the link map L with !do_add, then this function will not raise an exception, otherwise it is possible that it encounters a memory allocation failure. */ diff --git a/sysdeps/pthread/Makefile b/sysdeps/pthread/Makefile index 0af9c59b42..df8943f486 100644 --- a/sysdeps/pthread/Makefile +++ b/sysdeps/pthread/Makefile @@ -152,15 +152,17 @@ tests += tst-cancelx2 tst-cancelx3 tst-cancelx6 tst-cancelx8 tst-cancelx9 \ tst-cleanupx0 tst-cleanupx1 tst-cleanupx2 tst-cleanupx3 ifeq ($(build-shared),yes) -tests += tst-atfork2 tst-pt-tls4 tst-_res1 tst-fini1 +tests += tst-atfork2 tst-pt-tls4 tst-_res1 tst-fini1 tst-create1 tests-nolibpthread += tst-fini1 endif modules-names += tst-atfork2mod tst-tls4moda tst-tls4modb \ - tst-_res1mod1 tst-_res1mod2 tst-fini1mod + tst-_res1mod1 tst-_res1mod2 tst-fini1mod \ + tst-create1mod test-modules = $(addprefix $(objpfx),$(addsuffix .so,$(modules-names))) tst-atfork2mod.so-no-z-defs = yes +tst-create1mod.so-no-z-defs = yes ifeq ($(build-shared),yes) # Build all the modules even when not actually running test programs. @@ -279,4 +281,8 @@ LDFLAGS-tst-join7mod.so = -Wl,-soname,tst-join7mod.so CFLAGS-tst-unwind-thread.c += -funwind-tables +LDFLAGS-tst-create1 = -Wl,-export-dynamic +$(objpfx)tst-create1: $(shared-thread-library) +$(objpfx)tst-create1.out: $(objpfx)tst-create1mod.so + endif diff --git a/sysdeps/pthread/tst-create1.c b/sysdeps/pthread/tst-create1.c new file mode 100644 index 0000000000..932586c309 --- /dev/null +++ b/sysdeps/pthread/tst-create1.c @@ -0,0 +1,119 @@ +/* Verify that pthread_create does not deadlock when ctors take locks. + Copyright (C) 2021 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 <stdio.h> +#include <support/xdlfcn.h> +#include <support/xthread.h> + +/* +Check if ctor and pthread_create deadlocks in + +thread 1: dlopen -> ctor -> lock(user_lock) +thread 2: lock(user_lock) -> pthread_create + +or in + +thread 1: dlclose -> dtor -> lock(user_lock) +thread 2: lock(user_lock) -> pthread_create +*/ + +static pthread_barrier_t bar_ctor; +static pthread_barrier_t bar_dtor; +static pthread_mutex_t user_lock = PTHREAD_MUTEX_INITIALIZER; + +void +ctor (void) +{ + xpthread_barrier_wait (&bar_ctor); + dprintf (1, "thread 1: in ctor: started.\n"); + xpthread_mutex_lock (&user_lock); + dprintf (1, "thread 1: in ctor: locked user_lock.\n"); + xpthread_mutex_unlock (&user_lock); + dprintf (1, "thread 1: in ctor: unlocked user_lock.\n"); + dprintf (1, "thread 1: in ctor: done.\n"); +} + +void +dtor (void) +{ + xpthread_barrier_wait (&bar_dtor); + dprintf (1, "thread 1: in dtor: started.\n"); + xpthread_mutex_lock (&user_lock); + dprintf (1, "thread 1: in dtor: locked user_lock.\n"); + xpthread_mutex_unlock (&user_lock); + dprintf (1, "thread 1: in dtor: unlocked user_lock.\n"); + dprintf (1, "thread 1: in dtor: done.\n"); +} + +static void * +thread3 (void *a) +{ + dprintf (1, "thread 3: started.\n"); + dprintf (1, "thread 3: done.\n"); + return 0; +} + +static void * +thread2 (void *a) +{ + pthread_t t3; + dprintf (1, "thread 2: started.\n"); + + xpthread_mutex_lock (&user_lock); + dprintf (1, "thread 2: locked user_lock.\n"); + xpthread_barrier_wait (&bar_ctor); + t3 = xpthread_create (0, thread3, 0); + xpthread_mutex_unlock (&user_lock); + dprintf (1, "thread 2: unlocked user_lock.\n"); + xpthread_join (t3); + + xpthread_mutex_lock (&user_lock); + dprintf (1, "thread 2: locked user_lock.\n"); + xpthread_barrier_wait (&bar_dtor); + t3 = xpthread_create (0, thread3, 0); + xpthread_mutex_unlock (&user_lock); + dprintf (1, "thread 2: unlocked user_lock.\n"); + xpthread_join (t3); + + dprintf (1, "thread 2: done.\n"); + return 0; +} + +static void +thread1 (void) +{ + dprintf (1, "thread 1: started.\n"); + xpthread_barrier_init (&bar_ctor, NULL, 2); + xpthread_barrier_init (&bar_dtor, NULL, 2); + pthread_t t2 = xpthread_create (0, thread2, 0); + void *p = xdlopen ("tst-create1mod.so", RTLD_NOW | RTLD_GLOBAL); + dprintf (1, "thread 1: dlopen done.\n"); + xdlclose (p); + dprintf (1, "thread 1: dlclose done.\n"); + xpthread_join (t2); + dprintf (1, "thread 1: done.\n"); +} + +static int +do_test (void) +{ + thread1 (); + return 0; +} + +#include <support/test-driver.c> diff --git a/sysdeps/pthread/tst-create1mod.c b/sysdeps/pthread/tst-create1mod.c new file mode 100644 index 0000000000..62c9006961 --- /dev/null +++ b/sysdeps/pthread/tst-create1mod.c @@ -0,0 +1,41 @@ +/* Verify that pthread_create does not deadlock when ctors take locks. + Copyright (C) 2021 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 <stdio.h> + +/* Require TLS setup for the module. */ +__thread int tlsvar; + +void ctor (void); +void dtor (void); + +static void __attribute__ ((constructor)) +do_init (void) +{ + dprintf (1, "constructor started: %d.\n", tlsvar++); + ctor (); + dprintf (1, "constructor done: %d.\n", tlsvar++); +} + +static void __attribute__ ((destructor)) +do_end (void) +{ + dprintf (1, "destructor started: %d.\n", tlsvar++); + dtor (); + dprintf (1, "destructor done: %d.\n", tlsvar++); +} |