diff options
author | Chris Johns <chrisj@rtems.org> | 2018-11-20 14:56:11 +1100 |
---|---|---|
committer | Chris Johns <chrisj@rtems.org> | 2018-11-22 12:43:31 +1100 |
commit | 03139d5b1cf95d5b2f699e8f56e1f0ba2d7f89e4 (patch) | |
tree | 33fd489eac7497cdebe61560bc43e613b3eef0a9 /cpukit/libdl/rtl-obj.c | |
parent | libdl: Reindex unresolved names after removing used records. (diff) | |
download | rtems-03139d5b1cf95d5b2f699e8f56e1f0ba2d7f89e4.tar.bz2 |
libdl: Add object file dependencies to track references
Tracking references lets us manage when an object file can be
unloaded. If an object file has references to it, it cannot be
unloaded.
Modules that depend on each other cannot be unloaded.
Updates #3605
Diffstat (limited to 'cpukit/libdl/rtl-obj.c')
-rw-r--r-- | cpukit/libdl/rtl-obj.c | 141 |
1 files changed, 140 insertions, 1 deletions
diff --git a/cpukit/libdl/rtl-obj.c b/cpukit/libdl/rtl-obj.c index 7109b86fe8..0f58bf9bda 100644 --- a/cpukit/libdl/rtl-obj.c +++ b/cpukit/libdl/rtl-obj.c @@ -83,6 +83,7 @@ rtems_rtl_obj_alloc (void) * Initialise the chains. */ rtems_chain_initialize_empty (&obj->sections); + rtems_chain_initialize_empty (&obj->dependents); /* * No valid format. */ @@ -114,6 +115,8 @@ rtems_rtl_obj_free (rtems_rtl_obj* obj) rtems_chain_extract (&obj->link); rtems_rtl_alloc_module_del (&obj->text_base, &obj->const_base, &obj->eh_base, &obj->data_base, &obj->bss_base); + rtems_rtl_obj_erase_sections (obj); + rtems_rtl_obj_erase_dependents (obj); rtems_rtl_symbol_obj_erase (obj); rtems_rtl_obj_free_names (obj); if (obj->sec_num) @@ -550,6 +553,110 @@ rtems_rtl_obj_find_section_by_mask (const rtems_rtl_obj* obj, return match.sect; } +bool +rtems_rtl_obj_alloc_dependents (rtems_rtl_obj* obj, size_t dependents) +{ + rtems_rtl_obj_depends* depends; + size_t size; + + size = sizeof (rtems_rtl_obj_depends) + sizeof (rtems_rtl_obj*) * dependents; + + depends = rtems_rtl_alloc_new (RTEMS_RTL_ALLOC_OBJECT, + size, + true); + if (depends == NULL) + { + rtems_rtl_set_error (ENOMEM, "no memory for the dependency"); + } + else + { + depends->dependents = dependents; + rtems_chain_append (&obj->dependents, &depends->node); + } + + return depends != NULL; +} + +void +rtems_rtl_obj_erase_dependents (rtems_rtl_obj* obj) +{ + rtems_chain_node* node = rtems_chain_first (&obj->dependents); + while (!rtems_chain_is_tail (&obj->dependents, node)) + { + rtems_rtl_obj_depends* depends = (rtems_rtl_obj_depends*) node; + rtems_chain_node* next_node = rtems_chain_next (node); + rtems_chain_extract (node); + rtems_rtl_alloc_del (RTEMS_RTL_ALLOC_OBJECT, depends); + node = next_node; + } +} + +bool +rtems_rtl_obj_add_dependent (rtems_rtl_obj* obj, rtems_rtl_obj* dependent) +{ + rtems_rtl_obj** free_slot; + rtems_chain_node* node; + if (obj == dependent || dependent == rtems_rtl_baseimage ()) + return false; + free_slot = NULL; + node = rtems_chain_first (&obj->dependents); + while (!rtems_chain_is_tail (&obj->dependents, node)) + { + rtems_rtl_obj_depends* depends = (rtems_rtl_obj_depends*) node; + size_t d; + for (d = 0; d < depends->dependents; ++d) + { + if (free_slot == NULL && depends->depends[d] == NULL) + free_slot = &(depends->depends[d]); + if (depends->depends[d] == dependent) + return false; + } + node = rtems_chain_next (node); + } + if (free_slot == NULL) + { + if (rtems_rtl_obj_alloc_dependents (obj, + RTEMS_RTL_DEPENDENCY_BLOCK_SIZE)) + { + rtems_rtl_obj_depends* depends; + node = rtems_chain_last (&obj->dependents); + depends = (rtems_rtl_obj_depends*) node; + free_slot = &(depends->depends[0]); + if (*free_slot != NULL) + { + rtems_rtl_set_error (EINVAL, "new dependency node not empty"); + free_slot = NULL; + } + } + } + if (free_slot != NULL) + *free_slot = dependent; + return free_slot != NULL; +} + +bool +rtems_rtl_obj_iterate_dependents (rtems_rtl_obj* obj, + rtems_rtl_obj_depends_iterator iterator, + void* data) +{ + rtems_chain_node* node = rtems_chain_first (&obj->dependents); + while (!rtems_chain_is_tail (&obj->dependents, node)) + { + rtems_rtl_obj_depends* depends = (rtems_rtl_obj_depends*) node; + size_t d; + for (d = 0; d < depends->dependents; ++d) + { + if (depends->depends[d]) + { + if (iterator (obj, depends->depends[d], data)) + return true; + } + } + node = rtems_chain_next (node); + } + return false; +} + size_t rtems_rtl_obj_text_size (const rtems_rtl_obj* obj) { @@ -1220,10 +1327,42 @@ static bool rtems_rtl_obj_file_unload (rtems_rtl_obj* obj) { if (obj->format >= 0 && obj->format < RTEMS_RTL_LOADERS) - return loaders[obj->format].unload (obj); + { + rtems_chain_node* node; + + if (!loaders[obj->format].unload (obj)) + return false; + + node = rtems_chain_first (&obj->dependents); + while (!rtems_chain_is_tail (&obj->dependents, node)) + { + rtems_rtl_obj_depends* depends = (rtems_rtl_obj_depends*) node; + size_t d; + for (d = 0; d < depends->dependents; ++d) + { + if (depends->depends[d] != NULL) + rtems_rtl_obj_dec_reference (depends->depends[d]); + } + node = rtems_chain_next (node); + } + } + return false; } +void +rtems_rtl_obj_inc_reference (rtems_rtl_obj* obj) +{ + ++obj->refs; +} + +void +rtems_rtl_obj_dec_reference (rtems_rtl_obj* obj) +{ + if (obj->refs) + --obj->refs; +} + bool rtems_rtl_obj_load (rtems_rtl_obj* obj) { |