diff options
Diffstat (limited to 'elf')
-rw-r--r-- | elf/dl-close.c | 6 | ||||
-rw-r--r-- | elf/dl-open.c | 35 | ||||
-rw-r--r-- | elf/dl-support.c | 7 | ||||
-rw-r--r-- | elf/dl-tls.c | 16 | ||||
-rw-r--r-- | elf/rtld.c | 1 |
5 files changed, 56 insertions, 9 deletions
diff --git a/elf/dl-close.c b/elf/dl-close.c index 93ff5c9..cfe0f1c 100644 --- a/elf/dl-close.c +++ b/elf/dl-close.c @@ -549,6 +549,9 @@ _dl_close_worker (struct link_map *map, bool force) size_t tls_free_end; tls_free_start = tls_free_end = NO_TLS_OFFSET; + /* Protects global and module specitic TLS state. */ + __rtld_lock_lock_recursive (GL(dl_load_tls_lock)); + /* We modify the list of loaded objects. */ __rtld_lock_lock_recursive (GL(dl_load_write_lock)); @@ -784,6 +787,9 @@ _dl_close_worker (struct link_map *map, bool force) GL(dl_tls_static_used) = tls_free_start; } + /* TLS is cleaned up for the unloaded modules. */ + __rtld_lock_unlock_recursive (GL(dl_load_tls_lock)); + #ifdef SHARED /* Auditing checkpoint: we have deleted all objects. */ if (__glibc_unlikely (do_audit)) diff --git a/elf/dl-open.c b/elf/dl-open.c index 5295e93..6ea5dd2 100644 --- a/elf/dl-open.c +++ b/elf/dl-open.c @@ -66,6 +66,9 @@ struct dl_open_args libc_map value in the namespace in case of a dlopen failure. */ bool libc_already_loaded; + /* Set to true if the end of dl_open_worker_begin was reached. */ + bool worker_continue; + /* Original parameters to the program and the current environment. */ int argc; char **argv; @@ -482,7 +485,7 @@ call_dl_init (void *closure) } static void -dl_open_worker (void *a) +dl_open_worker_begin (void *a) { struct dl_open_args *args = a; const char *file = args->file; @@ -774,6 +777,36 @@ dl_open_worker (void *a) _dl_call_libc_early_init (libc_map, false); } + args->worker_continue = true; +} + +static void +dl_open_worker (void *a) +{ + struct dl_open_args *args = a; + + args->worker_continue = false; + + { + /* Protects global and module specific TLS state. */ + __rtld_lock_lock_recursive (GL(dl_load_tls_lock)); + + struct dl_exception ex; + int err = _dl_catch_exception (&ex, dl_open_worker_begin, args); + + __rtld_lock_unlock_recursive (GL(dl_load_tls_lock)); + + if (__glibc_unlikely (ex.errstring != NULL)) + /* Reraise the error. */ + _dl_signal_exception (err, &ex, NULL); + } + + if (!args->worker_continue) + return; + + int mode = args->mode; + struct link_map *new = args->map; + /* Run the initializer functions of new objects. Temporarily disable the exception handler, so that lazy binding failures are fatal. */ diff --git a/elf/dl-support.c b/elf/dl-support.c index 02e2ed7..d99c1f1 100644 --- a/elf/dl-support.c +++ b/elf/dl-support.c @@ -228,6 +228,13 @@ __rtld_lock_define_initialized_recursive (, _dl_load_lock) list of loaded objects while an object is added to or removed from that list. */ __rtld_lock_define_initialized_recursive (, _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_initialized_recursive (, _dl_load_tls_lock) #ifdef HAVE_AUX_VECTOR diff --git a/elf/dl-tls.c b/elf/dl-tls.c index d554ae4..9260d2d 100644 --- a/elf/dl-tls.c +++ b/elf/dl-tls.c @@ -532,7 +532,7 @@ _dl_allocate_tls_init (void *result) size_t maxgen = 0; /* Protects global dynamic TLS related state. */ - __rtld_lock_lock_recursive (GL(dl_load_lock)); + __rtld_lock_lock_recursive (GL(dl_load_tls_lock)); /* Check if the current dtv is big enough. */ if (dtv[-1].counter < GL(dl_tls_max_dtv_idx)) @@ -606,7 +606,7 @@ _dl_allocate_tls_init (void *result) listp = listp->next; assert (listp != NULL); } - __rtld_lock_unlock_recursive (GL(dl_load_lock)); + __rtld_lock_unlock_recursive (GL(dl_load_tls_lock)); /* The DTV version is up-to-date now. */ dtv[0].counter = maxgen; @@ -745,7 +745,7 @@ _dl_update_slotinfo (unsigned long int req_modid) Here the dtv needs to be updated to new_gen generation count. - This code may be called during TLS access when GL(dl_load_lock) + This code may be called during TLS access when GL(dl_load_tls_lock) is not held. In that case the user code has to synchronize with dlopen and dlclose calls of relevant modules. A module m is relevant if the generation of m <= new_gen and dlclose of m is @@ -867,11 +867,11 @@ tls_get_addr_tail (GET_ADDR_ARGS, dtv_t *dtv, struct link_map *the_map) if (__glibc_unlikely (the_map->l_tls_offset != FORCED_DYNAMIC_TLS_OFFSET)) { - __rtld_lock_lock_recursive (GL(dl_load_lock)); + __rtld_lock_lock_recursive (GL(dl_load_tls_lock)); if (__glibc_likely (the_map->l_tls_offset == NO_TLS_OFFSET)) { the_map->l_tls_offset = FORCED_DYNAMIC_TLS_OFFSET; - __rtld_lock_unlock_recursive (GL(dl_load_lock)); + __rtld_lock_unlock_recursive (GL(dl_load_tls_lock)); } else if (__glibc_likely (the_map->l_tls_offset != FORCED_DYNAMIC_TLS_OFFSET)) @@ -883,7 +883,7 @@ tls_get_addr_tail (GET_ADDR_ARGS, dtv_t *dtv, struct link_map *the_map) #else # error "Either TLS_TCB_AT_TP or TLS_DTV_AT_TP must be defined" #endif - __rtld_lock_unlock_recursive (GL(dl_load_lock)); + __rtld_lock_unlock_recursive (GL(dl_load_tls_lock)); dtv[GET_ADDR_MODULE].pointer.to_free = NULL; dtv[GET_ADDR_MODULE].pointer.val = p; @@ -891,7 +891,7 @@ tls_get_addr_tail (GET_ADDR_ARGS, dtv_t *dtv, struct link_map *the_map) return (char *) p + GET_ADDR_OFFSET; } else - __rtld_lock_unlock_recursive (GL(dl_load_lock)); + __rtld_lock_unlock_recursive (GL(dl_load_tls_lock)); } struct dtv_pointer result = allocate_and_init (the_map); dtv[GET_ADDR_MODULE].pointer = result; @@ -962,7 +962,7 @@ _dl_tls_get_addr_soft (struct link_map *l) return NULL; dtv_t *dtv = THREAD_DTV (); - /* This may be called without holding the GL(dl_load_lock). Reading + /* This may be called without holding the GL(dl_load_tls_lock). Reading arbitrary gen value is fine since this is best effort code. */ size_t gen = atomic_load_relaxed (&GL(dl_tls_generation)); if (__glibc_unlikely (dtv[0].counter != gen)) @@ -322,6 +322,7 @@ struct rtld_global _rtld_global = #ifdef _LIBC_REENTRANT ._dl_load_lock = _RTLD_LOCK_RECURSIVE_INITIALIZER, ._dl_load_write_lock = _RTLD_LOCK_RECURSIVE_INITIALIZER, + ._dl_load_tls_lock = _RTLD_LOCK_RECURSIVE_INITIALIZER, #endif ._dl_nns = 1, ._dl_ns = |