summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSimon Marlow <marlowsd@gmail.com>2013-09-22 13:08:01 +0100
committerSimon Marlow <marlowsd@gmail.com>2013-09-23 10:58:35 +0100
commit1908195261ccf16b0f3d2e77ebd5cd40c9e29cbc (patch)
treed0daabd85293a3a12749d7a277f2526576c851df
parentf5879acd018494b84233f26fba828ce376d0f81d (diff)
downloadhaskell-1908195261ccf16b0f3d2e77ebd5cd40c9e29cbc.tar.gz
Fix linker_unload now that we are running constructors in the linker (#8291)
See also #5435. Now we have to remember the the StablePtrs that get created by the module initializer so that we can free them again in unloadObj().
-rw-r--r--compiler/deSugar/DsForeign.lhs2
-rw-r--r--includes/rts/Linker.h3
-rw-r--r--rts/Linker.c49
-rw-r--r--rts/LinkerInternals.h13
4 files changed, 66 insertions, 1 deletions
diff --git a/compiler/deSugar/DsForeign.lhs b/compiler/deSugar/DsForeign.lhs
index c7cc13f598..e2f4f4ff3c 100644
--- a/compiler/deSugar/DsForeign.lhs
+++ b/compiler/deSugar/DsForeign.lhs
@@ -676,7 +676,7 @@ foreignExportInitialiser hs_fn =
[ text "static void stginit_export_" <> ppr hs_fn
<> text "() __attribute__((constructor));"
, text "static void stginit_export_" <> ppr hs_fn <> text "()"
- , braces (text "getStablePtr"
+ , braces (text "foreignExportStablePtr"
<> parens (text "(StgPtr) &" <> ppr hs_fn <> text "_closure")
<> semi)
]
diff --git a/includes/rts/Linker.h b/includes/rts/Linker.h
index 28f0a0e928..2e88fe4015 100644
--- a/includes/rts/Linker.h
+++ b/includes/rts/Linker.h
@@ -49,4 +49,7 @@ HsInt resolveObjs( void );
/* load a dynamic library */
const char *addDLL( pathchar* dll_name );
+/* called by the initialization code for a module, not a user API */
+StgStablePtr foreignExportStablePtr (StgPtr p);
+
#endif /* RTS_LINKER_H */
diff --git a/rts/Linker.c b/rts/Linker.c
index 31f60c09ac..7334a806af 100644
--- a/rts/Linker.c
+++ b/rts/Linker.c
@@ -1116,6 +1116,7 @@ typedef struct _RtsSymbolVal {
SymI_HasProto(getProgArgv) \
SymI_HasProto(getFullProgArgv) \
SymI_HasProto(getStablePtr) \
+ SymI_HasProto(foreignExportStablePtr) \
SymI_HasProto(hs_init) \
SymI_HasProto(hs_exit) \
SymI_HasProto(hs_set_argv) \
@@ -1948,6 +1949,37 @@ lookupSymbol( char *lbl )
}
/* -----------------------------------------------------------------------------
+ Create a StablePtr for a foeign export. This is normally called by
+ a C function with __attribute__((constructor)), which is generated
+ by GHC and linked into the module.
+
+ If the object code is being loaded dynamically, then we remember
+ which StablePtrs were allocated by the constructors and free them
+ again in unloadObj().
+ -------------------------------------------------------------------------- */
+
+static ObjectCode *loading_obj = NULL;
+
+StgStablePtr foreignExportStablePtr (StgPtr p)
+{
+ ForeignExportStablePtr *fe_sptr;
+ StgStablePtr *sptr;
+
+ sptr = getStablePtr(p);
+
+ if (loading_obj != NULL) {
+ fe_sptr = stgMallocBytes(sizeof(ForeignExportStablePtr),
+ "foreignExportStablePtr");
+ fe_sptr->stable_ptr = sptr;
+ fe_sptr->next = loading_obj->stable_ptrs;
+ loading_obj->stable_ptrs = fe_sptr;
+ }
+
+ return sptr;
+}
+
+
+/* -----------------------------------------------------------------------------
* Debugging aid: look in GHCi's object symbol tables for symbols
* within DELTA bytes of the specified address, and show their names.
*/
@@ -2143,6 +2175,7 @@ mkOc( pathchar *path, char *image, int imageSize,
oc->symbols = NULL;
oc->sections = NULL;
oc->proddables = NULL;
+ oc->stable_ptrs = NULL;
#ifndef USE_MMAP
#ifdef darwin_HOST_OS
@@ -2786,6 +2819,8 @@ resolveObjs( void )
if (!r) { return r; }
// run init/init_array/ctors/mod_init_func
+
+ loading_obj = oc; // tells foreignExportStablePtr what to do
#if defined(OBJFORMAT_ELF)
r = ocRunInit_ELF ( oc );
#elif defined(OBJFORMAT_PEi386)
@@ -2795,6 +2830,8 @@ resolveObjs( void )
#else
barf("resolveObjs: initializers not implemented on this platform");
#endif
+ loading_obj = NULL;
+
if (!r) { return r; }
oc->status = OBJECT_RESOLVED;
@@ -2863,6 +2900,18 @@ unloadObj( pathchar *path )
freeProddableBlocks(oc);
+ // Release any StablePtrs that were created when this
+ // object module was initialized.
+ {
+ ForeignExportStablePtr *fe_ptr, *next;
+
+ for (fe_ptr = oc->stable_ptrs; fe_ptr != NULL; fe_ptr = next) {
+ next = fe_ptr->next;
+ freeStablePtr(fe_ptr->stable_ptr);
+ stgFree(fe_ptr);
+ }
+ }
+
oc->status = OBJECT_UNLOADED;
/* This could be a member of an archive so continue
diff --git a/rts/LinkerInternals.h b/rts/LinkerInternals.h
index b788ea7022..e1942bc8ae 100644
--- a/rts/LinkerInternals.h
+++ b/rts/LinkerInternals.h
@@ -44,6 +44,17 @@ typedef
}
ProddableBlock;
+/*
+ * We must keep track of the StablePtrs that are created for foreign
+ * exports by constructor functions when the module is loaded, so that
+ * we can free them again when the module is unloaded. If we don't do
+ * this, then the StablePtr will keep the module alive indefinitely.
+ */
+typedef struct ForeignExportStablePtr_ {
+ StgStablePtr stable_ptr;
+ struct ForeignExportStablePtr_ *next;
+} ForeignExportStablePtr;
+
/* Jump Islands are sniplets of machine code required for relative
* address relocations on the PowerPC, x86_64 and ARM.
*/
@@ -120,6 +131,8 @@ typedef struct _ObjectCode {
unsigned long n_symbol_extras;
#endif
+ ForeignExportStablePtr *stable_ptrs;
+
} ObjectCode;
#define OC_INFORMATIVE_FILENAME(OC) \