This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH] Support thread cleanup without mingwm10.dll


This patch removes the requirement the -mthread be passed to link against mingwm10.dll if multithreaded exceptions are desired.

Instead, the shared libgcc_s_1.dll will be used. For static builds, a TLS callback in the main executable will provide the notifications.

With this patch, there's really no need for -mthread anymore. Most of GCC, mingw-runtime, and msvcrt is thread-safe by default anyhow. I haven't removed the option, though, in case there is some reason we should keep it.

With this patch, the dtor list logic is in GCC. Since it is both the only producer and only consumer of these events, this seems like the right place for it. There is no way for GCC to get at the mthr.c logic in mingw-runtime without changes there, and its probably far easier just to move this here. Also, this simplifies ABI concerns, and makes the total sum of the mthr code about half as large.

I've tested this by a bootstrap on i386-pc-mingw32. A full testsuite run is in progress.

OK to commit?
2008-08-17  Aaron W. LaFramboise  <aaronavay62@aaronwl.com>

	* config/i386/t-gthr-win32 (LIB2FUNCS_EXTRA): Add mthr.c.
	* config/i386/gthr-win32.c (MINGW32_SUPPORTS_MT_EH): Remove.
	* config/i386/mingw32.h (LIBGCC_SPEC): Remove -lmingwthrd.
	* config/i386/mthr.c: New file.
	* gthr-win32.h (MINGW32_SUPPORTS_MT_EH): Remove.
	(_CRT_MT) Remove.

Index: gcc/gthr-win32.h
===================================================================
--- gcc/gthr-win32.h	(revision 139186)
+++ gcc/gthr-win32.h	(working copy)
@@ -36,21 +36,13 @@ Software Foundation, 51 Franklin Street,
    does not map well into pthread-inspired gcc's threading model, and so
    there are caveats one needs to be aware of.
 
-   1. The destructor supplied to __gthread_key_create is ignored for
-      generic x86-win32 ports. This will certainly cause memory leaks
-      due to unreclaimed eh contexts (sizeof (eh_context) is at least
-      24 bytes for x86 currently).
-
-      This memory leak may be significant for long-running applications
-      that make heavy use of C++ EH.
-
-      However, Mingw runtime (version 0.3 or newer) provides a mechanism
-      to emulate pthreads key dtors; the runtime provides a special DLL,
-      linked in if -mthreads option is specified, that runs the dtors in
-      the reverse order of registration when each thread exits. If
-      -mthreads option is not given, a stub is linked in instead of the
-      DLL, which results in memory leak. Other x86-win32 ports can use
-      the same technique of course to avoid the leak.
+   1. The destructor supplied to __gthread_key_create is handled by mthr.c.
+      These destructors will be called in reverse order of registration
+      when the mthr.c TLS callback machinery receives notification of thread
+      or process exit.
+
+      This function was formerly provided by mingwm10.dll, part of
+      mingw-runtime.
 
    2. The error codes returned are non-POSIX like, and cast into ints.
       This may cause incorrect error return due to truncation values on
@@ -359,15 +351,7 @@ typedef struct {
   __gthread_recursive_mutex_init_function
 #define __GTHREAD_RECURSIVE_MUTEX_INIT_DEFAULT {-1, 0, 0, 0}
 
-#if __MINGW32_MAJOR_VERSION >= 1 || \
-  (__MINGW32_MAJOR_VERSION == 0 && __MINGW32_MINOR_VERSION > 2)
-#define MINGW32_SUPPORTS_MT_EH 1
-/* Mingw runtime >= v0.3 provides a magic variable that is set to nonzero
-   if -mthreads option was specified, or 0 otherwise. This is to get around
-   the lack of weak symbols in PE-COFF.  */
-extern int _CRT_MT;
 extern int __mingwthr_key_dtor (unsigned long, void (*) (void *));
-#endif /* __MINGW32__ version */
 
 /* The Windows95 kernel does not export InterlockedCompareExchange.
    This provides a substitute.   When building apps that reference
@@ -395,11 +379,7 @@ __gthr_i486_lock_cmp_xchg(long *dest, lo
 static inline int
 __gthread_active_p (void)
 {
-#ifdef MINGW32_SUPPORTS_MT_EH
-  return _CRT_MT;
-#else
   return 1;
-#endif
 }
 
 #if __GTHREAD_HIDE_WIN32API
@@ -577,11 +557,9 @@ __gthread_key_create (__gthread_key_t *k
   if (tls_index != 0xFFFFFFFF)
     {
       *key = tls_index;
-#ifdef MINGW32_SUPPORTS_MT_EH
-      /* Mingw runtime will run the dtors in reverse order for each thread
+      /* libgcc will run the dtors in reverse order for each thread
          when the thread exits.  */
       status = __mingwthr_key_dtor (*key, dtor);
-#endif
     }
   else
     status = (int) GetLastError ();
Index: gcc/config/i386/t-gthr-win32
===================================================================
--- gcc/config/i386/t-gthr-win32	(revision 139186)
+++ gcc/config/i386/t-gthr-win32	(working copy)
@@ -1,3 +1,3 @@
 # We hide calls to w32api needed for w32 thread support here:
-LIB2FUNCS_EXTRA = $(srcdir)/config/i386/gthr-win32.c
-
+LIB2FUNCS_EXTRA = $(srcdir)/config/i386/gthr-win32.c \
+                  $(srcdir)/config/i386/mthr.c
Index: gcc/config/i386/gthr-win32.c
===================================================================
--- gcc/config/i386/gthr-win32.c	(revision 139186)
+++ gcc/config/i386/gthr-win32.c	(working copy)
@@ -39,36 +39,7 @@ Software Foundation, 51 Franklin Street,
 #define __GTHREAD_I486_INLINE_LOCK_PRIMITIVES
 #include <gthr-win32.h>
 
-/* Windows32 threads specific definitions. The windows32 threading model
-   does not map well into pthread-inspired gcc's threading model, and so 
-   there are caveats one needs to be aware of.
-
-   1. The destructor supplied to __gthread_key_create is ignored for
-      generic x86-win32 ports. This will certainly cause memory leaks 
-      due to unreclaimed eh contexts (sizeof (eh_context) is at least 
-      24 bytes for x86 currently).
-
-      This memory leak may be significant for long-running applications
-      that make heavy use of C++ EH.
-
-      However, Mingw runtime (version 0.3 or newer) provides a mechanism
-      to emulate pthreads key dtors; the runtime provides a special DLL,
-      linked in if -mthreads option is specified, that runs the dtors in
-      the reverse order of registration when each thread exits. If
-      -mthreads option is not given, a stub is linked in instead of the
-      DLL, which results in memory leak. Other x86-win32 ports can use 
-      the same technique of course to avoid the leak.
-
-   2. The error codes returned are non-POSIX like, and cast into ints.
-      This may cause incorrect error return due to truncation values on 
-      hw where sizeof (DWORD) > sizeof (int).
-   
-   3. We are currently using a special mutex instead of the Critical
-      Sections, since Win9x does not support TryEnterCriticalSection
-      (while NT does).
-  
-   The basic framework should work well enough. In the long term, GCC
-   needs to use Structured Exception Handling on Windows32.  */
+/* See gthr-win32.h for more information. */
 
 int
 __gthr_win32_once (__gthread_once_t *once, void (*func) (void))
@@ -110,11 +81,9 @@ __gthr_win32_key_create (__gthread_key_t
   if (tls_index != 0xFFFFFFFF)
     {
       *key = tls_index;
-#ifdef MINGW32_SUPPORTS_MT_EH
-      /* Mingw runtime will run the dtors in reverse order for each thread
+      /* libgcc will run the dtors in reverse order for each thread
          when the thread exits.  */
       status = __mingwthr_key_dtor (*key, dtor);
-#endif
     }
   else
     status = (int) GetLastError ();
Index: gcc/config/i386/mingw32.h
===================================================================
--- gcc/config/i386/mingw32.h	(revision 139186)
+++ gcc/config/i386/mingw32.h	(working copy)
@@ -67,19 +67,33 @@ along with GCC; see the file COPYING3.  
 /* Include in the mingw32 libraries with libgcc */
 #undef LIBGCC_SPEC
 #define LIBGCC_SPEC \
-  "%{mthreads:-lmingwthrd} -lmingw32 -lgcc -lmoldname -lmingwex -lmsvcrt"
+  "-lmingw32 \
    %{shared-libgcc:-lgcc_s} -lgcc \
    -lmoldname -lmingwex -lmsvcrt"
 
Index: gcc/config/i386/mthr.c
===================================================================
--- gcc/config/i386/mthr.c	(revision 0)
+++ gcc/config/i386/mthr.c	(revision 0)
@@ -0,0 +1,161 @@
+/* Windows thread cleanup
+   Copyright (C) 1995, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
+   2005, 2006, 2007 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.
+
+ * Implement Mingw thread-support DLL .
+ *
+ * The sole job of the Mingw thread support in libgcc is to catch 
+ * all the dying threads and clean up the data allocated in the TLSs 
+ * for exception contexts during C++ EH. Posix threads have key dtors, 
+ * but win32 TLS keys do not, hence the magic. Without this, there's at 
+ * least `6 * sizeof (void*)' bytes leaks for each catch/throw in each
+ * thread. The only public interface is __mingwthr_key_dtor(). 
+ */
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#include <stdlib.h>
+
+#include "ansidecl.h"
+
+int __mingwthr_key_dtor (DWORD key, void (*dtor) (void *));
+
+/* To protect the thread/key association data structure modifications. */
+CRITICAL_SECTION __mingwthr_cs;
+
+/* An individual key/dtor pair in the list. */
+typedef struct __mingwthr_key __mingwthr_key_t;
+struct __mingwthr_key {
+  DWORD key;
+  void (*dtor) (void *);
+  __mingwthr_key_t *next;
+};
+
+/* The list of threads active with key/dtor pairs. */
+static __mingwthr_key_t *key_dtor_list;
+
+/* Add key/dtor association for this thread. If the thread entry does not
+ * exist, create a new one and add to the head of the threads list; add
+ * the new assoc at the head of the keys list. */
+
+int
+__mingwthr_key_dtor (DWORD key, void (*dtor) (void *))
+{
+  __mingwthr_key_t *new_key;
+
+  new_key = (__mingwthr_key_t *) calloc (1, sizeof (__mingwthr_key_t));
+  if (new_key == NULL)
+    return -1;
+  
+  new_key->key = key;
+  new_key->dtor = dtor;
+
+  EnterCriticalSection (&__mingwthr_cs);
+
+  new_key->next = key_dtor_list;
+  key_dtor_list = new_key;
+
+  LeaveCriticalSection (&__mingwthr_cs);
+
+  return 0;
+}
+
+/* Callback from DllMain when thread detaches to clean up the key
+ * storage. 
+ *
+ * Note that this does not delete the key itself, but just runs
+ * the dtor if the current value are both non-NULL. Note that the
+ * keys with NULL dtors are not added by __mingwthr_key_dtor, the
+ * only public interface, so we don't need to check. */
+
+static void
+__mingwthr_run_key_dtors (void)
+{
+  __mingwthr_key_t *keyp;
+
+  EnterCriticalSection (&__mingwthr_cs);
+
+  for (keyp = key_dtor_list; keyp; )
+  {
+     LPVOID value = TlsGetValue (keyp->key);
+     if (GetLastError () == ERROR_SUCCESS)
+     {
+        if (value)
+           (*keyp->dtor) (value);
+     }
+
+     keyp = keyp->next;
+  }
+  
+  LeaveCriticalSection (&__mingwthr_cs);
+}
+
+/*
+ * The TLS callback is called by the system any time there is a thread
+ * creation or termination, as well as when the process starts and ends.
+ *
+ * This function runs the thread destructors whenever a process or thread
+ * is terminating. */
+
+static void
+NTAPI tls_callback (void *handle ATTRIBUTE_UNUSED, DWORD reason,
+  void *reserved ATTRIBUTE_UNUSED)
+{
+  switch (reason)
+    {
+    case DLL_PROCESS_ATTACH:
+      InitializeCriticalSection (&__mingwthr_cs);
+      break;
+
+    case DLL_PROCESS_DETACH:
+      __mingwthr_run_key_dtors();
+      DeleteCriticalSection (&__mingwthr_cs);
+      break;
+
+    case DLL_THREAD_DETACH:
+      __mingwthr_run_key_dtors();
+      break;
+    }
+}
+
+/* The loader writes a pointer to the TLS index here. */
+DWORD __tls_index__ = 0;
+
+/* Mark the beginning and ends of various sections. */
+extern const DWORD __tls_start__;
+extern const DWORD __tls_end__;
+extern const PIMAGE_TLS_CALLBACK __crt_xl_start__;
+__attribute__ ((section (".CRT$XLzzz"))) const DWORD __crt_xl_end__ = 0;
+
+/* The TLS Directory
+ * 
+ * The linker will detect the _tls_used symbol and use it as the object's
+ * TLS directory. */
+const IMAGE_TLS_DIRECTORY _tls_used = {
+  (DWORD)&__tls_start__,
+  (DWORD)&__tls_end__,
+  (DWORD)&__tls_index__,
+  (DWORD)&__crt_xl_start__,
+  0,
+  0
+};
+
+/* Register the TLS callback. */
+static const PIMAGE_TLS_CALLBACK ptr __attribute__((section(".CRT$XLgcc")))
+  = tls_callback;

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]