From a611ae50d5c1106988df7ec8b053efc332e35ae3 Mon Sep 17 00:00:00 2001
From: Christopher Faylor <me@cgf.cx>
Date: Wed, 14 Sep 2005 14:00:07 +0000
Subject: [PATCH] * exceptions.cc (sigtid): Remove declaration.
 (handle_exceptions): Use _sig_tls rather than sigtid to determine if this is
 the signal thread. (set_signal_mask): Ditto for conditionalized CGF code. *
 pinfo.cc (pinfo::exit): Exit the thread if we forcefully terminated the main
 thread * sigproc.cc (sigtid): Delete. (_sig_tls): Define. (sig_clear): Use
 _sig_tls rather than sigtid to determine if this is the signal thread.
 (sig_dispatch_pending): Ditto. (wait_sig): Set _sig_tls here. * dcrt0.cc
 (do_exit): Move sigproc_terminate call later since signal handling was still
 needed for subsequent stuff.  Call sigproc_terminate with new exit_state
 value. * pinfo.cc (pinfo::exit): Call sigproc_terminate with new exit_state
 value. * sigproc.cc (proc_terminate): Remove unnecessary (void) parameter.
 (sigproc_terminate): Ditto.  Add new argument to accept exit state to be set.
 (wait_sig): Reorganize __SIGEXIT handling.  Add more debugging output. *
 winsup.h (sigproc_terminate): Declare with new exit_state argument.
 (exit_states): Reorganize to reflect new exit ordering of sigproc_terminate.

---
 winsup/cygwin/ChangeLog     | 30 ++++++++++++++++++++++++++
 winsup/cygwin/cygtls.h      |  1 +
 winsup/cygwin/dcrt0.cc      | 24 ++++++++++-----------
 winsup/cygwin/exceptions.cc |  6 ++----
 winsup/cygwin/pinfo.cc      | 12 +++++++----
 winsup/cygwin/sigproc.cc    | 42 +++++++++++++++++++++----------------
 winsup/cygwin/sigproc.h     |  2 +-
 winsup/cygwin/winsup.h      |  4 ++--
 8 files changed, 79 insertions(+), 42 deletions(-)

diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog
index d83936a06..d8ea23893 100644
--- a/winsup/cygwin/ChangeLog
+++ b/winsup/cygwin/ChangeLog
@@ -1,3 +1,33 @@
+2005-09-14  Christopher Faylor  <cgf@timesys.com>
+
+	* exceptions.cc (sigtid): Remove declaration.
+	(handle_exceptions): Use _sig_tls rather than sigtid to determine if
+	this is the signal thread.
+	(set_signal_mask): Ditto for conditionalized CGF code.
+	* pinfo.cc (pinfo::exit): Exit the thread if we forcefully terminated
+	the main thread
+	* sigproc.cc (sigtid): Delete.
+	(_sig_tls): Define.
+	(sig_clear): Use _sig_tls rather than sigtid to determine if this is
+	the signal thread.
+	(sig_dispatch_pending): Ditto.
+	(wait_sig): Set _sig_tls here.
+
+2005-09-13  Christopher Faylor  <cgf@timesys.com>
+
+	* dcrt0.cc (do_exit): Move sigproc_terminate call later since signal
+	handling was still needed for subsequent stuff.  Call sigproc_terminate
+	with new exit_state value.
+	* pinfo.cc (pinfo::exit): Call sigproc_terminate with new exit_state
+	value.
+	* sigproc.cc (proc_terminate): Remove unnecessary (void) parameter.
+	(sigproc_terminate): Ditto.  Add new argument to accept exit state to
+	be set.
+	(wait_sig): Reorganize __SIGEXIT handling.  Add more debugging output.
+	* winsup.h (sigproc_terminate): Declare with new exit_state argument.
+	(exit_states): Reorganize to reflect new exit ordering of
+	sigproc_terminate.
+
 2005-09-13  Christopher Faylor  <cgf@timesys.com>
 
 	* dcrt0.cc (do_exit): Rely on sigproc_terminate to set exit_state
diff --git a/winsup/cygwin/cygtls.h b/winsup/cygwin/cygtls.h
index 627531849..65994ebfa 100644
--- a/winsup/cygwin/cygtls.h
+++ b/winsup/cygwin/cygtls.h
@@ -248,6 +248,7 @@ extern char *_tlsbase __asm__ ("%fs:4");
 extern char *_tlstop __asm__ ("%fs:8");
 #define _my_tls (((_cygtls *) _tlsbase)[-1])
 extern _cygtls *_main_tls;
+extern _cygtls *_sig_tls;
 
 /*gentls_offsets*/
 class myfault
diff --git a/winsup/cygwin/dcrt0.cc b/winsup/cygwin/dcrt0.cc
index b7207667f..f293901b8 100644
--- a/winsup/cygwin/dcrt0.cc
+++ b/winsup/cygwin/dcrt0.cc
@@ -1056,17 +1056,7 @@ do_exit (int status)
       close_all_files ();
     }
 
-  if (exit_state < ES_SIGPROCTERMINATE)
-    sigproc_terminate ();	// sets exit_state directly
-
   myself->stopsig = 0;
-  if (exit_state < ES_TITLE)
-    {
-      exit_state = ES_TITLE;
-      /* restore console title */
-      if (old_title && display_title)
-	set_console_title (old_title);
-    }
 
   if (exit_state < ES_HUP_PGRP)
     {
@@ -1101,6 +1091,17 @@ do_exit (int status)
 
     }
 
+  if (exit_state < ES_SIGPROCTERMINATE)
+    sigproc_terminate (ES_SIGPROCTERMINATE);	// sets exit_state directly
+
+  if (exit_state < ES_TITLE)
+    {
+      exit_state = ES_TITLE;
+      /* restore console title */
+      if (old_title && display_title)
+	set_console_title (old_title);
+    }
+
   if (exit_state < ES_TTY_TERMINATE)
     {
       exit_state = ES_TTY_TERMINATE;
@@ -1165,9 +1166,6 @@ __api_fatal (const char *fmt, ...)
 	WriteFile (h, buf, len, &done, 0);
     }
 
-  /* We are going down without mercy.  Make sure we reset
-     our process_state. */
-  sigproc_terminate ();
 #ifdef DEBUGGING
   try_to_debug ();
 #endif
diff --git a/winsup/cygwin/exceptions.cc b/winsup/cygwin/exceptions.cc
index 939ec89ea..0f61409ab 100644
--- a/winsup/cygwin/exceptions.cc
+++ b/winsup/cygwin/exceptions.cc
@@ -36,8 +36,6 @@ static int handle_exceptions (EXCEPTION_RECORD *, void *, CONTEXT *, void *);
 extern void sigdelayed ();
 };
 
-extern DWORD sigtid;
-
 extern DWORD dwExeced;
 
 static BOOL WINAPI ctrl_c_handler (DWORD);
@@ -528,7 +526,7 @@ handle_exceptions (EXCEPTION_RECORD *e0, void *frame, CONTEXT *in0, void *)
 
   if (!me.fault_guarded ()
       && (!cygwin_finished_initializing
-	  || GetCurrentThreadId () == sigtid
+	  || &_my_tls == _sig_tls
 	  || (void *) global_sigs[si.si_signo].sa_handler == (void *) SIG_DFL
 	  || (void *) global_sigs[si.si_signo].sa_handler == (void *) SIG_IGN
 	  || (void *) global_sigs[si.si_signo].sa_handler == (void *) SIG_ERR))
@@ -1002,7 +1000,7 @@ extern "C" void __stdcall
 set_signal_mask (sigset_t newmask, sigset_t& oldmask)
 {
 #ifdef CGF
-  if (GetCurrentThreadId () == sigtid)
+  if (&_my_tls == _sig_tls)
     small_printf ("********* waiting in signal thread\n");
 #endif
   mask_sync.acquire (INFINITE);
diff --git a/winsup/cygwin/pinfo.cc b/winsup/cygwin/pinfo.cc
index 9ce988db7..5d0b890b0 100644
--- a/winsup/cygwin/pinfo.cc
+++ b/winsup/cygwin/pinfo.cc
@@ -136,8 +136,7 @@ pinfo::zap_cwd ()
 void
 pinfo::exit (DWORD n)
 {
-  sigproc_terminate ();
-  exit_state = ES_FINAL;
+  sigproc_terminate (ES_FINAL);
 
   cygthread::terminate ();
   if (n != EXITCODE_NOSET)
@@ -165,20 +164,25 @@ pinfo::exit (DWORD n)
   _my_tls.stackptr = _my_tls.stack;
   if (&_my_tls == _main_tls)
     {
-      sigproc_printf ("Calling ExitProcess hProcess %p, n %p, exitcode %p",
+      sigproc_printf ("Calling ExitThread hProcess %p, n %p, exitcode %p",
 		      hProcess, n, exitcode);
       ExitThread (exitcode);
     }
   else if (hMainThread)
     {
+#if 0	/* This would be nice, but I don't think that Windows guarantees that
+	   TerminateThread will not block. */
       sigproc_printf ("Calling TerminateThread since %p != %p, %p, n %p, exitcode %p",
 		      &_my_tls, _main_tls, hProcess, n, exitcode);
       TerminateThread (hMainThread, exitcode);
+      if (&_my_tls != _sig_tls)
+	ExitThread (0);
+#endif
     }
 
   sigproc_printf ("Calling ExitProcess since hMainthread is 0, hProcess %p, n %p, exitcode %p",
 		  hProcess, n, exitcode);
-  release ();
+  // release ();  Could race with signal thread.  Sigh.
   ExitProcess (exitcode);
 }
 # undef self
diff --git a/winsup/cygwin/sigproc.cc b/winsup/cygwin/sigproc.cc
index 5427d4632..d8fc2d36c 100644
--- a/winsup/cygwin/sigproc.cc
+++ b/winsup/cygwin/sigproc.cc
@@ -72,7 +72,7 @@ Static waitq waitq_head = {0, 0, 0, 0, 0, 0, 0};// Start of queue for wait'ing t
 
 static muto NO_COPY sync_proc_subproc;	// Control access to subproc stuff
 
-DWORD NO_COPY sigtid = 0;		// ID of the signal thread
+_cygtls NO_COPY *_sig_tls;
 
 /* Function declarations */
 static int __stdcall checkstate (waitq *) __attribute__ ((regparm (1)));
@@ -382,10 +382,9 @@ _cygtls::remove_wq (DWORD wait)
  * will not become procs.
  */
 void __stdcall
-proc_terminate (void)
+proc_terminate ()
 {
   sigproc_printf ("nprocs %d", nprocs);
-  /* Signal processing is assumed to be blocked in this routine. */
   if (nprocs)
     {
       sync_proc_subproc.acquire (WPSP);
@@ -414,7 +413,7 @@ proc_terminate (void)
 void __stdcall
 sig_clear (int target_sig)
 {
-  if (GetCurrentThreadId () != sigtid)
+  if (&_my_tls != _sig_tls)
     sig_send (myself, -target_sig);
   else
     {
@@ -445,11 +444,11 @@ sigpending (sigset_t *mask)
 void __stdcall
 sig_dispatch_pending (bool fast)
 {
-  if (exit_state || GetCurrentThreadId () == sigtid || !sigq.start.next)
+  if (exit_state || &_my_tls == _sig_tls || !sigq.start.next)
     {
 #ifdef DEBUGGING
-      sigproc_printf ("exit_state %d, cur thread id %p, sigtid %p, sigq.start.next %p",
-		      exit_state, GetCurrentThreadId (), sigtid, sigq.start.next);
+      sigproc_printf ("exit_state %d, cur thread id %p, _sig_tls %p, sigq.start.next %p",
+		      exit_state, GetCurrentThreadId (), _sig_tls, sigq.start.next);
 #endif
       return;
     }
@@ -498,13 +497,14 @@ sigproc_init ()
 /* Called on process termination to terminate signal and process threads.
  */
 void __stdcall
-sigproc_terminate (void)
+sigproc_terminate (exit_states es)
 {
-  if (exit_state > ES_SIGPROCTERMINATE)
+  exit_states prior_exit_state = exit_state;
+  exit_state = es;
+  if (prior_exit_state > ES_SIGPROCTERMINATE)
     sigproc_printf ("already performed");
   else
     {
-      exit_state = ES_SIGPROCTERMINATE;
       sigproc_printf ("entering");
       sig_send (myself_nowait, __SIGEXIT);
       proc_terminate ();		// clean up process stuff
@@ -1007,12 +1007,12 @@ wait_sig (VOID *self)
   myself->process_state |= PID_ACTIVE;
   myself->process_state &= ~PID_INITIALIZING;
 
+  _sig_tls = &_my_tls;
   sigproc_printf ("myself->dwProcessId %u", myself->dwProcessId);
   SetEvent (wait_sig_inited);
-  sigtid = GetCurrentThreadId ();
 
   exception_list el;
-  _my_tls.init_threadlist_exceptions (&el);
+  _sig_tls->init_threadlist_exceptions (&el);
   debug_printf ("entering ReadFile loop, readsig %p, myself->sendsig %p",
 		readsig, myself->sendsig);
 
@@ -1022,8 +1022,6 @@ wait_sig (VOID *self)
       sigpacket pack;
       if (!ReadFile (readsig, &pack, sizeof (pack), &nb, NULL))
 	break;
-      if (exit_state || pack.si.si_signo == __SIGEXIT)
-	break;
 
       if (nb != sizeof (pack))
 	{
@@ -1083,6 +1081,9 @@ wait_sig (VOID *self)
 		clearwait = true;
 	    }
 	  break;
+	case __SIGEXIT:
+	  sigproc_printf ("saw __SIGEXIT");
+	  break;	/* handle below */
 	default:
 	  if (pack.si.si_signo < 0)
 	    sig_clear (-pack.si.si_signo);
@@ -1120,18 +1121,23 @@ wait_sig (VOID *self)
 	  SetEvent (pack.wakeup);
 	  sigproc_printf ("signalled %p", pack.wakeup);
 	}
+      if (pack.si.si_signo == __SIGEXIT)
+	break;
     }
 
   my_sendsig = NULL;
-  sigproc_printf ("done");
-  if (WaitForSingleObject (hMainThread, 5000) == WAIT_OBJECT_0)
+  DWORD res = WaitForSingleObject (hMainThread, 10000);
+
+  if (res != WAIT_OBJECT_0)
+    sigproc_printf ("wait for main thread returned %d", res);
+  else
     {
       DWORD exitcode = 1;
       myself.release ();
+      sigproc_printf ("calling ExitProcess, exitcode %p", exitcode);
       GetExitCodeThread (hMainThread, &exitcode);
-      sigproc_printf ("Calling ExitProcess, exitcode %p",
-		      exitcode);
       ExitProcess (exitcode);
     }
+  sigproc_printf ("exiting thread");
   ExitThread (0);
 }
diff --git a/winsup/cygwin/sigproc.h b/winsup/cygwin/sigproc.h
index c135f32b3..a8895df7a 100644
--- a/winsup/cygwin/sigproc.h
+++ b/winsup/cygwin/sigproc.h
@@ -73,7 +73,7 @@ int __stdcall proc_subproc (DWORD, DWORD) __attribute__ ((regparm (2)));
 class _pinfo;
 void __stdcall proc_terminate ();
 void __stdcall sigproc_init ();
-void __stdcall sigproc_terminate ();
+void __stdcall sigproc_terminate (enum exit_states);
 bool __stdcall pid_exists (pid_t) __attribute__ ((regparm(1)));
 int __stdcall sig_send (_pinfo *, siginfo_t&, class _cygtls *tls = NULL) __attribute__ ((regparm (3)));
 int __stdcall sig_send (_pinfo *, int) __attribute__ ((regparm (2)));
diff --git a/winsup/cygwin/winsup.h b/winsup/cygwin/winsup.h
index 2bc40b170..960c6c4fa 100644
--- a/winsup/cygwin/winsup.h
+++ b/winsup/cygwin/winsup.h
@@ -193,10 +193,10 @@ enum exit_states
     ES_THREADTERM,
     ES_SIGNAL,
     ES_CLOSEALL,
-    ES_SIGPROCTERMINATE,
-    ES_TITLE,
     ES_HUP_PGRP,
     ES_HUP_SID,
+    ES_SIGPROCTERMINATE,
+    ES_TITLE,
     ES_TTY_TERMINATE,
     ES_FINAL
   };