/* exceptions.cc
Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
- 2005, 2006 Red Hat, Inc.
+ 2005, 2006, 2007, 2008, 2009, 2010, 2011 Red Hat, Inc.
This file is part of Cygwin.
Cygwin license. Please consult the file "CYGWIN_LICENSE" for
details. */
+#define CYGTLS_HANDLE
#include "winsup.h"
+#include "miscfuncs.h"
#include <wingdi.h>
#include <winuser.h>
#include <imagehlp.h>
#include <stdlib.h>
-#include <setjmp.h>
-#include <assert.h>
#include <syslog.h>
+#include <wchar.h>
-#include "exceptions.h"
-#include "sync.h"
#include "pinfo.h"
#include "cygtls.h"
#include "sigproc.h"
-#include "cygerrno.h"
#include "shared_info.h"
#include "perprocess.h"
-#include "security.h"
#include "path.h"
#include "fhandler.h"
#include "dtable.h"
#include "cygheap.h"
+#include "child_info.h"
+#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 * CYG_MAX_PATH + 20];
+char debugger_command[2 * NT_MAX_PATH + 20];
extern "C" {
extern void sigdelayed ();
};
-extern NO_COPY DWORD dwExeced;
-int NO_COPY sigExeced;
-
static BOOL WINAPI ctrl_c_handler (DWORD);
-char windows_system_directory[1024];
-static size_t windows_system_directory_length;
/* This is set to indicate that we have already exited. */
/* Initialization code. */
-BOOL WINAPI
-dummy_ctrl_c_handler (DWORD dwCtrlType)
-{
- return TRUE;
-}
-
void
-init_console_handler (BOOL install_handler)
+init_console_handler (bool install_handler)
{
BOOL res;
- while (SetConsoleCtrlHandler (ctrl_c_handler, FALSE))
- continue;
+
+ SetConsoleCtrlHandler (ctrl_c_handler, FALSE);
+ SetConsoleCtrlHandler (NULL, FALSE);
if (install_handler)
res = SetConsoleCtrlHandler (ctrl_c_handler, TRUE);
- else if (wincap.has_null_console_handler_routine ())
- res = SetConsoleCtrlHandler (NULL, TRUE);
else
- res = SetConsoleCtrlHandler (dummy_ctrl_c_handler, TRUE);
+ res = SetConsoleCtrlHandler (NULL, TRUE);
if (!res)
system_printf ("SetConsoleCtrlHandler failed, %E");
}
return;
}
- char pgm[CYG_MAX_PATH];
- if (!GetModuleFileName (NULL, pgm, CYG_MAX_PATH))
+ char pgm[NT_MAX_PATH];
+ if (!GetModuleFileName (NULL, pgm, NT_MAX_PATH))
strcpy (pgm, "cygwin1.dll");
for (char *p = strchr (pgm, '\\'); p; p = strchr (p, '\\'))
*p = '/';
static void
open_stackdumpfile ()
{
- if (myself->progname[0])
+ /* If we have no executable name, or if the CWD handle is NULL,
+ which means, the CWD is a virtual path, don't even try to open
+ a stackdump file. */
+ if (myself->progname[0] && cygheap->cwd.get_handle ())
{
- const char *p;
+ const WCHAR *p;
/* write to progname.stackdump if possible */
if (!myself->progname[0])
- p = "unknown";
- else if ((p = strrchr (myself->progname, '\\')))
+ p = L"unknown";
+ else if ((p = wcsrchr (myself->progname, L'\\')))
p++;
else
p = myself->progname;
- char corefile[strlen (p) + sizeof (".stackdump")];
- __small_sprintf (corefile, "%s.stackdump", p);
- HANDLE h = CreateFile (corefile, GENERIC_WRITE, 0, &sec_none_nih,
- CREATE_ALWAYS, 0, 0);
- if (h != INVALID_HANDLE_VALUE)
+
+ WCHAR corefile[wcslen (p) + sizeof (".stackdump")];
+ wcpcpy (wcpcpy(corefile, p), L".stackdump");
+ UNICODE_STRING ucore;
+ OBJECT_ATTRIBUTES attr;
+ /* Create the UNICODE variation of <progname>.stackdump. */
+ RtlInitUnicodeString (&ucore, corefile);
+ /* Create an object attribute which refers to <progname>.stackdump
+ in Cygwin's cwd. Stick to caseinsensitivity. */
+ InitializeObjectAttributes (&attr, &ucore, OBJ_CASE_INSENSITIVE,
+ cygheap->cwd.get_handle (), NULL);
+ HANDLE h;
+ IO_STATUS_BLOCK io;
+ NTSTATUS status;
+ /* Try to open it to dump the stack in it. */
+ status = NtCreateFile (&h, GENERIC_WRITE | SYNCHRONIZE, &attr, &io,
+ NULL, FILE_ATTRIBUTE_NORMAL, 0, FILE_OVERWRITE_IF,
+ FILE_SYNCHRONOUS_IO_NONALERT
+ | FILE_OPEN_FOR_BACKUP_INTENT, NULL, 0);
+ if (NT_SUCCESS (status))
{
if (!myself->cygstarted)
- system_printf ("Dumping stack trace to %s", corefile);
+ system_printf ("Dumping stack trace to %S", &ucore);
else
- debug_printf ("Dumping stack trace to %s", corefile);
+ debug_printf ("Dumping stack trace to %S", &ucore);
SetStdHandle (STD_ERROR_HANDLE, h);
}
}
/* Utilities for dumping the stack, etc. */
static void
-exception (EXCEPTION_RECORD *e, CONTEXT *in)
+dump_exception (EXCEPTION_RECORD *e, CONTEXT *in)
{
const char *exception_name = NULL;
small_printf ("Signal %d at eip=%08x\r\n", e->ExceptionCode, in->Eip);
small_printf ("eax=%08x ebx=%08x ecx=%08x edx=%08x esi=%08x edi=%08x\r\n",
in->Eax, in->Ebx, in->Ecx, in->Edx, in->Esi, in->Edi);
- small_printf ("ebp=%08x esp=%08x program=%s, pid %u, thread %s\r\n",
+ small_printf ("ebp=%08x esp=%08x program=%W, pid %u, thread %s\r\n",
in->Ebp, in->Esp, myself->progname, myself->pid, cygthread::name ());
small_printf ("cs=%04x ds=%04x es=%04x fs=%04x gs=%04x ss=%04x\r\n",
in->SegCs, in->SegDs, in->SegEs, in->SegFs, in->SegGs, in->SegSs);
# undef debp
}
+extern "C" void _cygwin_exit_return ();
+
/* Walk the stack by looking at successive stored 'bp' frames.
This is not foolproof. */
int
stack_info::walk ()
{
char **ebp;
- if ((ebp = (char **) next_offset ()) == NULL)
+
+ if ((void (*) ()) sf.AddrPC.Offset == _cygwin_exit_return)
+ return 0; /* stack frames are exhausted */
+
+ if (((ebp = (char **) next_offset ()) == NULL) || (ebp >= (char **) cygwin_hmodule))
return 0;
sf.AddrFrame.Offset = (DWORD) ebp;
sf.AddrPC.Offset = sf.AddrReturn.Offset;
- if (!sf.AddrPC.Offset)
- return 0; /* stack frames are exhausted */
-
/* The return address always follows the stack pointer */
sf.AddrReturn.Offset = (DWORD) *++ebp;
if (needargs)
- /* The arguments follow the return address */
- for (unsigned i = 0; i < NPARAMS; i++)
- sf.Params[i] = (DWORD) *++ebp;
+ {
+ unsigned nparams = NPARAMS;
+
+ /* The arguments follow the return address */
+ sf.Params[0] = (DWORD) *++ebp;
+ /* Hack for XP/2K3 WOW64. If the first stack param points to the
+ application entry point, we can only fetch one additional
+ parameter. Accessing anything beyond this address results in
+ a SEGV. This is fixed in Vista/2K8 WOW64. */
+ if (wincap.has_restricted_stack_args () && sf.Params[0] == 0x401000)
+ nparams = 2;
+ for (unsigned i = 1; i < nparams; i++)
+ sf.Params[i] = (DWORD) *++ebp;
+ }
return 1;
}
-static void
+void
stackdump (DWORD ebp, int open_file, bool isexception)
{
- extern unsigned long rlim_core;
static bool already_dumped;
- if (rlim_core == 0UL || (open_file && already_dumped))
+ if (cygheap->rlim_core == 0UL || (open_file && already_dumped))
return;
if (open_file)
i == 16 ? " (more stack frames may be present)" : "");
}
-static bool
-inside_kernel (CONTEXT *cx)
+bool
+_cygtls::inside_kernel (CONTEXT *cx)
{
int res;
MEMORY_BASIC_INFORMATION m;
+ if (!isinitialized ())
+ return true;
+
memset (&m, 0, sizeof m);
if (!VirtualQuery ((LPCVOID) cx->Eip, &m, sizeof m))
sigproc_printf ("couldn't get memory info, pc %p, %E", cx->Eip);
- char *checkdir = (char *) alloca (windows_system_directory_length + 4);
- memset (checkdir, 0, sizeof (checkdir));
+ size_t size = (windows_system_directory_length + 6) * sizeof (WCHAR);
+ PWCHAR checkdir = (PWCHAR) alloca (size);
+ memset (checkdir, 0, size);
# define h ((HMODULE) m.AllocationBase)
/* Apparently Windows 95 can sometimes return bogus addresses from
GetThreadContext. These resolve to a strange allocation base.
These should *never* be treated as interruptible. */
if (!h || m.State != MEM_COMMIT)
- res = false;
- else if (h == user_data->hmodule)
- res = true;
- else if (!GetModuleFileName (h, checkdir, windows_system_directory_length + 2))
res = true;
+ else if (h == user_data->hmodule)
+ res = false;
+ else if (!GetModuleFileNameW (h, checkdir, windows_system_directory_length + 6))
+ res = false;
else
- res = !strncasematch (windows_system_directory, checkdir,
+ {
+ /* Skip potential long path prefix. */
+ if (!wcsncmp (checkdir, L"\\\\?\\", 4))
+ checkdir += 4;
+ res = !wcsncasecmp (windows_system_directory, checkdir,
windows_system_directory_length);
- sigproc_printf ("pc %p, h %p, interruptible %d", cx->Eip, h, res);
+ }
+ sigproc_printf ("pc %p, h %p, inside_kernel %d", cx->Eip, h, res);
# undef h
return res;
}
return 0;
if (being_debugged ())
{
- DebugBreak ();
+ extern void break_here ();
+ break_here ();
return 0;
}
SetThreadPriority (GetCurrentThread (), THREAD_PRIORITY_HIGHEST);
PROCESS_INFORMATION pi = {NULL, 0, 0, 0};
- STARTUPINFO si = {0, NULL, NULL, NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL};
+ STARTUPINFOW si = {0, NULL, NULL, NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL};
si.lpReserved = NULL;
si.lpDesktop = NULL;
si.dwFlags = 0;
suspend_all_threads_except (current_thread_id);
*/
- /* if any of these mutexes is owned, we will fail to start any cygwin app
- until trapped app exits */
+ /* If the tty mutex is owned, we will fail to start any cygwin app
+ until the trapped app exits. However, this will only release any
+ the mutex if it is owned by this thread so that may be problematic. */
- ReleaseMutex (tty_mutex);
+ lock_ttys::release ();
/* prevent recursive exception handling */
- char* rawenv = GetEnvironmentStrings () ;
- for (char* p = rawenv; *p != '\0'; p = strchr (p, '\0') + 1)
+ PWCHAR rawenv = GetEnvironmentStringsW () ;
+ for (PWCHAR p = rawenv; *p != L'\0'; p = wcschr (p, L'\0') + 1)
{
- if (strncmp (p, "CYGWIN=", strlen ("CYGWIN=")) == 0)
+ if (wcsncmp (p, L"CYGWIN=", wcslen (L"CYGWIN=")) == 0)
{
- char* q = strstr (p, "error_start") ;
+ PWCHAR q = wcsstr (p, L"error_start") ;
/* replace 'error_start=...' with '_rror_start=...' */
if (q)
{
- *q = '_' ;
- SetEnvironmentVariable ("CYGWIN", p + strlen ("CYGWIN=")) ;
+ *q = L'_' ;
+ SetEnvironmentVariableW (L"CYGWIN", p + wcslen (L"CYGWIN=")) ;
}
break ;
}
console_printf ("*** starting debugger for pid %u, tid %u\n",
cygwin_pid (GetCurrentProcessId ()), GetCurrentThreadId ());
BOOL dbg;
- dbg = CreateProcess (NULL,
- debugger_command,
- NULL,
- NULL,
- FALSE,
- CREATE_NEW_CONSOLE | CREATE_NEW_PROCESS_GROUP,
- NULL,
- NULL,
- &si,
- &pi);
+ WCHAR dbg_cmd[strlen(debugger_command)];
+ sys_mbstowcs (dbg_cmd, strlen(debugger_command) + 1, debugger_command);
+ dbg = CreateProcessW (NULL,
+ dbg_cmd,
+ NULL,
+ NULL,
+ FALSE,
+ CREATE_NEW_CONSOLE | CREATE_NEW_PROCESS_GROUP,
+ NULL,
+ NULL,
+ &si,
+ &pi);
if (!dbg)
system_printf ("Failed to start debugger, %E");
return dbg;
SetThreadPriority (GetCurrentThread (), THREAD_PRIORITY_IDLE);
while (!being_debugged ())
- low_priority_sleep (0);
+ yield ();
Sleep (2000);
}
/* Main exception handler. */
-extern "C" char *__progname;
+extern exception_list *_except_list asm ("%fs:0");
+
int
-_cygtls::handle_exceptions (EXCEPTION_RECORD *e, exception_list *frame, CONTEXT *in, void *)
+exception::handle (EXCEPTION_RECORD *e, exception_list *frame, CONTEXT *in, void *)
{
static bool NO_COPY debugging;
static int NO_COPY recursed;
break;
case STATUS_ACCESS_VIOLATION:
- if (mmap_is_attached_page (e->ExceptionInformation[1]))
+ switch (mmap_is_attached_or_noreserve ((void *)e->ExceptionInformation[1],
+ 1))
{
+ case MMAP_NORESERVE_COMMITED:
+ return 0;
+ case MMAP_RAISE_SIGBUS: /* MAP_NORESERVE page, commit failed, or
+ access to mmap page beyond EOF. */
si.si_signo = SIGBUS;
si.si_code = BUS_OBJERR;
- }
- else
- {
+ break;
+ default:
MEMORY_BASIC_INFORMATION m;
VirtualQuery ((PVOID) e->ExceptionInformation[1], &m, sizeof m);
si.si_signo = SIGSEGV;
si.si_code = m.State == MEM_FREE ? SEGV_MAPERR : SEGV_ACCERR;
+ break;
}
break;
return 1;
}
- rtl_unwind (frame, e);
+ 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);
- 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);
-
- if (global_sigs[si.si_signo].sa_mask & SIGTOMASK (si.si_signo))
+ bool masked = !!(me.sigmask & SIGTOMASK (si.si_signo));
+ if (masked)
syscall_printf ("signal %d, masked %p", si.si_signo,
global_sigs[si.si_signo].sa_mask);
break;
}
- if (me.fault_guarded ())
- me.return_from_fault ();
+ if (me.andreas)
+ me.andreas->leave (); /* Return from a "san" caught fault */
me.copy_context (in);
- if (!cygwin_finished_initializing
+
+ /* Temporarily replace windows top level SEH with our own handler.
+ We don't want any Windows magic kicking in. This top level frame
+ will be removed automatically after our exception handler returns. */
+ _except_list->handler = handle;
+
+ if (masked
|| &me == _sig_tls
+ || !cygwin_finished_initializing
|| (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)
return 0;
}
- open_stackdumpfile ();
- exception (e, in);
- stackdump ((DWORD) ebp, 0, 1);
+ rtl_unwind (frame, e);
+ if (cygheap->rlim_core > 0UL)
+ {
+ open_stackdumpfile ();
+ dump_exception (e, in);
+ stackdump ((DWORD) ebp, 0, 1);
+ }
}
if (e->ExceptionCode == STATUS_ACCESS_VIOLATION)
error_code |= 1;
if (e->ExceptionInformation[0]) /* Write access */
error_code |= 2;
- if (!inside_kernel (in)) /* User space */
+ if (!me.inside_kernel (in)) /* User space */
error_code |= 4;
klog (LOG_INFO, "%s[%d]: segfault at %08x rip %08x rsp %08x error %d",
__progname, myself->pid,
? 0 : 4) | (e->ExceptionInformation[0] << 1));
}
- me.signal_exit (0x80 | si.si_signo); // Flag signal + core dump
+ /* Flag signal + core dump */
+ me.signal_exit ((cygheap->rlim_core > 0UL ? 0x80 : 0) | si.si_signo);
}
- si.si_addr = (void *) in->Eip;
+ si.si_addr = (si.si_signo == SIGSEGV || si.si_signo == SIGBUS
+ ? (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
- sigset_t oldmask = myself->getsigmask (); // Remember for restoration
-
- set_signal_mask (tempmask, myself->getsigmask ());
+ 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;
default:
{
bool interrupted;
- if (incyg || spinning || locked () || !inside_kernel (cx))
+ /* Delay the interrupt if we are
+ 1) somehow inside the DLL
+ 2) in _sigfe (spinning is true) and about to enter cygwin DLL
+ 3) in a Windows DLL. */
+ if (incyg || spinning || inside_kernel (cx))
interrupted = false;
else
{
/* 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;
+ }
- tls->unlock ();
- 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. */
-
-#ifndef DEBUGGING
- sigproc_printf ("suspending mainthread");
-#else
- cx.ContextFlags = CONTEXT_CONTROL | CONTEXT_INTEGER;
- if (!GetThreadContext (hth, &cx))
- memset (&cx, 0, sizeof cx);
- sigproc_printf ("suspending mainthread PC %p", cx.Eip);
-#endif
- 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 main thread, %E");
- else
- interrupted = tls->interrupt_now (&cx, sig, handler, siga);
+ DWORD res;
+ HANDLE hth = (HANDLE) *tls;
- 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 ("couldn't interrupt. trying again.");
- low_priority_sleep (0);
+ 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 ();
+ }
+ /* Hit here if we couldn't deliver the signal. Take a more drastic
+ action before trying again. */
+ Sleep (1);
}
out:
with the desktop (using the "Allow service to interact with desktop"
property) are running in an invisible window station. */
if ((station_hdl = GetProcessWindowStation ())
- && GetUserObjectInformationA (station_hdl, UOI_FLAGS, &uof,
+ && GetUserObjectInformationW (station_hdl, UOI_FLAGS, &uof,
sizeof uof, &len)
&& (uof.dwFlags & WSF_VISIBLE))
return true;
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 (!saw_close && type == CTRL_LOGOFF_EVENT)
{
-#if 0
- /* CV, 2005-09-08: The CTRL_LOGOFF_EVENT is only send to services.
- It's send when *any* user logs off. Services generally have
- a modified console handler which allows services to survive
- also after a user logged out, even if the service has a console
- window attached to the visible window station of the user
- ("Interact with desktop"). The below code contradicts this
- standard behaviour, so for now, we disable it and just return
- FALSE to get the default behaviour or the one the application's
- own console handler (if any) requires.
- In other words: We never send SIGHUP to services and their
- child processes on a LOGOFF event. */
-
- /* Check if the process is actually associated with a visible
- window station, one which actually represents a visible desktop.
- If not, the CTRL_LOGOFF_EVENT doesn't concern this process. */
- if (has_visible_window_station ())
- sig_send (myself_nowait, SIGHUP);
-#endif
+ /* The CTRL_LOGOFF_EVENT is sent when *any* user logs off.
+ The below code sends a SIGHUP only if it is not performing the
+ default activity for SIGHUP. Note that it is possible for two
+ SIGHUP signals to arrive if a process group leader is exiting
+ too. Getting this 100% right is saved for a future cygwin mailing
+ list goad. */
+ if (global_sigs[SIGHUP].sa_handler != SIG_DFL)
+ {
+ sig_send (myself_nowait, SIGHUP);
+ return TRUE;
+ }
return FALSE;
}
}
- /* If we are a stub and the new process has a pinfo structure, let it
- handle this signal. */
- if (dwExeced && pinfo (dwExeced))
+ if (ch_spawn.set_saw_ctrl_c ())
return TRUE;
/* We're only the process group leader when we have a valid pinfo structure.
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
extern "C" void __stdcall
set_process_mask (sigset_t newmask)
{
- set_signal_mask (newmask, myself->getsigmask ());
-sigproc_printf ("mask now %p\n", myself->getsigmask ());
+ set_signal_mask (newmask, _my_tls.sigmask);
}
extern "C" int
return -1;
}
mask_sync.acquire (INFINITE);
- sigset_t mask = myself->getsigmask ();
+ sigset_t mask = _my_tls.sigmask;
sigaddset (&mask, sig);
- set_signal_mask (mask, myself->getsigmask ());
+ set_signal_mask (mask, _my_tls.sigmask);
mask_sync.release ();
return 0;
}
return -1;
}
mask_sync.acquire (INFINITE);
- sigset_t mask = myself->getsigmask ();
+ sigset_t mask = _my_tls.sigmask;
sigdelset (&mask, sig);
- set_signal_mask (mask, myself->getsigmask ());
+ set_signal_mask (mask, _my_tls.sigmask);
mask_sync.release ();
return 0;
}
}
mask_sync.acquire (INFINITE);
- sigset_t mask = myself->getsigmask ();
+ sigset_t mask = _my_tls.sigmask;
/* If sig was in the signal mask return SIG_HOLD, otherwise return the
previous disposition. */
if (sigismember (&mask, sig))
else
{
/* No error checking. The test which could return SIG_ERR has already
- been made above. */
+ been made above. */
signal (sig, func);
sigdelset (&mask, sig);
}
- set_signal_mask (mask, myself->getsigmask ());
+ set_signal_mask (mask, _my_tls.sigmask);
mask_sync.release ();
return prev;
}
if (_my_tls.deltamask & SIG_NONMASKABLE)
oldmask = _my_tls.oldmask; /* from handle_sigsuspend */
else
- oldmask = myself->getsigmask ();
+ oldmask = _my_tls.sigmask;
newmask = (oldmask | _my_tls.deltamask) & ~SIG_NONMASKABLE;
sigproc_printf ("oldmask %p, newmask %p, deltamask %p", oldmask, newmask,
_my_tls.deltamask);
- myself->setsigmask (newmask);
+ _my_tls.sigmask = newmask;
mask_sync.release ();
return oldmask;
}
sigpacket::process ()
{
DWORD continue_now;
+ struct sigaction dummy = global_sigs[SIGSTOP];
+
if (si.si_signo != SIGCONT)
continue_now = false;
else
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;
else
handler = NULL;
+ _cygtls *use_tls = tls ?: _main_tls;
+
if (si.si_signo == SIGKILL)
goto exit_sig;
if (si.si_signo == SIGSTOP)
{
sig_clear (SIGCONT);
- if (!tls)
- tls = _main_tls;
goto stop;
}
bool insigwait_mask;
if ((masked = ISSTATE (myself, PID_STOPPED)))
insigwait_mask = false;
- else if (!tls)
- insigwait_mask = !handler && (tls = _cygtls::find_tls (si.si_signo));
- else
+ else if (tls)
insigwait_mask = sigismember (&tls->sigwait_mask, si.si_signo);
+ else if (!(tls = _cygtls::find_tls (si.si_signo)))
+ insigwait_mask = false;
+ else
+ {
+ use_tls = tls;
+ insigwait_mask = true;
+ }
if (insigwait_mask)
goto thread_specific;
else if (tls)
masked = sigismember (&tls->sigmask, si.si_signo);
- if (!tls)
- tls = _main_tls;
-
if (masked)
{
sigproc_printf ("signal %d blocked", si.si_signo);
if (handler == (void *) SIG_ERR)
goto exit_sig;
- tls->set_siginfo (this);
+ use_tls->set_siginfo (this);
goto dosig;
stop:
if (ISSTATE (myself, PID_STOPPED))
goto done;
handler = (void *) sig_handle_tty_stop;
- struct sigaction dummy = global_sigs[SIGSTOP];
thissig = dummy;
dosig:
/* Dispatch to the appropriate function. */
sigproc_printf ("signal %d, about to call %p", si.si_signo, handler);
- rc = setup_handler (si.si_signo, handler, thissig, tls);
+ rc = setup_handler (si.si_signo, handler, thissig, use_tls);
done:
+ tls = use_tls;
if (continue_now)
SetEvent (sigCONT);
sigproc_printf ("returning %d", rc);
return rc;
thread_specific:
- tls->sig = si.si_signo;
- tls->set_siginfo (this);
+ use_tls->sig = si.si_signo;
+ use_tls->set_siginfo (this);
+ use_tls->func = NULL;
sigproc_printf ("releasing sigwait for thread");
- SetEvent (tls->event);
+ SetEvent (use_tls->event);
goto done;
exit_sig:
- if (si.si_signo == SIGQUIT || si.si_signo == SIGABRT)
- {
- CONTEXT c;
- c.ContextFlags = CONTEXT_FULL;
- GetThreadContext (hMainThread, &c);
- tls->copy_context (&c);
- si.si_signo |= 0x80;
- }
- sigproc_printf ("signal %d, about to call do_exit", si.si_signo);
- tls->signal_exit (si.si_signo); /* never returns */
+ 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)
- myself.exit (rc);
-
- /* Starve other threads in a vain attempt to stop them from doing something
- stupid. */
- SetThreadPriority (GetCurrentThread (), THREAD_PRIORITY_TIME_CRITICAL);
-
- user_data->resourcelocks->Delete ();
- user_data->resourcelocks->Init ();
-
- sigproc_printf ("about to call do_exit (%x)", rc);
- SetEvent (signal_arrived);
- do_exit (rc);
-}
-
-HANDLE NO_COPY tty_mutex = NULL;
-
void
events_init ()
{
- char *name;
- char mutex_name[CYG_MAX_PATH];
- /* tty_mutex is on while searching for a tty slot. It's necessary
- while finding console window handle */
-
- if (!(tty_mutex = CreateMutex (&sec_all_nih, FALSE,
- name = shared_name (mutex_name,
- "tty_mutex", 0))))
- api_fatal ("can't create title mutex '%s', %E", name);
-
- ProtectHandle (tty_mutex);
mask_sync.init ("mask_sync");
- windows_system_directory[0] = '\0';
- GetSystemDirectory (windows_system_directory, sizeof (windows_system_directory) - 2);
- char *end = strchr (windows_system_directory, '\0');
- if (end == windows_system_directory)
- api_fatal ("can't find windows system directory");
- if (end[-1] != '\\')
- {
- *end++ = '\\';
- *end = '\0';
- }
- windows_system_directory_length = end - windows_system_directory;
- debug_printf ("windows_system_directory '%s', windows_system_directory_length %d",
- windows_system_directory, windows_system_directory_length);
}
void
int
_cygtls::call_signal_handler ()
{
- int this_sa_flags = 0;
- /* Call signal handler. */
- while (sig)
+ 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) = func;
+ void (*sigfunc) (int) = thisfunc;
+ incyg = false;
sigfunc (thissig);
}
else
{
siginfo_t thissi = infodata;
- void (*sigact) (int, siginfo_t *, void *) = (void (*) (int, siginfo_t *, void *)) func;
+ 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;
- set_signal_mask (this_oldmask, myself->getsigmask ());
+ 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)
{
void
_cygtls::signal_debugger (int sig)
{
- if (being_debugged ())
+ if (isinitialized () && being_debugged ())
{
char sigmsg[2 * sizeof (_CYGWIN_SIGNAL_STRING " ffffffff ffffffff")];
__small_sprintf (sigmsg, _CYGWIN_SIGNAL_STRING " %d %p %p", sig, thread_id, &thread_context);