/* 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.
#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];
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. */
return 1;
}
-static void
+void
stackdump (DWORD ebp, int open_file, bool isexception)
{
static bool already_dumped;
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)
}
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
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
{
case WAIT_OBJECT_0:
case WAIT_OBJECT_0 + 1:
- reset_signal_arrived ();
myself->stopsig = SIGCONT;
myself->alert_parent (SIGCONT);
break;
/* 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);
}
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:
ctrl_c_handler (DWORD type)
{
static bool saw_close;
- lock_process now;
if (!cygwin_finished_initializing)
{
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);
}
}
- 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
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);
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;
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 ()
{
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
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)
{