Welcome to mirror list, hosted at ThFree Co, Russian Federation.

cygwin.com/git/newlib-cygwin.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'winsup/mingw/dllcrt1.c')
-rw-r--r--winsup/mingw/dllcrt1.c141
1 files changed, 124 insertions, 17 deletions
diff --git a/winsup/mingw/dllcrt1.c b/winsup/mingw/dllcrt1.c
index a0055d8b0..fe351eb10 100644
--- a/winsup/mingw/dllcrt1.c
+++ b/winsup/mingw/dllcrt1.c
@@ -25,10 +25,11 @@
* $Date$
*
*/
-
+#include <stdlib.h>
#include <stdio.h>
#include <io.h>
#include <process.h>
+#include <errno.h>
#include <windows.h>
/* Unlike normal crt1, I don't initialize the FPU, because the process
@@ -40,8 +41,20 @@ extern void __main ();
extern void __do_global_dtors ();
#endif
+typedef void (* p_atexit_fn )(void);
+static p_atexit_fn* first_atexit;
+static p_atexit_fn* next_atexit;
+
+static void
+__dll_exit (void);
+
+/* This is based on the function in the Wine project's exit.c */
+p_atexit_fn __dllonexit (p_atexit_fn, p_atexit_fn**, p_atexit_fn**);
+
+
extern BOOL WINAPI DllMain (HANDLE, DWORD, LPVOID);
+
BOOL WINAPI
DllMainCRTStartup (HANDLE hDll, DWORD dwReason, LPVOID lpReserved)
{
@@ -49,41 +62,135 @@ DllMainCRTStartup (HANDLE hDll, DWORD dwReason, LPVOID lpReserved)
if (dwReason == DLL_PROCESS_ATTACH)
{
+ /* Initialize private atexit table for this dll.
+ 32 is min size required by ANSI */
+
+ first_atexit = (p_atexit_fn*) malloc (32 * sizeof (p_atexit_fn));
+ if (first_atexit == NULL ) /* can't allocate memory */
+ {
+ errno=ENOMEM;
+ return FALSE;
+ }
+ *first_atexit = NULL;
+ next_atexit = first_atexit;
+
+#ifdef DEBUG
+ printf ("%s: DLL_PROCESS_ATTACH (%d)\n", __FUNCTION__);
+#endif
+
+
#ifdef __GNUC__
- /* From libgcc.a, calls global class constructors. */
+ /* From libgcc.a, __main calls global class constructors,
+ __do_global_ctors, which registers __do_global_dtors
+ as the first entry of the private atexit table we
+ have just initialised */
__main ();
+
#endif
- }
+ }
/*
- * Call the user-supplied DllMain subroutine
+ * Call the user-supplied DllMain subroutine.
+ * This has to come after initialization of atexit table and
+ * registration of global constructors.
* NOTE: DllMain is optional, so libmingw32.a includes a stub
* which will be used if the user does not supply one.
*/
+
bRet = DllMain (hDll, dwReason, lpReserved);
+ /* Handle case where DllMain returns FALSE on attachment attempt. */
-#ifdef __GNUC__
- if (dwReason == DLL_PROCESS_DETACH)
+ if ( (dwReason == DLL_PROCESS_ATTACH) && !bRet)
{
- /* From libgcc.a, calls global class destructors. */
- __do_global_dtors ();
- }
+#ifdef DEBUG
+ printf ("%s: DLL_PROCESS_ATTACH failed, cleaning up\n", __FUNCTION__);
#endif
+ __dll_exit (); /* Cleanup now. This will set first_atexit to NULL so we
+ know we've cleaned up */
+ }
+
+ if (dwReason == DLL_PROCESS_DETACH)
+ {
+#ifdef DEBUG
+ printf ("%s: DLL_PROCESS_DETACH (%d)\n", __FUNCTION__);
+#endif
+ /* If not attached, return FALSE. Cleanup already done above
+ if failed attachment attempt. */
+ if (! first_atexit )
+ bRet = FALSE;
+ else
+ /*
+ * We used to call __do_global_dtors () here. This is
+ * no longer necessary since __do_global_dtors is now
+ * registered at start (last out) of private atexit table.
+ */
+ __dll_exit ();
+ }
return bRet;
}
+static
+void
+__dll_exit(void)
+/* Run LIFO terminators registered in private atexit table */
+{
+ if ( first_atexit )
+ {
+ p_atexit_fn* __last = next_atexit - 1;
+ while ( __last >= first_atexit )
+ {
+ if ( *__last != NULL )
+ {
+#ifdef DEBUG
+ printf ("%s: Calling exit function 0x%x from 0x%x\n",
+ __FUNCTION__, (unsigned)(*__last),(unsigned)__last);
+#endif
+ (**__last) ();
+ }
+ __last--;
+ }
+ free ( first_atexit ) ;
+ first_atexit = NULL ;
+ }
+ /*
+ Make sure output buffers opened by DllMain or
+ atexit-registered functions are flushed before detaching,
+ otherwise we can have problems with redirected output.
+ */
+ fflush (NULL);
+}
+
/*
- * For the moment a dummy atexit. Atexit causes problems in DLLs, especially
- * if they are dynamically loaded. For now atexit inside a DLL does nothing.
- * NOTE: We need this even if the DLL author never calls atexit because
- * the global constructor function __do_global_ctors called from __main
- * will attempt to register __do_global_dtors using atexit.
- * Thanks to Andrey A. Smirnov for pointing this one out.
+ * The atexit exported from msvcrt.dll causes problems in DLLs.
+ * Here, we override the exported version of atexit with one that passes the
+ * private table initialised in DllMainCRTStartup to __dllonexit.
+ * That means we have to hide the mscvrt.dll atexit because the
+ * atexit defined here gets __dllonexit from the same lib.
*/
+
int
-atexit (void (*pfn) ())
+atexit (p_atexit_fn pfn )
{
- return 0;
+#ifdef DEBUG
+ printf ("%s: registering exit function 0x%x at 0x%x\n",
+ __FUNCTION__, (unsigned)pfn, (unsigned)next_atexit);
+#endif
+ return (__dllonexit (pfn, &first_atexit, &next_atexit)
+ == NULL ? -1 : 0 );
}
+/*
+ * Likewise for non-ANSI function _onexit that may be called by
+ * code in the dll.
+ */
+
+_onexit_t
+_onexit (_onexit_t pfn )
+{
+#ifdef DEBUG
+ printf ("%s: registering exit function 0x%x at 0x%x\n",
+ __FUNCTION__, (unsigned)pfn, (unsigned)next_atexit);
+#endif
+ return ((_onexit_t) __dllonexit ((p_atexit_fn)pfn, &first_atexit, &next_atexit));
+}