diff options
author | Siddhesh Poyarekar <siddhesh@redhat.com> | 2013-02-18 19:08:21 +0530 |
---|---|---|
committer | Siddhesh Poyarekar <siddhesh@redhat.com> | 2013-02-18 19:08:21 +0530 |
commit | ba384f6ed9275f3966505f2375b56d169e3dc588 (patch) | |
tree | d832a5a24bab934c946089b8d2a9a16f1766470d /stdlib/tst-tls-atexit.c | |
parent | ffaa74cf68a370e232279a9a9b0a02ade287cc99 (diff) | |
download | glibc-ba384f6ed9275f3966505f2375b56d169e3dc588.tar.gz glibc-ba384f6ed9275f3966505f2375b56d169e3dc588.tar.xz glibc-ba384f6ed9275f3966505f2375b56d169e3dc588.zip |
C++11 thread_local destructors support
This feature is specifically for the C++ compiler to offload calling thread_local object destructors on thread program exit, to glibc. This is to overcome the possible complication of destructors of thread_local objects getting called after the DSO in which they're defined is unloaded by the dynamic linker. The DSO is marked as 'unloadable' if it has a constructed thread_local object and marked as 'unloadable' again when all the constructed thread_local objects defined in it are destroyed.
Diffstat (limited to 'stdlib/tst-tls-atexit.c')
-rw-r--r-- | stdlib/tst-tls-atexit.c | 111 |
1 files changed, 111 insertions, 0 deletions
diff --git a/stdlib/tst-tls-atexit.c b/stdlib/tst-tls-atexit.c new file mode 100644 index 0000000000..b7312cbc84 --- /dev/null +++ b/stdlib/tst-tls-atexit.c @@ -0,0 +1,111 @@ +/* Verify that DSO is unloaded only if its TLS objects are destroyed. + Copyright (C) 2012 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 + <http://www.gnu.org/licenses/>. */ + +/* There are two tests in this test case. The first is implicit where it is + assumed that the destructor call on exit of the LOAD function does not + segfault. The other is a verification that after the thread has exited, a + dlclose will unload the DSO. */ + +#include <dlfcn.h> +#include <pthread.h> +#include <stdio.h> +#include <unistd.h> +#include <string.h> +#include <errno.h> + +void *handle; +pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER; + +void * +load (void *u) +{ + pthread_mutex_lock (&m); + handle = dlopen ("$ORIGIN/tst-tls-atexit-lib.so", RTLD_LAZY); + if (!handle) + { + printf ("Unable to load DSO: %s\n", dlerror ()); + return (void *) (uintptr_t) 1; + } + + void (*foo) (void) = (void (*) (void)) dlsym(handle, "do_foo"); + + if (!foo) + { + printf ("Unable to find symbol: %s\n", dlerror ()); + exit (1); + } + + foo (); + + /* This should not unload the DSO. If it does, then the thread exit will + result in a segfault. */ + dlclose (handle); + pthread_mutex_unlock (&m); + + return NULL; +} + +int +main (void) +{ + pthread_t t; + int ret; + void *thr_ret; + + if ((ret = pthread_create (&t, NULL, load, NULL)) != 0) + { + printf ("pthread_create failed: %s\n", strerror (ret)); + return 1; + } + + if ((ret = pthread_join (t, &thr_ret)) != 0) + { + printf ("pthread_create failed: %s\n", strerror (ret)); + return 1; + } + + if (thr_ret != NULL) + return 1; + + /* Now this should unload the DSO. */ + dlclose (handle); + + /* Run through our maps and ensure that the DSO is unloaded. */ + FILE *f = fopen ("/proc/self/maps", "r"); + + if (f == NULL) + { + perror ("Failed to open /proc/self/maps"); + fprintf (stderr, "Skipping verification of DSO unload\n"); + return 0; + } + + char *line = NULL; + size_t s = 0; + while (getline (&line, &s, f) > 0) + { + if (strstr (line, "tst-tls-atexit-lib.so")) + { + printf ("DSO not unloaded yet:\n%s", line); + return 1; + } + } + free (line); + + return 0; +} |