Use a CFI cache's corresponding dwfl load_lock to serialize its
initialization.  Rename __libdwfl_set_cfi to __libdwfl_set_cfi_locked
to indicate that the caller must hold the load_lock.   Atomics are used
to acquire an initialized CFI cache without needing to obtain the
load_lock.

Signed-off-by: Aaron Merey <[email protected]>
---
 libdwfl/dwfl_module.c           |  2 +-
 libdwfl/dwfl_module_dwarf_cfi.c | 25 ++++++++++++++++++-------
 libdwfl/dwfl_module_eh_cfi.c    | 26 ++++++++++++++++++--------
 libdwfl/libdwflP.h              |  7 ++++---
 4 files changed, 41 insertions(+), 19 deletions(-)

diff --git a/libdwfl/dwfl_module.c b/libdwfl/dwfl_module.c
index b4ddf806..27e6c064 100644
--- a/libdwfl/dwfl_module.c
+++ b/libdwfl/dwfl_module.c
@@ -74,7 +74,7 @@ __libdwfl_module_free (Dwfl_Module *mod)
     }
 
   /* We might have primed the Dwarf_CFI ebl cache with our own ebl
-     in __libdwfl_set_cfi. Make sure we don't free it twice.  */
+     in __libdwfl_set_cfi_locked. Make sure we don't free it twice.  */
   if (mod->eh_cfi != NULL)
     {
       if (mod->eh_cfi->ebl != NULL && mod->eh_cfi->ebl == mod->ebl)
diff --git a/libdwfl/dwfl_module_dwarf_cfi.c b/libdwfl/dwfl_module_dwarf_cfi.c
index 05a14f7c..2da02b32 100644
--- a/libdwfl/dwfl_module_dwarf_cfi.c
+++ b/libdwfl/dwfl_module_dwarf_cfi.c
@@ -35,7 +35,7 @@
 
 Dwarf_CFI *
 internal_function
-__libdwfl_set_cfi (Dwfl_Module *mod, Dwarf_CFI **slot, Dwarf_CFI *cfi)
+__libdwfl_set_cfi_locked (Dwfl_Module *mod, Dwarf_CFI **slot, Dwarf_CFI *cfi)
 {
   if (cfi != NULL && cfi->ebl == NULL)
     {
@@ -51,7 +51,9 @@ __libdwfl_set_cfi (Dwfl_Module *mod, Dwarf_CFI **slot, 
Dwarf_CFI *cfi)
        }
     }
 
-  return *slot = cfi;
+  if (cfi != NULL)
+    atomic_store_release (slot, cfi);
+  return cfi;
 }
 
 Dwarf_CFI *
@@ -60,14 +62,23 @@ dwfl_module_dwarf_cfi (Dwfl_Module *mod, Dwarf_Addr *bias)
   if (mod == NULL)
     return NULL;
 
-  if (mod->dwarf_cfi != NULL)
+  Dwarf_CFI *cfi = atomic_load_acquire (&mod->dwarf_cfi);
+  if (cfi != NULL)
     {
       *bias = dwfl_adjusted_dwarf_addr (mod, 0);
-      return mod->dwarf_cfi;
+      return cfi;
     }
 
-  return __libdwfl_set_cfi (mod, &mod->dwarf_cfi,
-                           INTUSE(dwarf_getcfi)
-                           (INTUSE(dwfl_module_getdwarf) (mod, bias)));
+  mutex_lock (mod->dwfl->load_lock);
+  cfi = mod->dwarf_cfi;
+  if (cfi == NULL)
+    cfi = __libdwfl_set_cfi_locked (mod, &mod->dwarf_cfi,
+                                   INTUSE(dwarf_getcfi)
+                                   (INTUSE(dwfl_module_getdwarf) (mod, bias)));
+  else
+    *bias = dwfl_adjusted_dwarf_addr (mod, 0);
+
+  mutex_unlock (mod->dwfl->load_lock);
+  return cfi;
 }
 INTDEF (dwfl_module_dwarf_cfi)
diff --git a/libdwfl/dwfl_module_eh_cfi.c b/libdwfl/dwfl_module_eh_cfi.c
index aac6657d..cc28ad60 100644
--- a/libdwfl/dwfl_module_eh_cfi.c
+++ b/libdwfl/dwfl_module_eh_cfi.c
@@ -39,21 +39,31 @@ dwfl_module_eh_cfi (Dwfl_Module *mod, Dwarf_Addr *bias)
   if (mod == NULL)
     return NULL;
 
-  if (mod->eh_cfi != NULL)
+  Dwarf_CFI *cfi = atomic_load_acquire (&mod->eh_cfi);
+  if (cfi != NULL)
     {
       *bias = dwfl_adjusted_address (mod, 0);
-      return mod->eh_cfi;
+      return cfi;
     }
 
-  __libdwfl_getelf (mod);
-  if (mod->elferr != DWFL_E_NOERROR)
+  mutex_lock (mod->dwfl->load_lock);
+  cfi = mod->eh_cfi;
+  if (cfi == NULL)
     {
-      __libdwfl_seterrno (mod->elferr);
-      return NULL;
+      __libdwfl_getelf (mod);
+      if (mod->elferr != DWFL_E_NOERROR)
+       {
+         __libdwfl_seterrno (mod->elferr);
+         mutex_unlock (mod->dwfl->load_lock);
+         return NULL;
+       }
+
+      cfi = __libdwfl_set_cfi_locked (mod, &mod->eh_cfi,
+                                     INTUSE(dwarf_getcfi_elf) (mod->main.elf));
     }
 
+  mutex_unlock (mod->dwfl->load_lock);
   *bias = dwfl_adjusted_address (mod, 0);
-  return __libdwfl_set_cfi (mod, &mod->eh_cfi,
-                           INTUSE(dwarf_getcfi_elf) (mod->main.elf));
+  return cfi;
 }
 INTDEF (dwfl_module_eh_cfi)
diff --git a/libdwfl/libdwflP.h b/libdwfl/libdwflP.h
index 7a181029..56014ff6 100644
--- a/libdwfl/libdwflP.h
+++ b/libdwfl/libdwflP.h
@@ -521,9 +521,10 @@ extern Dwfl_Error __libdwfl_relocate_value (Dwfl_Module 
*mod, Elf *elf,
 /* Ensure that MOD->ebl is set up.  */
 extern Dwfl_Error __libdwfl_module_getebl (Dwfl_Module *mod) internal_function;
 
-/* Install a new Dwarf_CFI in *SLOT (MOD->eh_cfi or MOD->dwarf_cfi).  */
-extern Dwarf_CFI *__libdwfl_set_cfi (Dwfl_Module *mod, Dwarf_CFI **slot,
-                                    Dwarf_CFI *cfi)
+/* Install a new Dwarf_CFI in *SLOT (MOD->eh_cfi or MOD->dwarf_cfi).
+   MOD->dwfl->load_lock must be held by the caller.  */
+extern Dwarf_CFI *__libdwfl_set_cfi_locked (Dwfl_Module *mod, Dwarf_CFI **slot,
+                                           Dwarf_CFI *cfi)
   internal_function;
 
 /* Iterate through all the CU's in the module.  Start by passing a null
-- 
2.56.0

Reply via email to