summaryrefslogtreecommitdiff
path: root/stdlib/tst-tls-atexit.c
diff options
context:
space:
mode:
Diffstat (limited to 'stdlib/tst-tls-atexit.c')
-rw-r--r--stdlib/tst-tls-atexit.c60
1 files changed, 46 insertions, 14 deletions
diff --git a/stdlib/tst-tls-atexit.c b/stdlib/tst-tls-atexit.c
index cea655decc..e9839d8b15 100644
--- a/stdlib/tst-tls-atexit.c
+++ b/stdlib/tst-tls-atexit.c
@@ -16,12 +16,20 @@
License along with the GNU C Library; if not, see
<http://www.gnu.org/licenses/>. */
-/* This test dynamically loads a DSO and spawns a thread that subsequently
- calls into the DSO to register a destructor for an object in the DSO and
- then calls dlclose on the handle for the DSO. When the thread exits, the
- DSO should not be unloaded or else the destructor called during thread exit
- will crash. Further in the main thread, the DSO is opened and closed again,
- at which point the DSO should be unloaded. */
+/* For the default case, i.e. NO_DELETE not defined, the test dynamically loads
+ a DSO and spawns a thread that subsequently calls into the DSO to register a
+ destructor for an object in the DSO and then calls dlclose on the handle for
+ the DSO. When the thread exits, the DSO should not be unloaded or else the
+ destructor called during thread exit will crash. Further in the main
+ thread, the DSO is opened and closed again, at which point the DSO should be
+ unloaded.
+
+ When NO_DELETE is defined, the DSO is loaded twice, once with just RTLD_LAZY
+ flag and the second time with the RTLD_NODELETE flag set. The thread is
+ spawned, destructor registered and then thread exits without closing the
+ DSO. In the main thread, the first handle is then closed, followed by the
+ second handle. In the end, the DSO should remain loaded due to the
+ RTLD_NODELETE flag being set in the second dlopen call. */
#include <dlfcn.h>
#include <pthread.h>
@@ -31,6 +39,14 @@
#include <errno.h>
#include <link.h>
+#ifndef NO_DELETE
+# define LOADED_IS_GOOD false
+#endif
+
+#ifndef H2_RTLD_FLAGS
+# define H2_RTLD_FLAGS (RTLD_LAZY)
+#endif
+
#define DSO_NAME "$ORIGIN/tst-tls-atexit-lib.so"
/* Walk through the map in the _r_debug structure to see if our lib is still
@@ -43,7 +59,10 @@ is_loaded (void)
for (; lm; lm = lm->l_next)
if (lm->l_type == lt_loaded && lm->l_name
&& strcmp (basename (DSO_NAME), basename (lm->l_name)) == 0)
- return true;
+ {
+ printf ("%s is still loaded\n", lm->l_name);
+ return true;
+ }
return false;
}
@@ -63,7 +82,9 @@ reg_dtor_and_close (void *h)
reg_dtor ();
+#ifndef NO_DELETE
dlclose (h);
+#endif
return NULL;
}
@@ -104,19 +125,30 @@ do_test (void)
return 1;
}
+#ifndef NO_DELETE
if (spawn_thread (h1) != 0)
return 1;
+#endif
- /* Now this should unload the DSO. FIXME: This is a bug, calling dlclose
- like this is actually wrong, but it works because cxa_thread_atexit_impl
- has a bug which results in dlclose allowing this to work. */
- dlclose (h1);
+ void *h2 = dlopen (DSO_NAME, H2_RTLD_FLAGS);
+ if (h2 == NULL)
+ {
+ printf ("h2: Unable to load DSO: %s\n", dlerror ());
+ return 1;
+ }
- /* Check link maps to ensure that the DSO has unloaded. */
- if (is_loaded ())
+#ifdef NO_DELETE
+ if (spawn_thread (h1) != 0)
return 1;
- return 0;
+ dlclose (h1);
+#endif
+ dlclose (h2);
+
+ /* Check link maps to ensure that the DSO has unloaded. In the normal case,
+ the DSO should be unloaded if there are no uses. However, if one of the
+ dlopen calls were with RTLD_NODELETE, the DSO should remain loaded. */
+ return is_loaded () == LOADED_IS_GOOD ? 0 : 1;
}
#define TEST_FUNCTION do_test ()