summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIan Lynagh <ian@well-typed.com>2012-10-13 16:18:41 +0100
committerIan Lynagh <ian@well-typed.com>2012-10-13 16:18:41 +0100
commitbe497c202b790999c3fd0ddc4a4176b8cf6acf7e (patch)
tree8e3185027c6ee8e6ffa06120bbd6aba37094afa0
parent76410f7face73050551b28f92e45e523f4dabdae (diff)
downloadhaskell-be497c202b790999c3fd0ddc4a4176b8cf6acf7e.tar.gz
Keep the list of DLLs that we dlopen
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.
-rw-r--r--rts/Linker.c52
1 files changed, 50 insertions, 2 deletions
diff --git a/rts/Linker.c b/rts/Linker.c
index 4ae9193a11..2d7e7d78a7 100644
--- a/rts/Linker.c
+++ b/rts/Linker.c
@@ -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);