Keep the list of DLLs that we dlopen
authorIan Lynagh <ian@well-typed.com>
Sat, 13 Oct 2012 15:18:41 +0000 (16:18 +0100)
committerIan Lynagh <ian@well-typed.com>
Sat, 13 Oct 2012 15:18:41 +0000 (16:18 +0100)
Unfortunately, dlsym finds the first symbol loaded, while when we reload
a compiled module in GHCi it's the last symbol that we want. Therefore
we remember the list of loaded DLLs ourselves and go through them in
order.

rts/Linker.c

index 4ae9193..2d7e7d7 100644 (file)
@@ -1588,9 +1588,32 @@ static OpenedDLL* opened_dlls = NULL;
 
 #  if defined(OBJFORMAT_ELF) || defined(OBJFORMAT_MACHO)
 
+/* Suppose in ghci we load a temporary SO for a module containing
+       f = 1
+   and then modify the module, recompile, and load another temporary
+   SO with
+       f = 2
+   Then as we don't unload the first SO, dlsym will find the
+       f = 1
+   symbol whereas we want the
+       f = 2
+   symbol. We therefore need to keep our own SO handle list, and
+   try SOs in the right order. */
+
+typedef
+   struct _OpenedSO {
+      struct _OpenedSO* next;
+      void *handle;
+   }
+   OpenedSO;
+
+/* A list thereof. */
+static OpenedSO* openedSOs = NULL;
+
 static const char *
 internal_dlopen(const char *dll_name)
 {
+   OpenedSO* o_so;
    void *hdl;
    const char *errmsg;
    char *errmsg_copy;
@@ -1618,11 +1641,36 @@ internal_dlopen(const char *dll_name)
       strcpy(errmsg_copy, errmsg);
       errmsg = errmsg_copy;
    }
+   o_so = stgMallocBytes(sizeof(OpenedSO), "addDLL");
+   o_so->handle = hdl;
+   o_so->next   = openedSOs;
+   openedSOs    = o_so;
+
    RELEASE_LOCK(&dl_mutex);
    //--------------- End critical section -------------------
 
    return errmsg;
 }
+
+static void *
+internal_dlsym(void *hdl, const char *symbol) {
+    OpenedSO* o_so;
+    void *v;
+
+    // We acquire dl_mutex as concurrent dl* calls may alter dlerror
+    ACQUIRE_LOCK(&dl_mutex);
+    dlerror();
+    for (o_so = openedSOs; o_so != NULL; o_so = o_so->next) {
+        v = dlsym(o_so->handle, symbol);
+        if (dlerror() == NULL) {
+            RELEASE_LOCK(&dl_mutex);
+            return v;
+        }
+    }
+    v = dlsym(hdl, symbol)
+    RELEASE_LOCK(&dl_mutex);
+    return v;
+}
 #  endif
 
 const char *
@@ -1798,7 +1846,7 @@ lookupSymbol( char *lbl )
     if (val == NULL) {
         IF_DEBUG(linker, debugBelch("lookupSymbol: symbol not found\n"));
 #       if defined(OBJFORMAT_ELF)
-        return dlsym(dl_prog_handle, lbl);
+        return internal_dlsym(dl_prog_handle, lbl);
 #       elif defined(OBJFORMAT_MACHO)
 #       if HAVE_DLFCN_H
         /* On OS X 10.3 and later, we use dlsym instead of the old legacy
@@ -1812,7 +1860,7 @@ lookupSymbol( char *lbl )
         */
         IF_DEBUG(linker, debugBelch("lookupSymbol: looking up %s with dlsym\n", lbl));
        ASSERT(lbl[0] == '_');
-       return dlsym(dl_prog_handle, lbl + 1);
+       return internal_dlsym(dl_prog_handle, lbl + 1);
 #       else
         if (NSIsSymbolNameDefined(lbl)) {
             NSSymbol symbol = NSLookupAndBindSymbol(lbl);