Browse Source

libdl: rudimentary locking for dlopen/dlsym/dlclose

This implements big-dlfcn lock to allow multithreaded usage of
dlopen/dlsym/dlclose. We should really clean up the dl code so
we can use more fine grained locking or even RCU where appropriate.
But at least we won't crash now.

Signed-off-by: Timo Teräs <timo.teras@iki.fi>
Signed-off-by: Bernhard Reutner-Fischer <rep.dot.nop@gmail.com>
Timo Teräs 13 years ago
parent
commit
f69319d5a7
2 changed files with 50 additions and 5 deletions
  1. 1 0
      TODO
  2. 49 5
      ldso/libdl/libdl.c

+ 1 - 0
TODO

@@ -101,6 +101,7 @@ TODO list for AFTER the uClibc 1.0.0 release:
     *) run 'nm -D --size-sort -t d libuClibc-0.9.26.so' and work on the
     *) run 'nm -D --size-sort -t d libuClibc-0.9.26.so' and work on the
 	biggest things (i.e. stuff at the end of the list) to make
 	biggest things (i.e. stuff at the end of the list) to make
 	them smaller.
 	them smaller.
+    *) Fix dlopen/dlsym/dlclose locking to more fine grained or use RCU
     <more wishlist items here>
     <more wishlist items here>
 
 
 
 

+ 49 - 5
ldso/libdl/libdl.c

@@ -34,6 +34,7 @@
 #include <stdio.h>
 #include <stdio.h>
 #include <string.h> /* Needed for 'strstr' prototype' */
 #include <string.h> /* Needed for 'strstr' prototype' */
 #include <stdbool.h>
 #include <stdbool.h>
+#include <bits/uClibc_mutex.h>
 
 
 #ifdef __UCLIBC_HAS_TLS__
 #ifdef __UCLIBC_HAS_TLS__
 #include <tls.h>
 #include <tls.h>
@@ -44,6 +45,10 @@
 extern void _dl_add_to_slotinfo(struct link_map  *l);
 extern void _dl_add_to_slotinfo(struct link_map  *l);
 #endif
 #endif
 
 
+/* TODO: get rid of global lock and use more finegrained locking, or
+ * perhaps RCU for the global structures */
+__UCLIBC_MUTEX_STATIC(_dl_mutex, PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP);
+
 #ifdef SHARED
 #ifdef SHARED
 # if defined(USE_TLS) && USE_TLS
 # if defined(USE_TLS) && USE_TLS
 # include <dl-tls.h>
 # include <dl-tls.h>
@@ -291,7 +296,7 @@ static ptrdiff_t _dl_build_local_scope (struct elf_resolve **list,
 	return p - list;
 	return p - list;
 }
 }
 
 
-void *dlopen(const char *libname, int flag)
+static void *do_dlopen(const char *libname, int flag)
 {
 {
 	struct elf_resolve *tpnt, *tfrom;
 	struct elf_resolve *tpnt, *tfrom;
 	struct dyn_elf *dyn_chain, *rpnt = NULL, *dyn_ptr, *relro_ptr, *handle;
 	struct dyn_elf *dyn_chain, *rpnt = NULL, *dyn_ptr, *relro_ptr, *handle;
@@ -650,7 +655,18 @@ oops:
 	return NULL;
 	return NULL;
 }
 }
 
 
-void *dlsym(void *vhandle, const char *name)
+void *dlopen(const char *libname, int flag)
+{
+	void *ret;
+
+	__UCLIBC_MUTEX_CONDITIONAL_LOCK(_dl_mutex, 1);
+	ret = do_dlopen(libname, flag);
+	__UCLIBC_MUTEX_CONDITIONAL_UNLOCK(_dl_mutex, 1);
+
+	return ret;
+}
+
+static void *do_dlsym(void *vhandle, const char *name, void *caller_address)
 {
 {
 	struct elf_resolve *tpnt, *tfrom;
 	struct elf_resolve *tpnt, *tfrom;
 	struct dyn_elf *handle;
 	struct dyn_elf *handle;
@@ -698,7 +714,7 @@ void *dlsym(void *vhandle, const char *name)
 		 * dynamic loader itself, as it doesn't know
 		 * dynamic loader itself, as it doesn't know
 		 * how to properly treat it.
 		 * how to properly treat it.
 		 */
 		 */
-		from = (ElfW(Addr)) __builtin_return_address(0);
+		from = (ElfW(Addr)) caller_address;
 
 
 		tfrom = NULL;
 		tfrom = NULL;
 		for (rpnt = _dl_symbol_tables; rpnt; rpnt = rpnt->next) {
 		for (rpnt = _dl_symbol_tables; rpnt; rpnt = rpnt->next) {
@@ -735,6 +751,17 @@ out:
 	return ret;
 	return ret;
 }
 }
 
 
+void *dlsym(void *vhandle, const char *name)
+{
+	void *ret;
+
+	__UCLIBC_MUTEX_CONDITIONAL_LOCK(_dl_mutex, 1);
+	ret = do_dlsym(vhandle, name, __builtin_return_address(0));
+	__UCLIBC_MUTEX_CONDITIONAL_UNLOCK(_dl_mutex, 1);
+
+	return ret;
+}
+
 #if 0
 #if 0
 void *dlvsym(void *vhandle, const char *name, const char *version)
 void *dlvsym(void *vhandle, const char *name, const char *version)
 {
 {
@@ -1018,7 +1045,13 @@ static int do_dlclose(void *vhandle, int need_fini)
 
 
 int dlclose(void *vhandle)
 int dlclose(void *vhandle)
 {
 {
-	return do_dlclose(vhandle, 1);
+	int ret;
+
+	__UCLIBC_MUTEX_CONDITIONAL_LOCK(_dl_mutex, 1);
+	ret = do_dlclose(vhandle, 1);
+	__UCLIBC_MUTEX_CONDITIONAL_UNLOCK(_dl_mutex, 1);
+
+	return ret;
 }
 }
 
 
 char *dlerror(void)
 char *dlerror(void)
@@ -1065,7 +1098,7 @@ int dlinfo(void)
 	return 0;
 	return 0;
 }
 }
 
 
-int dladdr(const void *__address, Dl_info * __info)
+static int do_dladdr(const void *__address, Dl_info * __info)
 {
 {
 	struct elf_resolve *pelf;
 	struct elf_resolve *pelf;
 	struct elf_resolve *rpnt;
 	struct elf_resolve *rpnt;
@@ -1177,3 +1210,14 @@ int dladdr(const void *__address, Dl_info * __info)
 	}
 	}
 }
 }
 #endif
 #endif
+
+int dladdr(const void *__address, Dl_info * __info)
+{
+	int ret;
+
+	__UCLIBC_MUTEX_CONDITIONAL_LOCK(_dl_mutex, 1);
+	ret = do_dladdr(__address, __info);
+	__UCLIBC_MUTEX_CONDITIONAL_UNLOCK(_dl_mutex, 1);
+
+	return ret;
+}