lock files that are to be finied so that they are not finied twice. draft
authorMathieu Lacage <mathieu.lacage@alcmeon.com>
Sun, 17 Feb 2013 15:33:23 +0100
changeset 652 2653fbff9e35
parent 651 9d7e2cd9633b
child 653 5cb8918ff4cf
lock files that are to be finied so that they are not finied twice.
stage2.c
vdl-dl.c
vdl-file.h
vdl-fini.c
vdl-fini.h
vdl-map.c
--- a/stage2.c	Wed Feb 13 22:37:34 2013 +0900
+++ b/stage2.c	Sun Feb 17 15:33:23 2013 +0100
@@ -328,7 +328,9 @@
   // in the correct order.
   struct VdlList *link_map = vdl_linkmap_copy ();
   struct VdlList *call_fini = vdl_sort_call_fini (link_map);
-  vdl_fini_call (call_fini);
+  struct VdlList *locked = vdl_fini_lock(call_fini);
+  vdl_fini_call (locked);
+  vdl_list_delete (locked);
   vdl_list_delete (call_fini);
   vdl_list_delete (link_map);
 }
--- a/vdl-dl.c	Wed Feb 13 22:37:34 2013 +0900
+++ b/vdl-dl.c	Sun Feb 17 15:33:23 2013 +0100
@@ -357,23 +357,25 @@
   }
 
   struct VdlList *call_fini = vdl_sort_call_fini (gc.unload);
+  struct VdlList *locked = vdl_fini_lock(call_fini);
+  vdl_list_delete(call_fini);
+  call_fini = locked;
 
   // must not hold the lock to call fini
   futex_unlock (g_vdl.futex);
   vdl_fini_call (call_fini);
   futex_lock (g_vdl.futex);
 
-  vdl_list_delete (call_fini);
-
-  vdl_tls_file_deinitialize (gc.unload);
+  vdl_tls_file_deinitialize (call_fini);
 
   // update the linkmap before unmapping
-  vdl_linkmap_remove_range (vdl_list_begin (gc.unload),
-			    vdl_list_end (gc.unload));
+  vdl_linkmap_remove_range (vdl_list_begin (call_fini),
+			    vdl_list_end (call_fini));
 
   // now, unmap
-  vdl_unmap (gc.unload, true);
+  vdl_unmap (call_fini, true);
 
+  vdl_list_delete (call_fini);
   vdl_list_delete (gc.unload);
   vdl_list_delete (gc.not_unload);
 
--- a/vdl-file.h	Wed Feb 13 22:37:34 2013 +0900
+++ b/vdl-file.h	Sun Feb 17 15:33:23 2013 +0100
@@ -98,6 +98,9 @@
   // indicates if the ELF initializers of this file
   // have been called.
   uint32_t init_called : 1;
+  // indicates that the ELF finalizers of this file are
+  // going to be called.
+  uint32_t fini_call_lock : 1;
   // indicates if the ELF finalizers of this file
   // have been called.
   uint32_t fini_called : 1;
--- a/vdl-fini.c	Wed Feb 13 22:37:34 2013 +0900
+++ b/vdl-fini.c	Sun Feb 17 15:33:23 2013 +0100
@@ -43,13 +43,37 @@
   if (file->dt_fini != 0)
     {
       DtFini dt_fini = (DtFini) file->load_base + file->dt_fini;
-      VDL_LOG_DEBUG("call_fini debug4\n");
       dt_fini ();
     }
 
   vdl_context_notify (file->context, file, VDL_EVENT_DESTROYED);
 }
 
+struct VdlList *vdl_fini_lock (struct VdlList *files)
+{
+  // Make sure that we have not already planed to call fini
+  // on these files
+  struct VdlList *locked = vdl_list_new();
+  {
+    void **cur;
+    for (cur = vdl_list_begin (files);
+	 cur != vdl_list_end (files);
+	 cur = vdl_list_next (cur))
+      {
+	struct VdlFile *file = *cur;
+	if (file->fini_call_lock == 1)
+	  {
+	    // already locked. ignore
+	    continue;
+	  }
+	file->fini_call_lock = 1;
+	vdl_list_push_back (locked, file);
+      }
+  }
+  return locked;
+}
+
+
 void vdl_fini_call (struct VdlList *files)
 {
   vdl_list_iterate (files, (void(*)(void*))call_fini);
--- a/vdl-fini.h	Wed Feb 13 22:37:34 2013 +0900
+++ b/vdl-fini.h	Sun Feb 17 15:33:23 2013 +0100
@@ -3,6 +3,7 @@
 
 struct VdlList;
 
+struct VdlList *vdl_fini_lock (struct VdlList *files);
 void vdl_fini_call (struct VdlList *files);
 
 #endif /* VDL_FINI_H */
--- a/vdl-map.c	Wed Feb 13 22:37:34 2013 +0900
+++ b/vdl-map.c	Sun Feb 17 15:33:23 2013 +0100
@@ -335,6 +335,7 @@
   file->deps_initialized = 0;
   file->tls_initialized = 0;
   file->init_called = 0;
+  file->fini_call_lock = 0;
   file->fini_called = 0;
   file->reloced = 0;
   file->patched = 0;