Fri Nov  5 02:32:32 1999  Mumit Khan  <khan@xraylith.wisc.edu>

	* gthr-win32.h (__gthread_active_p): Support Mingw MT runtime.
	(__gthread_key_create): Likewise. 
 	(__gthread_key_dtor):  Likewise.
	(__gthread_once): Fix logic.
	(__gthread_key_delete): Cast away constness.

	* i386/cygwin.h (SUBTARGET_SWITCHES): Add -mthreads option.
	* invoke.texi: Document.
	* i386/mingw32.h (CPP_SPEC): Use.
	(LIBGCC_SPEC): Likewise.
	* i386/crtdll.h (LIBGCC_SPEC): Likewise.

Index: gcc-2.95.2/gcc/gthr-win32.h
===================================================================
RCS file: /homes/khan/src/CVSROOT/gcc-2.95.2/gcc/gthr-win32.h,v
retrieving revision 1.1
diff -u -3 -p -r1.1 gthr-win32.h
--- gcc-2.95.2/gcc/gthr-win32.h	1999/11/05 08:27:10	1.1
+++ gcc-2.95.2/gcc/gthr-win32.h	1999/11/05 08:30:39
@@ -34,23 +34,41 @@ Boston, MA 02111-1307, USA.  */
    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. This
-      will certainly cause memory leaks due to unreclaimed eh contexts
-      (sizeof (eh_context) is at least 24 bytes for x86 currently).
+   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 might consider using Critical Sections instead of Windows32 
+      mutexes for better performance, but emulating __gthread_mutex_trylock 
+      interface becomes more complicated (Win9x does not support
+      TryEnterCriticalSectioni, while NT does).
   
-   The basic framework should work well enough. */
+   The basic framework should work well enough. In the long term, GCC
+   needs to use Structured Exception Handling on Windows32.  */
 
 #define __GTHREADS 1
 
 #include <windows.h>
 #include <errno.h>
+#ifdef __MINGW32__
+#include <_mingw.h>
+#endif
 
 typedef DWORD __gthread_key_t;
 
@@ -64,10 +82,24 @@ typedef HANDLE __gthread_mutex_t;
 #define __GTHREAD_ONCE_INIT {FALSE, -1}
 #define __GTHREAD_MUTEX_INIT_FUNCTION __gthread_mutex_init_function
 
+#if __MINGW32_MAJOR_VERSION >= 1 || \
+  (__MINGW32_MAJOR_VERSION == 0 && __MINGW32_MINOR_VERSION > 2)
+#define MINGW32_SUPPORTS_MT_EH 1
+extern int __mingwthr_key_dtor PROTO((DWORD, void (*) (void *)));
+/* Mingw runtime >= v0.3 provides a magic variable that is set to non-zero
+   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;
+#endif
+
 static inline int
 __gthread_active_p ()
 {
+#ifdef MINGW32_SUPPORTS_MT_EH
+  return _CRT_MT;
+#else
   return 1;
+#endif
 }
 
 static inline int
@@ -85,48 +117,52 @@ __gthread_once (__gthread_once_t *once, 
 	  (*func) ();
 	  once->done = TRUE;
 	}
-    }
-  else
-    {
-      /* Another thread is currently executing the code, so wait for it to
-         finish; yield the CPU in the meantime.  */ 
-      while (! once->done)
-        Sleep (0);
+      else
+	{
+	  /* Another thread is currently executing the code, so wait for it 
+	     to finish; yield the CPU in the meantime.  If performance 
+	     does become an issue, the solution is to use an Event that 
+	     we wait on here (and set above), but that implies a place to 
+	     create the event before this routine is called.  */ 
+	  while (! once->done)
+	    Sleep (0);
+	}
     }
   
   return 0;
 }
 
-/* Windows32 thread local keys don't support destructors; to avoid leaks,
-   we will have to figure something out in the future.  */
+/* Windows32 thread local keys don't support destructors; this leads to
+   leaks, especially in threaded applications making extensive use of 
+   C++ EH. Mingw uses a thread-support DLL to work-around this problem.  */
 static inline int
-__gthread_key_create (__gthread_key_t *key, 
-                      void (*dtor) (void *) __attribute__((__unused__)))
+__gthread_key_create (__gthread_key_t *key, void (*dtor) (void *))
 {
   int status = 0;
   DWORD tls_index = TlsAlloc ();
   if (tls_index != 0xFFFFFFFF)
-    *key = tls_index;
+    {
+      *key = tls_index;
+#ifdef MINGW32_SUPPORTS_MT_EH
+      /* Mingw runtime 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 ();
   return status;
 }
 
-/* Currently, this routine is never called since win32 keys don't support
-   destructors. Hopefully we'll find a way in the future.  */
+/* Currently, this routine is called only for Mingw runtime, and if
+   -mthreads option is chosen to link in the thread support DLL.  */ 
 static inline int
 __gthread_key_dtor (__gthread_key_t key, void *ptr)
 {
-  int status = 0;
-
-  /* Just reset the key value to zero. */
-  if (ptr)
-    status = (TlsSetValue (key, 0) != 0) ? 0 : (int) GetLastError ();
-  return status;
+  /* Nothing needed. */
+  return 0;
 }
 
-/* Currently, this routine is never called since win32 keys don't support
-   destructors. Hopefully we'll find a way in the future.  */
 static inline int
 __gthread_key_delete (__gthread_key_t key)
 {
@@ -142,7 +178,7 @@ __gthread_getspecific (__gthread_key_t k
 static inline int
 __gthread_setspecific (__gthread_key_t key, const void *ptr)
 {
-  return (TlsSetValue (key, ptr) != 0) ? 0 : (int) GetLastError ();
+  return (TlsSetValue (key, (void*) ptr) != 0) ? 0 : (int) GetLastError ();
 }
 
 static inline void
Index: gcc-2.95.2/gcc/invoke.texi
===================================================================
RCS file: /homes/khan/src/CVSROOT/gcc-2.95.2/gcc/invoke.texi,v
retrieving revision 1.1.1.1
diff -u -3 -p -r1.1.1.1 invoke.texi
--- gcc-2.95.2/gcc/invoke.texi	1999/11/05 01:09:43	1.1.1.1
+++ gcc-2.95.2/gcc/invoke.texi	1999/11/05 08:31:33
@@ -343,6 +343,7 @@ in the following sections.
 -mreg-alloc=@var{list}  -mregparm=@var{num}
 -malign-jumps=@var{num}  -malign-loops=@var{num}
 -malign-functions=@var{num} -mpreferred-stack-boundary=@var{num}
+-mthreads
 
 @emph{HPPA Options}
 -march=@var{architecture type}
@@ -5220,6 +5221,14 @@ This extra alignment does consume extra 
 to stack space usage, such as embedded systems and operating system kernels,
 may want to reduce the preferred alignment to
 @samp{-mpreferred-stack-boundary=2}.
+
+@item -mthreads
+@kindex -mthreads
+Support thread-safe exception handling on @samp{Mingw32}. Code that relies 
+on thread-safe exception handling must compile and link all code with the 
+@samp{-mthreads} option. When compiling, @samp{-mthreads} defines 
+@samp{-D_MT}; when linking, it links in a special thread helper library 
+@samp{-lmingwthrd} which cleans up per thread exception handling data.
 @end table
 
 @node HPPA Options
Index: gcc-2.95.2/gcc/config/i386/crtdll.h
===================================================================
RCS file: /homes/khan/src/CVSROOT/gcc-2.95.2/gcc/config/i386/crtdll.h,v
retrieving revision 1.2
diff -u -3 -p -r1.2 crtdll.h
--- gcc-2.95.2/gcc/config/i386/crtdll.h	1999/11/05 08:19:24	1.2
+++ gcc-2.95.2/gcc/config/i386/crtdll.h	1999/11/05 08:29:27
@@ -32,7 +32,8 @@ Boston, MA 02111-1307, USA. */
   -Asystem(winnt) -Acpu(i386) -Amachine(i386)"
 
 #undef LIBGCC_SPEC
-#define LIBGCC_SPEC "-lmingw32 -lgcc -lmoldname -lcrtdll"
+#define LIBGCC_SPEC \
+  "%{mthreads:-lmingwthrd} -lmingw32 -lgcc -lmoldname -lcrtdll"
 
 /* Specify a different entry point when linking a DLL */
 #undef STARTFILE_SPEC
Index: gcc-2.95.2/gcc/config/i386/cygwin.h
===================================================================
RCS file: /homes/khan/src/CVSROOT/gcc-2.95.2/gcc/config/i386/cygwin.h,v
retrieving revision 1.5
diff -u -3 -p -r1.5 cygwin.h
--- gcc-2.95.2/gcc/config/i386/cygwin.h	1999/11/05 08:21:44	1.5
+++ gcc-2.95.2/gcc/config/i386/cygwin.h	1999/11/05 08:29:27
@@ -51,7 +51,8 @@ Boston, MA 02111-1307, USA. */
 { "console",		  -MASK_WINDOWS, "Create console application" }, \
 { "dll",		  MASK_DLL, "Generate code for a DLL" },     \
 { "nop-fun-dllimport",	  MASK_NOP_FUN_DLLIMPORT, "Ignore dllimport for functions" }, \
-{ "no-nop-fun-dllimport", -MASK_NOP_FUN_DLLIMPORT, "" },
+{ "no-nop-fun-dllimport", -MASK_NOP_FUN_DLLIMPORT, "" }, \
+{ "threads",		  0, "Use Mingw-specific thread support" },
 
 
 /* Support the __declspec keyword by turning them into attributes.
Index: gcc-2.95.2/gcc/config/i386/mingw32.h
===================================================================
RCS file: /homes/khan/src/CVSROOT/gcc-2.95.2/gcc/config/i386/mingw32.h,v
retrieving revision 1.2
diff -u -3 -p -r1.2 mingw32.h
--- gcc-2.95.2/gcc/config/i386/mingw32.h	1999/11/05 08:19:24	1.2
+++ gcc-2.95.2/gcc/config/i386/mingw32.h	1999/11/05 08:29:27
@@ -45,7 +45,8 @@ Boston, MA 02111-1307, USA. */
 #define STANDARD_INCLUDE_COMPONENT "MINGW32"
 
 #undef CPP_SPEC
-#define CPP_SPEC "-remap %(cpp_cpu) %{posix:-D_POSIX_SOURCE}"
+#define CPP_SPEC \
+  "-remap %(cpp_cpu) %{posix:-D_POSIX_SOURCE} %{mthreads:-D_MT}"
 
 /* For Windows applications, include more libraries, but always include
    kernel32.  */
@@ -55,7 +56,8 @@ Boston, MA 02111-1307, USA. */
 
 /* Include in the mingw32 libraries with libgcc */
 #undef LIBGCC_SPEC
-#define LIBGCC_SPEC "-lmingw32 -lgcc -lmoldname -lmsvcrt"
+#define LIBGCC_SPEC \
+  "%{mthreads:-lmingwthrd} -lmingw32 -lgcc -lmoldname -lmsvcrt"
 
 #undef STARTFILE_SPEC
 #define STARTFILE_SPEC "%{mdll:dllcrt2%O%s} %{!mdll:crt2%O%s} %{pg:gcrt2%O%s}"
