OSDN Git Service

Rename cygWFMO to cygwait throughout and use the magic of polymorphism to "wait
[pf3gnuchains/pf3gnuchains4x.git] / winsup / cygwin / exceptions.cc
index 7176657..b16e816 100644 (file)
@@ -1,7 +1,7 @@
 /* exceptions.cc
 
    Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
-   2005, 2006, 2007, 2008, 2009, 2010 Red Hat, Inc.
+   2005, 2006, 2007, 2008, 2009, 2010, 2011 Red Hat, Inc.
 
 This file is part of Cygwin.
 
@@ -32,7 +32,8 @@ details. */
 #include "ntdll.h"
 #include "exception.h"
 
-#define CALL_HANDLER_RETRY 20
+#define CALL_HANDLER_RETRY_OUTER 10
+#define CALL_HANDLER_RETRY_INNER 10
 
 char debugger_command[2 * NT_MAX_PATH + 20];
 
@@ -40,8 +41,6 @@ extern "C" {
 extern void sigdelayed ();
 };
 
-extern child_info_spawn *chExeced;
-
 static BOOL WINAPI ctrl_c_handler (DWORD);
 
 /* This is set to indicate that we have already exited.  */
@@ -280,7 +279,7 @@ stack_info::walk ()
   return 1;
 }
 
-static void
+void
 stackdump (DWORD ebp, int open_file, bool isexception)
 {
   static bool already_dumped;
@@ -601,8 +600,8 @@ exception::handle (EXCEPTION_RECORD *e, exception_list *frame, CONTEXT *in, void
       return 1;
     }
 
-  debug_printf ("In cygwin_except_handler exc %p at %p sp %p", e->ExceptionCode, in->Eip, in->Esp);
-  debug_printf ("In cygwin_except_handler sig %d at %p", si.si_signo, in->Eip);
+  debug_printf ("In cygwin_except_handler exception %p at %p sp %p", e->ExceptionCode, in->Eip, in->Esp);
+  debug_printf ("In cygwin_except_handler signal %d at %p", si.si_signo, in->Eip);
 
   bool masked = !!(me.sigmask & SIGTOMASK (si.si_signo));
   if (masked)
@@ -688,8 +687,8 @@ exception::handle (EXCEPTION_RECORD *e, exception_list *frame, CONTEXT *in, void
     }
 
   si.si_addr =  (si.si_signo == SIGSEGV || si.si_signo == SIGBUS
-                 ? (void *) e->ExceptionInformation[1]
-                 : (void *) in->Eip);
+                ? (void *) e->ExceptionInformation[1]
+                : (void *) in->Eip);
   si.si_errno = si.si_pid = si.si_uid = 0;
   me.incyg++;
   sig_send (NULL, si, &me);    // Signal myself
@@ -712,19 +711,13 @@ exception::handle (EXCEPTION_RECORD *e, exception_list *frame, CONTEXT *in, void
 int __stdcall
 handle_sigsuspend (sigset_t tempmask)
 {
-  if (&_my_tls != _main_tls)
-    {
-      cancelable_wait (signal_arrived, INFINITE, cw_cancel_self);
-      return -1;
-    }
-
   sigset_t oldmask = _my_tls.sigmask;  // Remember for restoration
 
   set_signal_mask (tempmask, _my_tls.sigmask);
   sigproc_printf ("oldmask %p, newmask %p", oldmask, tempmask);
 
   pthread_testcancel ();
-  cancelable_wait (signal_arrived, INFINITE);
+  cancelable_wait (signal_arrived);
 
   set_sig_errno (EINTR);       // Per POSIX
 
@@ -762,7 +755,6 @@ sig_handle_tty_stop (int sig)
     {
     case WAIT_OBJECT_0:
     case WAIT_OBJECT_0 + 1:
-      reset_signal_arrived ();
       myself->stopsig = SIGCONT;
       myself->alert_parent (SIGCONT);
       break;
@@ -827,7 +819,7 @@ _cygtls::interrupt_setup (int sig, void *handler, struct sigaction& siga)
   /* Clear any waiting threads prior to dispatching to handler function */
   int res = SetEvent (signal_arrived); // For an EINTR case
   proc_subproc (PROC_CLEARWAIT, 1);
-  sigproc_printf ("armed signal_arrived %p, sig %d, res %d", signal_arrived,
+  sigproc_printf ("armed signal_arrived %p, signal %d, res %d", signal_arrived,
                  sig, res);
 }
 
@@ -849,57 +841,59 @@ setup_handler (int sig, void *handler, struct sigaction& siga, _cygtls *tls)
 
   if (tls->sig)
     {
-      sigproc_printf ("trying to send sig %d but signal %d already armed",
+      sigproc_printf ("trying to send signal %d but signal %d already armed",
                      sig, tls->sig);
       goto out;
     }
 
-  for (int i = 0; i < CALL_HANDLER_RETRY; i++)
+  for (int n = 0; n < CALL_HANDLER_RETRY_OUTER; n++)
     {
-      tls->lock ();
-      if (tls->incyg)
+      for (int i = 0; i < CALL_HANDLER_RETRY_INNER; i++)
        {
-         sigproc_printf ("controlled interrupt. stackptr %p, stack %p, stackptr[-1] %p",
-                         tls->stackptr, tls->stack, tls->stackptr[-1]);
-         tls->interrupt_setup (sig, handler, siga);
-         interrupted = true;
-         tls->unlock ();
-         break;
-       }
+         tls->lock ();
+         if (tls->incyg)
+           {
+             sigproc_printf ("controlled interrupt. stackptr %p, stack %p, stackptr[-1] %p",
+                             tls->stackptr, tls->stack, tls->stackptr[-1]);
+             tls->interrupt_setup (sig, handler, siga);
+             interrupted = true;
+             tls->unlock ();
+             goto out;
+           }
 
-      DWORD res;
-      HANDLE hth = (HANDLE) *tls;
-
-      /* Suspend the thread which will receive the signal.
-        For Windows 95, we also have to ensure that the addresses returned by
-        GetThreadContext are valid.
-        If one of these conditions is not true we loop for a fixed number of times
-        since we don't want to stall the signal handler.  FIXME: Will this result in
-        noticeable delays?
-        If the thread is already suspended (which can occur when a program has called
-        SuspendThread on itself) then just queue the signal. */
-
-      sigproc_printf ("suspending thread");
-      res = SuspendThread (hth);
-      /* Just set pending if thread is already suspended */
-      if (res)
-       {
-         ResumeThread (hth);
-         break;
-       }
-      cx.ContextFlags = CONTEXT_CONTROL | CONTEXT_INTEGER;
-      if (!GetThreadContext (hth, &cx))
-       system_printf ("couldn't get context of thread, %E");
-      else
-       interrupted = tls->interrupt_now (&cx, sig, handler, siga);
+         DWORD res;
+         HANDLE hth = (HANDLE) *tls;
 
-      tls->unlock ();
-      res = ResumeThread (hth);
-      if (interrupted)
-       break;
+         /* Suspend the thread which will receive the signal.
+            If one of these conditions is not true we loop.
+            If the thread is already suspended (which can occur when a program
+            has called SuspendThread on itself) then just queue the signal. */
+
+         sigproc_printf ("suspending thread");
+         res = SuspendThread (hth);
+         /* Just set pending if thread is already suspended */
+         if (res)
+           {
+             ResumeThread (hth);
+             goto out;
+           }
+         cx.ContextFlags = CONTEXT_CONTROL | CONTEXT_INTEGER;
+         if (!GetThreadContext (hth, &cx))
+           system_printf ("couldn't get context of thread, %E");
+         else
+           interrupted = tls->interrupt_now (&cx, sig, handler, siga);
+
+         tls->unlock ();
+         res = ResumeThread (hth);
+         if (interrupted)
+           goto out;
 
-      sigproc_printf ("couldn't interrupt.  trying again.");
-      yield ();
+         sigproc_printf ("couldn't interrupt.  trying again.");
+         yield ();
+       }
+      /* Hit here if we couldn't deliver the signal.  Take a more drastic
+        action before trying again. */
+      Sleep (1);
     }
 
 out:
@@ -933,7 +927,6 @@ static BOOL WINAPI
 ctrl_c_handler (DWORD type)
 {
   static bool saw_close;
-  lock_process now;
 
   if (!cygwin_finished_initializing)
     {
@@ -943,8 +936,6 @@ ctrl_c_handler (DWORD type)
       ExitProcess (STATUS_CONTROL_C_EXIT);
     }
 
-  _my_tls.remove (INFINITE);
-
 #if 0
   if (type == CTRL_C_EVENT || type == CTRL_BREAK_EVENT)
     proc_subproc (PROC_KILLFORKED, 0);
@@ -991,21 +982,18 @@ ctrl_c_handler (DWORD type)
        }
     }
 
-  if (chExeced)
-    {
-      chExeced->set_saw_ctrl_c ();
-      return TRUE;
-    }
+  if (ch_spawn.set_saw_ctrl_c ())
+    return TRUE;
 
   /* We're only the process group leader when we have a valid pinfo structure.
      If we don't have one, then the parent "stub" will handle the signal. */
   if (!pinfo (cygwin_pid (GetCurrentProcessId ())))
     return TRUE;
 
-  tty_min *t = cygwin_shared->tty.get_tty (myself->ctty);
+  tty_min *t = cygwin_shared->tty.get_cttyp ();
   /* Ignore this if we're not the process group leader since it should be handled
      *by* the process group leader. */
-  if (myself->ctty != -1 && t->getpgid () == myself->pid &&
+  if (t && t->getpgid () == myself->pid &&
        (GetTickCount () - t->last_ctrl_c) >= MIN_CTRL_C_SLOP)
     /* Otherwise we just send a SIGINT to the process group and return TRUE (to indicate
        that we have handled the signal).  At this point, type should be
@@ -1174,6 +1162,19 @@ sigpacket::process ()
       sig_clear (SIGTTOU);
     }
 
+  switch (si.si_signo)
+    {
+    case SIGINT:
+    case SIGQUIT:
+    case SIGSTOP:
+    case SIGTSTP:
+      if (cygheap->ctty)
+       cygheap->ctty->sigflush ();
+      break;
+    default:
+      break;
+    }
+
   int rc = 1;
 
   sigproc_printf ("signal %d processing", si.si_signo);
@@ -1183,7 +1184,7 @@ sigpacket::process ()
 
   bool masked;
   void *handler;
-  if (!hExeced || (void *) thissig.sa_handler == (void *) SIG_IGN)
+  if (!have_execed || (void *) thissig.sa_handler == (void *) SIG_IGN)
     handler = (void *) thissig.sa_handler;
   else if (tls)
     return 1;
@@ -1302,47 +1303,9 @@ thread_specific:
   goto done;
 
 exit_sig:
-  if (si.si_signo == SIGQUIT || si.si_signo == SIGABRT)
-    {
-      CONTEXT c;
-      c.ContextFlags = CONTEXT_FULL;
-      GetThreadContext (hMainThread, &c);
-      use_tls->copy_context (&c);
-      if (cygheap->rlim_core > 0UL)
-       si.si_signo |= 0x80;
-    }
-  sigproc_printf ("signal %d, about to call do_exit", si.si_signo);
   use_tls->signal_exit (si.si_signo);  /* never returns */
 }
 
-/* Cover function to `do_exit' to handle exiting even in presence of more
-   exceptions.  We used to call exit, but a SIGSEGV shouldn't cause atexit
-   routines to run.  */
-void
-_cygtls::signal_exit (int rc)
-{
-  if (hExeced)
-    {
-      sigproc_printf ("terminating captive process");
-      TerminateProcess (hExeced, sigExeced = rc);
-    }
-
-  signal_debugger (rc & 0x7f);
-  if ((rc & 0x80) && !try_to_debug ())
-    stackdump (thread_context.ebp, 1, 1);
-
-  lock_process until_exit (true);
-  if (hExeced || exit_state > ES_PROCESS_LOCKED)
-    myself.exit (rc);
-
-  /* Starve other threads in a vain attempt to stop them from doing something
-     stupid. */
-  SetThreadPriority (GetCurrentThread (), THREAD_PRIORITY_TIME_CRITICAL);
-
-  sigproc_printf ("about to call do_exit (%x)", rc);
-  do_exit (rc);
-}
-
 void
 events_init ()
 {
@@ -1358,25 +1321,42 @@ events_terminate ()
 int
 _cygtls::call_signal_handler ()
 {
-  int this_sa_flags = 0;
-  /* Call signal handler.  */
-  while (sig && func)
+  int this_sa_flags = SA_RESTART;
+  while (1)
     {
       lock ();
+      if (sig)
+       pop ();
+      else if (this != _main_tls)
+       {
+         _main_tls->lock ();
+         if (_main_tls->sig)
+           {
+             sig = _main_tls->sig;
+             sa_flags = _main_tls->sa_flags;
+             func = _main_tls->func;
+             infodata = _main_tls->infodata;
+             _main_tls->pop ();
+             _main_tls->sig = 0;
+
+           }
+         _main_tls->unlock ();
+       }
+      if (!sig)
+       break;
+
       this_sa_flags = sa_flags;
       int thissig = sig;
       void (*thisfunc) (int) = func;
 
-      pop ();
-      reset_signal_arrived ();
       sigset_t this_oldmask = set_process_mask_delta ();
       int this_errno = saved_errno;
       sig = 0;
       unlock ();       // make sure synchronized
-      incyg = 0;
       if (!(this_sa_flags & SA_SIGINFO))
        {
          void (*sigfunc) (int) = thisfunc;
+         incyg = false;
          sigfunc (thissig);
        }
       else
@@ -1384,27 +1364,19 @@ _cygtls::call_signal_handler ()
          siginfo_t thissi = infodata;
          void (*sigact) (int, siginfo_t *, void *) = (void (*) (int, siginfo_t *, void *)) thisfunc;
          /* no ucontext_t information provided yet */
+         incyg = false;
          sigact (thissig, &thissi, NULL);
        }
-      incyg = 1;
+      incyg = true;
       set_signal_mask (this_oldmask, _my_tls.sigmask);
       if (this_errno >= 0)
        set_errno (this_errno);
     }
 
+  unlock ();
   return this_sa_flags & SA_RESTART;
 }
 
-extern "C" void __stdcall
-reset_signal_arrived ()
-{
-  // NEEDED? WaitForSingleObject (signal_arrived, 10);
-  ResetEvent (signal_arrived);
-  sigproc_printf ("reset signal_arrived");
-  if (_my_tls.stackptr > _my_tls.stack)
-    debug_printf ("stackptr[-1] %p", _my_tls.stackptr[-1]);
-}
-
 void
 _cygtls::copy_context (CONTEXT *c)
 {