diff options
Diffstat (limited to '')
-rw-r--r-- | cpukit/libdl/rtl.c | 277 |
1 files changed, 219 insertions, 58 deletions
diff --git a/cpukit/libdl/rtl.c b/cpukit/libdl/rtl.c index fdf4c1229f..f331cbbf02 100644 --- a/cpukit/libdl/rtl.c +++ b/cpukit/libdl/rtl.c @@ -27,9 +27,10 @@ #include <rtems/rtl/rtl.h> #include <rtems/rtl/rtl-allocator.h> +#include <rtems/rtl/rtl-trace.h> +#include "rtl-chain-iterator.h" #include "rtl-error.h" #include "rtl-string.h" -#include <rtems/rtl/rtl-trace.h> /** * Symbol table cache size. They can be big so the cache needs space to work. @@ -123,10 +124,14 @@ rtems_rtl_data_init (void) rtems_recursive_mutex_lock (&rtl->lock); /* - * Initialise the objects list and create any required services. + * Initialise the objects and pending list. */ rtems_chain_initialize_empty (&rtl->objects); + rtems_chain_initialize_empty (&rtl->pending); + /* + * Open the global symbol table. + */ if (!rtems_rtl_symbol_table_open (&rtl->globals, RTEMS_RTL_SYMS_GLOBAL_BUCKETS)) { @@ -136,6 +141,14 @@ rtems_rtl_data_init (void) return false; } + /* + * Open the archives. + */ + rtems_rtl_archives_open (&rtl->archives, "/etc/rtl-libs.conf"); + + /* + * Open the unresolved table. + */ if (!rtems_rtl_unresolved_table_open (&rtl->unresolved, RTEMS_RTL_UNRESOLVED_BLOCK_SIZE)) { @@ -252,6 +265,28 @@ rtems_rtl_global_symbols (void) return &rtl->globals; } +rtems_chain_control* +rtems_rtl_objects_unprotected (void) +{ + if (!rtl) + { + rtems_rtl_set_error (ENOENT, "no rtl"); + return NULL; + } + return &rtl->objects; +} + +rtems_chain_control* +rtems_rtl_pending_unprotected (void) +{ + if (!rtl) + { + rtems_rtl_set_error (ENOENT, "no rtl"); + return NULL; + } + return &rtl->pending; +} + rtems_rtl_unresolved* rtems_rtl_unresolved_unprotected (void) { @@ -263,6 +298,17 @@ rtems_rtl_unresolved_unprotected (void) return &rtl->unresolved; } +rtems_rtl_archives* +rtems_rtl_archives_unprotected (void) +{ + if (!rtl) + { + rtems_rtl_set_error (ENOENT, "no rtl"); + return NULL; + } + return &rtl->archives; +} + void rtems_rtl_obj_caches (rtems_rtl_obj_cache** symbols, rtems_rtl_obj_cache** strings, @@ -317,19 +363,34 @@ rtems_rtl_obj_decompress (rtems_rtl_obj_comp** decomp, } } +typedef struct rtems_rtl_obj_flags_data +{ + uint32_t clear; /**< Flags to clear, do not invert. */ + uint32_t set; /**< Flags to set, applied after clearing. */ +} rtems_rtl_obj_flags_data; + +static bool +rtems_rtl_obj_flags_iterator (rtems_chain_node* node, void* data) +{ + rtems_rtl_obj* obj = (rtems_rtl_obj*) node; + rtems_rtl_obj_flags_data* flags = (rtems_rtl_obj_flags_data*) data; + if (flags->clear != 0) + obj->flags &= ~flags->clear; + if (flags->set != 0) + obj->flags |= flags->set; + return true; +} + void rtems_rtl_obj_update_flags (uint32_t clear, uint32_t set) { - rtems_chain_node* node = rtems_chain_first (&rtl->objects); - while (!rtems_chain_is_tail (&rtl->objects, node)) - { - rtems_rtl_obj* obj = (rtems_rtl_obj*) node; - if (clear != 0) - obj->flags &= ~clear; - if (set != 0) - obj->flags |= set; - node = rtems_chain_next (node); - } + rtems_rtl_obj_flags_data flags = { + .clear = clear, + .set = set + }; + rtems_rtl_chain_iterate (&rtl->objects, + rtems_rtl_obj_flags_iterator, + &flags); } rtems_rtl_data* @@ -390,16 +451,16 @@ rtems_rtl_find_obj (const char* name) (aname != NULL && strcmp (obj->aname, aname) == 0 && strcmp (obj->oname, oname) == 0)) { - found = obj; - break; + found = obj; + break; } node = rtems_chain_next (node); } - if (!aname) + if (aname != NULL) rtems_rtl_alloc_del(RTEMS_RTL_ALLOC_OBJECT, (void*) aname); - if (!oname) + if (oname != NULL) rtems_rtl_alloc_del(RTEMS_RTL_ALLOC_OBJECT, (void*) oname); return found; @@ -412,8 +473,15 @@ rtems_rtl_find_obj_with_symbol (const rtems_rtl_obj_sym* sym) while (!rtems_chain_is_tail (&rtl->objects, node)) { rtems_rtl_obj* obj = (rtems_rtl_obj*) node; - if (sym >= obj->global_table && - sym < (obj->global_table + obj->global_syms)) + if (rtems_rtl_obj_has_symbol (obj, sym)) + return obj; + node = rtems_chain_next (node); + } + node = rtems_chain_first (&rtl->pending); + while (!rtems_chain_is_tail (&rtl->pending, node)) + { + rtems_rtl_obj* obj = (rtems_rtl_obj*) node; + if (rtems_rtl_obj_has_symbol (obj, sym)) return obj; node = rtems_chain_next (node); } @@ -455,18 +523,17 @@ rtems_rtl_load_object (const char* name, int mode) return NULL; } - rtems_chain_append (&rtl->objects, &obj->link); + rtems_chain_append (&rtl->pending, &obj->link); if (!rtems_rtl_obj_load (obj)) { + rtems_chain_extract (&obj->link); rtems_rtl_obj_free (obj); rtems_rtl_obj_caches_flush (); return NULL; } rtems_rtl_obj_caches_flush (); - - rtems_rtl_unresolved_resolve (); } /* @@ -474,25 +541,67 @@ rtems_rtl_load_object (const char* name, int mode) */ ++obj->users; + return obj; +} + +rtems_rtl_obj* +rtems_rtl_load (const char* name, int mode) +{ + rtems_rtl_obj* obj; + /* - * FIXME: Resolving existing unresolved symbols could add more constructors - * lists that need to be called. Make a list in the obj load layer and - * invoke the list here. + * Refesh the archives. */ + rtems_rtl_archives_refresh (&rtl->archives); /* - * Run any local constructors if this is the first user because the object - * file will have just been loaded. Unlock the linker to avoid any dead locks - * if the object file needs to load files or update the symbol table. We also - * do not want a constructor to unload this object file. + * Collect the loaded object files. */ - if (obj->users == 1) + rtems_chain_initialize_empty (&rtl->pending); + + obj = rtems_rtl_load_object (name, mode); + if (obj != NULL) { - obj->flags |= RTEMS_RTL_OBJ_LOCKED; - rtems_rtl_unlock (); - rtems_rtl_obj_run_ctors (obj); - rtems_rtl_lock (); - obj->flags &= ~RTEMS_RTL_OBJ_LOCKED; + rtems_chain_node* node; + + rtems_rtl_unresolved_resolve (); + + /* + * Iterator over the pending list of object files that have been loaded. + */ + node = rtems_chain_first (&rtl->pending); + while (!rtems_chain_is_tail (&rtl->pending, node)) + { + rtems_rtl_obj* obj = (rtems_rtl_obj*) node; + + /* + * Move to the next pending object file and place this object file on the + * RTL's objects list. + */ + node = rtems_chain_next (&obj->link); + rtems_chain_extract (&obj->link); + rtems_chain_append (&rtl->objects, &obj->link); + + /* + * Make sure the object file and cache is synchronized. + */ + rtems_rtl_obj_synchronize_cache (obj); + + /* + * Run any local constructors if this is the first user because the + * object file will have just been loaded. Unlock the linker to avoid any + * dead locks if the object file needs to load files or update the symbol + * table. We also do not want a constructor to unload this object file. + */ + if (obj->users == 1) + { + obj->flags |= RTEMS_RTL_OBJ_LOCKED; + rtems_rtl_unlock (); + rtems_rtl_obj_run_ctors (obj); + rtems_rtl_lock (); + obj->flags &= ~RTEMS_RTL_OBJ_LOCKED; + } + } } return obj; @@ -501,55 +610,107 @@ rtems_rtl_load_object (const char* name, int mode) bool rtems_rtl_unload_object (rtems_rtl_obj* obj) { - bool ok = true; - if (rtems_rtl_trace (RTEMS_RTL_TRACE_UNLOAD)) - printf ("rtl: unloading '%s'\n", rtems_rtl_obj_fname (obj)); + printf ("rtl: unload object '%s'\n", rtems_rtl_obj_fname (obj)); /* * If the object is locked it cannot be unloaded and the unload fails. */ if ((obj->flags & RTEMS_RTL_OBJ_LOCKED) == RTEMS_RTL_OBJ_LOCKED) { - rtems_rtl_set_error (EINVAL, "cannot unload when locked"); + rtems_rtl_set_error (EINVAL, "object file is locked"); return false; } /* - * Check the number of users in a safe manner. If this is the last user unload the - * object file from memory. + * Move the object file from the objects list to the pending list if unloaded. + */ + if (rtems_rtl_obj_get_reference (obj) > 0) + { + rtems_rtl_set_error (EINVAL, "object file has references to it"); + return false; + } + + /* + * Check the number of users in a safe manner. If this is the last user unload + * the object file from memory. */ if (obj->users > 0) --obj->users; - if (obj->users == 0) + return true; +} + +bool +rtems_rtl_unload (rtems_rtl_obj* obj) +{ + bool ok = rtems_rtl_unload_object (obj); + if (ok && obj->users == 0) { - if (obj->refs != 0) + rtems_chain_control unloading; + rtems_chain_node* node; + + /* + * Remove the orphaned object files from the objects list. This makes the + * list private and any changes in any desctructors will effect the run. + */ + rtems_chain_initialize_empty (&unloading); + + node = rtems_chain_first (&rtl->objects); + while (!rtems_chain_is_tail (&rtl->objects, node)) { - rtems_rtl_set_error (EBUSY, "object file referenced"); - return false; + rtems_chain_node* next_node = rtems_chain_next (node); + rtems_rtl_obj* uobj = (rtems_rtl_obj*) node; + if (rtems_rtl_trace (RTEMS_RTL_TRACE_UNLOAD)) + printf ("rtl: unload object: %s: %s\n", + rtems_rtl_obj_oname (obj), + rtems_rtl_obj_orphaned (uobj) ? "orphaned" : "inuse"); + if (rtems_rtl_obj_orphaned (uobj)) + { + rtems_rtl_obj_remove_dependencies (uobj); + rtems_chain_extract (&uobj->link); + rtems_chain_append (&unloading, &uobj->link); + uobj->flags |= RTEMS_RTL_OBJ_LOCKED; + } + node = next_node; } - obj->flags |= RTEMS_RTL_OBJ_LOCKED; + + /* + * Call the desctructors unlocked. An RTL call will not deadlock. + */ rtems_rtl_unlock (); - rtems_rtl_obj_run_dtors (obj); - rtems_rtl_lock (); - obj->flags &= ~RTEMS_RTL_OBJ_LOCKED; - ok = rtems_rtl_obj_unload (obj); + node = rtems_chain_first (&unloading); + while (!rtems_chain_is_tail (&unloading, node)) + { + rtems_rtl_obj* uobj = (rtems_rtl_obj*) node; + rtems_rtl_obj_run_dtors (uobj); + node = rtems_chain_next (node); + } - rtems_rtl_obj_free (obj); - rtems_rtl_obj_caches_flush (); - } + rtems_rtl_lock (); + /* + * Unload the object files. + */ + node = rtems_chain_first (&unloading); + while (!rtems_chain_is_tail (&unloading, node)) + { + rtems_chain_node* next_node = rtems_chain_next (node); + rtems_rtl_obj* uobj = (rtems_rtl_obj*) node; + if (rtems_rtl_trace (RTEMS_RTL_TRACE_UNLOAD)) + printf ("rtl: unloading '%s'\n", rtems_rtl_obj_oname (uobj)); + uobj->flags &= ~RTEMS_RTL_OBJ_LOCKED; + if (!rtems_rtl_obj_unload (uobj)) + ok = false; + rtems_rtl_obj_free (uobj); + rtems_rtl_obj_caches_flush (); + node = next_node; + } + } return ok; } -void -rtems_rtl_run_ctors (rtems_rtl_obj* obj) -{ - rtems_rtl_obj_run_ctors (obj); -} - static bool rtems_rtl_path_update (bool prepend, const char* path) { |