Move cache_sections' reloc_info initialization code into new function cache_sections_locked, which cache_sections calls while holding dwfl->load_lock.
Atomics are used to acquire intitialized reloc_info without needing to obtain the load_lock. Signed-off-by: Aaron Merey <[email protected]> --- libdwfl/derelocate.c | 53 ++++++++++++++++++++++++++++++++------------ 1 file changed, 39 insertions(+), 14 deletions(-) diff --git a/libdwfl/derelocate.c b/libdwfl/derelocate.c index 2f80b20f..f9dbbe55 100644 --- a/libdwfl/derelocate.c +++ b/libdwfl/derelocate.c @@ -77,13 +77,11 @@ compare_secrefs (const void *a, const void *b) } static int -cache_sections (Dwfl_Module *mod) +cache_sections_locked (Dwfl_Module *mod, struct dwfl_relocation **result) { - if (likely (mod->reloc_info != NULL)) - return mod->reloc_info->count; - struct secref *refs = NULL; size_t nrefs = 0; + struct dwfl_relocation *reloc_info = NULL; size_t shstrndx; if (unlikely (elf_getshdrstrndx (mod->main.elf, &shstrndx) < 0)) @@ -165,8 +163,8 @@ cache_sections (Dwfl_Module *mod) } } - mod->reloc_info = malloc (offsetof (struct dwfl_relocation, refs[nrefs])); - if (unlikely (mod->reloc_info == NULL)) + reloc_info = malloc (offsetof (struct dwfl_relocation, refs[nrefs])); + if (unlikely (reloc_info == NULL)) goto nomem; struct secref **sortrefs = malloc (nrefs * sizeof sortrefs[0]); @@ -179,14 +177,14 @@ cache_sections (Dwfl_Module *mod) qsort (sortrefs, nrefs, sizeof sortrefs[0], &compare_secrefs); - mod->reloc_info->count = nrefs; + reloc_info->count = nrefs; for (size_t i = 0; i < nrefs; ++i) { - mod->reloc_info->refs[i].name = sortrefs[i]->name; - mod->reloc_info->refs[i].scn = sortrefs[i]->scn; - mod->reloc_info->refs[i].relocs = sortrefs[i]->relocs; - mod->reloc_info->refs[i].start = sortrefs[i]->start; - mod->reloc_info->refs[i].end = sortrefs[i]->end; + reloc_info->refs[i].name = sortrefs[i]->name; + reloc_info->refs[i].scn = sortrefs[i]->scn; + reloc_info->refs[i].relocs = sortrefs[i]->relocs; + reloc_info->refs[i].start = sortrefs[i]->start; + reloc_info->refs[i].end = sortrefs[i]->end; free (sortrefs[i]); } @@ -212,16 +210,20 @@ cache_sections (Dwfl_Module *mod) Elf_Scn *tscn = elf_getscn (mod->main.elf, shdr->sh_info); if (likely (tscn != NULL)) for (size_t i = 0; i < nrefs; ++i) - if (mod->reloc_info->refs[i].scn == tscn) + if (reloc_info->refs[i].scn == tscn) { - mod->reloc_info->refs[i].relocs = scn; + reloc_info->refs[i].relocs = scn; break; } } } } + *result = reloc_info; + reloc_info = NULL; + free_refs: + free (reloc_info); while (refs != NULL) { struct secref *ref = refs; @@ -232,6 +234,29 @@ free_refs: return nrefs; } +static int +cache_sections (Dwfl_Module *mod) +{ + if (likely (atomic_load_acquire (&mod->reloc_info) != NULL)) + return mod->reloc_info->count; + + int count; + mutex_lock (mod->dwfl->load_lock); + + if (mod->reloc_info == NULL) + { + struct dwfl_relocation *reloc_info = NULL; + count = cache_sections_locked (mod, &reloc_info); + if (count >= 0) + atomic_store_release (&mod->reloc_info, reloc_info); + } + else + count = mod->reloc_info->count; + + mutex_unlock (mod->dwfl->load_lock); + return count; +} + int dwfl_module_relocations (Dwfl_Module *mod) -- 2.56.0
