summaryrefslogtreecommitdiffstats
path: root/winsup/cygwin/dll_init.cc
diff options
context:
space:
mode:
authorChristopher Faylor <me@cgf.cx>2010-01-29 18:34:09 +0000
committerChristopher Faylor <me@cgf.cx>2010-01-29 18:34:09 +0000
commitd5c4cd3f6ce4023376c550f74656303a425bdcd4 (patch)
treeb49b3cbeb66fcc52e06c9783a0677d2ac568fd60 /winsup/cygwin/dll_init.cc
parent2b37c431b1c2f4e90fd7c6130b8bddc9e9c019f9 (diff)
downloadcygnal-d5c4cd3f6ce4023376c550f74656303a425bdcd4.tar.gz
cygnal-d5c4cd3f6ce4023376c550f74656303a425bdcd4.tar.bz2
cygnal-d5c4cd3f6ce4023376c550f74656303a425bdcd4.zip
* dll_init.cc (remove_dll_atexit): New function.
(dll_list::detach): Run any atexit handlers registered in the DLL prior to unloading.
Diffstat (limited to 'winsup/cygwin/dll_init.cc')
-rw-r--r--winsup/cygwin/dll_init.cc28
1 files changed, 28 insertions, 0 deletions
diff --git a/winsup/cygwin/dll_init.cc b/winsup/cygwin/dll_init.cc
index 20cc4f9ce..763964bac 100644
--- a/winsup/cygwin/dll_init.cc
+++ b/winsup/cygwin/dll_init.cc
@@ -20,6 +20,7 @@ details. */
#include "pinfo.h"
#include "cygtls.h"
#include <wchar.h>
+#include <sys/reent.h>
extern void __stdcall check_sanity_and_sync (per_process *);
@@ -142,6 +143,32 @@ dll_list::alloc (HINSTANCE h, per_process *p, dll_type type)
return d;
}
+/* This function looks for every atexit function registered in the
+ about-to-be-unloaded DLL and runs it.
+
+ newlib does not provide any method for selectively running elements
+ from the atexit() queue so we have to roll our own.
+
+ Note that this is not foolproof since a function in the DLL could
+ register an atexit function outside of the DLL and that should be
+ run when the DLL detachs. */
+static void
+remove_dll_atexit (MEMORY_BASIC_INFORMATION& m)
+{
+ unsigned char *dll_beg = (unsigned char *) m.AllocationBase;
+ unsigned char *dll_end = (unsigned char *) m.AllocationBase + m.RegionSize;
+ struct _atexit *p = _GLOBAL_REENT->_atexit;
+ for (int n = p->_ind - 1; n >= 0; n--)
+ {
+ void (*fn) (void) = p->_fns[n];
+ if ((unsigned char *) fn >= dll_beg && (unsigned char *) fn < dll_end)
+ {
+ fn ();
+ p->_fns[n] = NULL;
+ }
+ }
+}
+
/* Detach a DLL from the chain. */
void
dll_list::detach (void *retaddr)
@@ -161,6 +188,7 @@ dll_list::detach (void *retaddr)
system_printf ("WARNING: trying to detach an already detached dll ...");
else if (--d->count == 0)
{
+ remove_dll_atexit (m);
d->run_dtors ();
d->prev->next = d->next;
if (d->next)