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>
This commit is contained in:
Timo Teräs 2011-03-24 13:27:36 +02:00 committed by Bernhard Reutner-Fischer
parent bc4bc07d93
commit f69319d5a7
2 changed files with 50 additions and 5 deletions

1
TODO
View File

@ -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
biggest things (i.e. stuff at the end of the list) to make
them smaller.
*) Fix dlopen/dlsym/dlclose locking to more fine grained or use RCU
<more wishlist items here>

View File

@ -34,6 +34,7 @@
#include <stdio.h>
#include <string.h> /* Needed for 'strstr' prototype' */
#include <stdbool.h>
#include <bits/uClibc_mutex.h>
#ifdef __UCLIBC_HAS_TLS__
#include <tls.h>
@ -44,6 +45,10 @@
extern void _dl_add_to_slotinfo(struct link_map *l);
#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
# if defined(USE_TLS) && USE_TLS
# include <dl-tls.h>
@ -291,7 +296,7 @@ static ptrdiff_t _dl_build_local_scope (struct elf_resolve **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 dyn_elf *dyn_chain, *rpnt = NULL, *dyn_ptr, *relro_ptr, *handle;
@ -650,7 +655,18 @@ oops:
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 dyn_elf *handle;
@ -698,7 +714,7 @@ void *dlsym(void *vhandle, const char *name)
* dynamic loader itself, as it doesn't know
* how to properly treat it.
*/
from = (ElfW(Addr)) __builtin_return_address(0);
from = (ElfW(Addr)) caller_address;
tfrom = NULL;
for (rpnt = _dl_symbol_tables; rpnt; rpnt = rpnt->next) {
@ -735,6 +751,17 @@ out:
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
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)
{
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)
@ -1065,7 +1098,7 @@ int dlinfo(void)
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 *rpnt;
@ -1177,3 +1210,14 @@ int dladdr(const void *__address, Dl_info * __info)
}
}
#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;
}