OSDN Git Service

* exceptions.cc (open_stackdumpfile): Add comments.
[pf3gnuchains/pf3gnuchains4x.git] / winsup / cygwin / exceptions.cc
1 /* exceptions.cc
2
3    Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
4    2005, 2006, 2007 Red Hat, Inc.
5
6 This file is part of Cygwin.
7
8 This software is a copyrighted work licensed under the terms of the
9 Cygwin license.  Please consult the file "CYGWIN_LICENSE" for
10 details. */
11
12 #include "winsup.h"
13 #include <wingdi.h>
14 #include <winuser.h>
15 #include <imagehlp.h>
16 #include <stdlib.h>
17 #include <setjmp.h>
18 #include <assert.h>
19 #include <syslog.h>
20
21 #include "exceptions.h"
22 #include "sync.h"
23 #include "pinfo.h"
24 #include "cygtls.h"
25 #include "sigproc.h"
26 #include "cygerrno.h"
27 #include "shared_info.h"
28 #include "perprocess.h"
29 #include "security.h"
30 #include "path.h"
31 #include "fhandler.h"
32 #include "dtable.h"
33 #include "cygheap.h"
34 #include "child_info.h"
35 #include "ntdll.h"
36
37 #define CALL_HANDLER_RETRY 20
38
39 char debugger_command[2 * NT_MAX_PATH + 20];
40
41 extern "C" {
42 extern void sigdelayed ();
43 };
44
45 extern child_info_spawn *chExeced;
46 int NO_COPY sigExeced;
47
48 static BOOL WINAPI ctrl_c_handler (DWORD);
49 char windows_system_directory[1024];
50 static size_t windows_system_directory_length;
51
52 /* This is set to indicate that we have already exited.  */
53
54 static NO_COPY int exit_already = 0;
55 static muto NO_COPY mask_sync;
56
57 NO_COPY static struct
58 {
59   unsigned int code;
60   const char *name;
61 } status_info[] =
62 {
63 #define X(s) s, #s
64   { X (STATUS_ABANDONED_WAIT_0) },
65   { X (STATUS_ACCESS_VIOLATION) },
66   { X (STATUS_ARRAY_BOUNDS_EXCEEDED) },
67   { X (STATUS_BREAKPOINT) },
68   { X (STATUS_CONTROL_C_EXIT) },
69   { X (STATUS_DATATYPE_MISALIGNMENT) },
70   { X (STATUS_FLOAT_DENORMAL_OPERAND) },
71   { X (STATUS_FLOAT_DIVIDE_BY_ZERO) },
72   { X (STATUS_FLOAT_INEXACT_RESULT) },
73   { X (STATUS_FLOAT_INVALID_OPERATION) },
74   { X (STATUS_FLOAT_OVERFLOW) },
75   { X (STATUS_FLOAT_STACK_CHECK) },
76   { X (STATUS_FLOAT_UNDERFLOW) },
77   { X (STATUS_GUARD_PAGE_VIOLATION) },
78   { X (STATUS_ILLEGAL_INSTRUCTION) },
79   { X (STATUS_INTEGER_DIVIDE_BY_ZERO) },
80   { X (STATUS_INTEGER_OVERFLOW) },
81   { X (STATUS_INVALID_DISPOSITION) },
82   { X (STATUS_IN_PAGE_ERROR) },
83   { X (STATUS_NONCONTINUABLE_EXCEPTION) },
84   { X (STATUS_NO_MEMORY) },
85   { X (STATUS_PENDING) },
86   { X (STATUS_PRIVILEGED_INSTRUCTION) },
87   { X (STATUS_SINGLE_STEP) },
88   { X (STATUS_STACK_OVERFLOW) },
89   { X (STATUS_TIMEOUT) },
90   { X (STATUS_USER_APC) },
91   { X (STATUS_WAIT_0) },
92   { 0, 0 }
93 #undef X
94 };
95
96 /* Initialization code.  */
97
98 void
99 init_console_handler (bool install_handler)
100 {
101   BOOL res;
102
103   SetConsoleCtrlHandler (ctrl_c_handler, FALSE);
104   SetConsoleCtrlHandler (NULL, FALSE);
105   if (install_handler)
106     res = SetConsoleCtrlHandler (ctrl_c_handler, TRUE);
107   else
108     res = SetConsoleCtrlHandler (NULL, TRUE);
109   if (!res)
110     system_printf ("SetConsoleCtrlHandler failed, %E");
111 }
112
113 extern "C" void
114 error_start_init (const char *buf)
115 {
116   if (!buf || !*buf)
117     {
118       debugger_command[0] = '\0';
119       return;
120     }
121
122   char pgm[NT_MAX_PATH];
123   if (!GetModuleFileName (NULL, pgm, NT_MAX_PATH))
124     strcpy (pgm, "cygwin1.dll");
125   for (char *p = strchr (pgm, '\\'); p; p = strchr (p, '\\'))
126     *p = '/';
127
128   __small_sprintf (debugger_command, "%s \"%s\"", buf, pgm);
129 }
130
131 static void
132 open_stackdumpfile ()
133 {
134   if (myself->progname[0])
135     {
136       const char *p;
137       /* write to progname.stackdump if possible */
138       if (!myself->progname[0])
139         p = "unknown";
140       else if ((p = strrchr (myself->progname, '\\')))
141         p++;
142       else
143         p = myself->progname;
144
145       WCHAR corefile[strlen (p) + sizeof (".stackdump")];
146       UNICODE_STRING ucore;
147       OBJECT_ATTRIBUTES attr;
148       /* Create the UNICODE variation of <progname>.stackdump. */
149       RtlInitEmptyUnicodeString (&ucore, corefile,
150                                  sizeof corefile - sizeof (WCHAR));
151       ucore.Length = sys_mbstowcs (ucore.Buffer,
152                                    ucore.MaximumLength / sizeof (WCHAR),
153                                    p, strlen (p)) * sizeof (WCHAR);
154       RtlAppendUnicodeToString (&ucore, L".stackdump");
155       /* Create an object attribute which refers to <progname>.stackdump
156          in Cygwin's cwd. */
157       InitializeObjectAttributes (&attr, &ucore, OBJ_CASE_INSENSITIVE,
158                                   cygheap->cwd.get_handle (), NULL);
159       HANDLE h;
160       IO_STATUS_BLOCK io;
161       NTSTATUS status;
162       /* Try to open it to dump the stack in it. */
163       status = NtCreateFile (&h, GENERIC_WRITE | SYNCHRONIZE, &attr, &io,
164                              NULL, FILE_ATTRIBUTE_NORMAL, 0, FILE_OVERWRITE_IF,
165                              FILE_SYNCHRONOUS_IO_NONALERT
166                              | FILE_OPEN_FOR_BACKUP_INTENT
167                              | FILE_OPEN_FOR_RECOVERY, NULL, 0);
168       if (NT_SUCCESS (status))
169         {
170           if (!myself->cygstarted)
171             system_printf ("Dumping stack trace to %s", corefile);
172           else
173             debug_printf ("Dumping stack trace to %s", corefile);
174           SetStdHandle (STD_ERROR_HANDLE, h);
175         }
176     }
177 }
178
179 /* Utilities for dumping the stack, etc.  */
180
181 static void
182 exception (EXCEPTION_RECORD *e,  CONTEXT *in)
183 {
184   const char *exception_name = NULL;
185
186   if (e)
187     {
188       for (int i = 0; status_info[i].name; i++)
189         {
190           if (status_info[i].code == e->ExceptionCode)
191             {
192               exception_name = status_info[i].name;
193               break;
194             }
195         }
196     }
197
198   if (exception_name)
199     small_printf ("Exception: %s at eip=%08x\r\n", exception_name, in->Eip);
200   else
201     small_printf ("Signal %d at eip=%08x\r\n", e->ExceptionCode, in->Eip);
202   small_printf ("eax=%08x ebx=%08x ecx=%08x edx=%08x esi=%08x edi=%08x\r\n",
203                 in->Eax, in->Ebx, in->Ecx, in->Edx, in->Esi, in->Edi);
204   small_printf ("ebp=%08x esp=%08x program=%s, pid %u, thread %s\r\n",
205                 in->Ebp, in->Esp, myself->progname, myself->pid, cygthread::name ());
206   small_printf ("cs=%04x ds=%04x es=%04x fs=%04x gs=%04x ss=%04x\r\n",
207                 in->SegCs, in->SegDs, in->SegEs, in->SegFs, in->SegGs, in->SegSs);
208 }
209
210 /* A class for manipulating the stack. */
211 class stack_info
212 {
213   int walk ();                  /* Uses the "old" method */
214   char *next_offset () {return *((char **) sf.AddrFrame.Offset);}
215   bool needargs;
216   DWORD dummy_frame;
217 public:
218   STACKFRAME sf;                 /* For storing the stack information */
219   void init (DWORD, bool, bool); /* Called the first time that stack info is needed */
220
221   /* Postfix ++ iterates over the stack, returning zero when nothing is left. */
222   int operator ++(int) { return walk (); }
223 };
224
225 /* The number of parameters used in STACKFRAME */
226 #define NPARAMS (sizeof (thestack.sf.Params) / sizeof (thestack.sf.Params[0]))
227
228 /* This is the main stack frame info for this process. */
229 static NO_COPY stack_info thestack;
230
231 /* Initialize everything needed to start iterating. */
232 void
233 stack_info::init (DWORD ebp, bool wantargs, bool goodframe)
234 {
235 # define debp ((DWORD *) ebp)
236   memset (&sf, 0, sizeof (sf));
237   if (!goodframe)
238     sf.AddrFrame.Offset = ebp;
239   else
240     {
241       dummy_frame = ebp;
242       sf.AddrFrame.Offset = (DWORD) &dummy_frame;
243     }
244   sf.AddrReturn.Offset = debp[1];
245   sf.AddrFrame.Mode = AddrModeFlat;
246   needargs = wantargs;
247 # undef debp
248 }
249
250 /* Walk the stack by looking at successive stored 'bp' frames.
251    This is not foolproof. */
252 int
253 stack_info::walk ()
254 {
255   char **ebp;
256   if ((ebp = (char **) next_offset ()) == NULL)
257     return 0;
258
259   sf.AddrFrame.Offset = (DWORD) ebp;
260   sf.AddrPC.Offset = sf.AddrReturn.Offset;
261
262   if (!sf.AddrPC.Offset)
263     return 0;           /* stack frames are exhausted */
264
265   /* The return address always follows the stack pointer */
266   sf.AddrReturn.Offset = (DWORD) *++ebp;
267
268   if (needargs)
269     {
270       unsigned nparams = NPARAMS;
271
272       /* The arguments follow the return address */
273       sf.Params[0] = (DWORD) *++ebp;
274       /* Hack for XP/2K3 WOW64.  If the first stack param points to the
275          application entry point, we can only fetch one additional
276          parameter.  Accessing anything beyond this address results in
277          a SEGV.  This is fixed in Vista/2K8 WOW64. */
278       if (wincap.has_restricted_stack_args () && sf.Params[0] == 0x401000)
279         nparams = 2;
280       for (unsigned i = 1; i < nparams; i++)
281         sf.Params[i] = (DWORD) *++ebp;
282     }
283
284   return 1;
285 }
286
287 static void
288 stackdump (DWORD ebp, int open_file, bool isexception)
289 {
290   extern unsigned long rlim_core;
291   static bool already_dumped;
292
293   if (rlim_core == 0UL || (open_file && already_dumped))
294     return;
295
296   if (open_file)
297     open_stackdumpfile ();
298
299   already_dumped = true;
300
301   int i;
302
303   thestack.init (ebp, 1, !isexception); /* Initialize from the input CONTEXT */
304   small_printf ("Stack trace:\r\nFrame     Function  Args\r\n");
305   for (i = 0; i < 16 && thestack++; i++)
306     {
307       small_printf ("%08x  %08x ", thestack.sf.AddrFrame.Offset,
308                     thestack.sf.AddrPC.Offset);
309       for (unsigned j = 0; j < NPARAMS; j++)
310         small_printf ("%s%08x", j == 0 ? " (" : ", ", thestack.sf.Params[j]);
311       small_printf (")\r\n");
312     }
313   small_printf ("End of stack trace%s\n",
314               i == 16 ? " (more stack frames may be present)" : "");
315 }
316
317 bool
318 _cygtls::inside_kernel (CONTEXT *cx)
319 {
320   int res;
321   MEMORY_BASIC_INFORMATION m;
322
323   if (!isinitialized ())
324     return true;
325
326   memset (&m, 0, sizeof m);
327   if (!VirtualQuery ((LPCVOID) cx->Eip, &m, sizeof m))
328     sigproc_printf ("couldn't get memory info, pc %p, %E", cx->Eip);
329
330   char *checkdir = (char *) alloca (windows_system_directory_length + 4);
331   memset (checkdir, 0, sizeof (checkdir));
332
333 # define h ((HMODULE) m.AllocationBase)
334   /* Apparently Windows 95 can sometimes return bogus addresses from
335      GetThreadContext.  These resolve to a strange allocation base.
336      These should *never* be treated as interruptible. */
337   if (!h || m.State != MEM_COMMIT)
338     res = true;
339   else if (h == user_data->hmodule)
340     res = false;
341   else if (!GetModuleFileName (h, checkdir, windows_system_directory_length + 2))
342     res = false;
343   else
344     res = strncasematch (windows_system_directory, checkdir,
345                          windows_system_directory_length);
346   sigproc_printf ("pc %p, h %p, inside_kernel %d", cx->Eip, h, res);
347 # undef h
348   return res;
349 }
350
351 /* Temporary (?) function for external callers to get a stack dump */
352 extern "C" void
353 cygwin_stackdump ()
354 {
355   CONTEXT c;
356   c.ContextFlags = CONTEXT_FULL;
357   GetThreadContext (GetCurrentThread (), &c);
358   stackdump (c.Ebp, 0, 0);
359 }
360
361 #define TIME_TO_WAIT_FOR_DEBUGGER 10000
362
363 extern "C" int
364 try_to_debug (bool waitloop)
365 {
366   WCHAR dbg_cmd[sizeof debugger_command];
367
368   debug_printf ("debugger_command '%s'", debugger_command);
369   if (*debugger_command == '\0')
370     return 0;
371   if (being_debugged ())
372     {
373       extern void break_here ();
374       break_here ();
375       return 0;
376     }
377
378   __small_sprintf (strchr (debugger_command, '\0'), " %u", GetCurrentProcessId ());
379
380   LONG prio = GetThreadPriority (GetCurrentThread ());
381   SetThreadPriority (GetCurrentThread (), THREAD_PRIORITY_HIGHEST);
382   PROCESS_INFORMATION pi = {NULL, 0, 0, 0};
383
384   STARTUPINFOW si = {0, NULL, NULL, NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL};
385   si.lpReserved = NULL;
386   si.lpDesktop = NULL;
387   si.dwFlags = 0;
388   si.cb = sizeof (si);
389
390   /* FIXME: need to know handles of all running threads to
391      suspend_all_threads_except (current_thread_id);
392   */
393
394   /* if any of these mutexes is owned, we will fail to start any cygwin app
395      until trapped app exits */
396
397   lock_ttys::release ();
398
399   /* prevent recursive exception handling */
400   char* rawenv = GetEnvironmentStrings () ;
401   for (char* p = rawenv; *p != '\0'; p = strchr (p, '\0') + 1)
402     {
403       if (strncmp (p, "CYGWIN=", strlen ("CYGWIN=")) == 0)
404         {
405           char* q = strstr (p, "error_start") ;
406           /* replace 'error_start=...' with '_rror_start=...' */
407           if (q)
408             {
409               *q = '_' ;
410               SetEnvironmentVariable ("CYGWIN", p + strlen ("CYGWIN=")) ;
411             }
412           break ;
413         }
414     }
415
416   console_printf ("*** starting debugger for pid %u, tid %u\n",
417                   cygwin_pid (GetCurrentProcessId ()), GetCurrentThreadId ());
418   BOOL dbg;
419   sys_mbstowcs (dbg_cmd, sizeof debugger_command, debugger_command);
420   dbg = CreateProcessW (NULL,
421                         dbg_cmd,
422                         NULL,
423                         NULL,
424                         FALSE,
425                         CREATE_NEW_CONSOLE | CREATE_NEW_PROCESS_GROUP,
426                         NULL,
427                         NULL,
428                         &si,
429                         &pi);
430
431   if (!dbg)
432     system_printf ("Failed to start debugger, %E");
433   else
434     {
435       if (!waitloop)
436         return dbg;
437       SetThreadPriority (GetCurrentThread (), THREAD_PRIORITY_IDLE);
438       while (!being_debugged ())
439         low_priority_sleep (0);
440       Sleep (2000);
441     }
442
443   console_printf ("*** continuing pid %u from debugger call (%d)\n",
444                   cygwin_pid (GetCurrentProcessId ()), dbg);
445
446   SetThreadPriority (GetCurrentThread (), prio);
447   return dbg;
448 }
449
450 extern "C" DWORD __stdcall RtlUnwind (void *, void *, void *, DWORD);
451 static void __stdcall rtl_unwind (exception_list *, PEXCEPTION_RECORD) __attribute__ ((noinline, regparm (3)));
452 void __stdcall
453 rtl_unwind (exception_list *frame, PEXCEPTION_RECORD e)
454 {
455   __asm__ ("\n\
456   pushl         %%ebx                                   \n\
457   pushl         %%edi                                   \n\
458   pushl         %%esi                                   \n\
459   pushl         $0                                      \n\
460   pushl         %1                                      \n\
461   pushl         $1f                                     \n\
462   pushl         %0                                      \n\
463   call          _RtlUnwind@16                           \n\
464 1:                                                      \n\
465   popl          %%esi                                   \n\
466   popl          %%edi                                   \n\
467   popl          %%ebx                                   \n\
468 ": : "r" (frame), "r" (e));
469 }
470
471 /* Main exception handler. */
472
473 extern "C" char *__progname;
474 int
475 _cygtls::handle_exceptions (EXCEPTION_RECORD *e, exception_list *frame, CONTEXT *in, void *)
476 {
477   static bool NO_COPY debugging;
478   static int NO_COPY recursed;
479   _cygtls& me = _my_tls;
480
481   if (debugging && ++debugging < 500000)
482     {
483       SetThreadPriority (hMainThread, THREAD_PRIORITY_NORMAL);
484       return 0;
485     }
486
487   /* If we've already exited, don't do anything here.  Returning 1
488      tells Windows to keep looking for an exception handler.  */
489   if (exit_already || e->ExceptionFlags)
490     return 1;
491
492   siginfo_t si = {0};
493   si.si_code = SI_KERNEL;
494   /* Coerce win32 value to posix value.  */
495   switch (e->ExceptionCode)
496     {
497     case STATUS_FLOAT_DENORMAL_OPERAND:
498     case STATUS_FLOAT_DIVIDE_BY_ZERO:
499     case STATUS_FLOAT_INVALID_OPERATION:
500     case STATUS_FLOAT_STACK_CHECK:
501       si.si_signo = SIGFPE;
502       si.si_code = FPE_FLTSUB;
503       break;
504     case STATUS_FLOAT_INEXACT_RESULT:
505       si.si_signo = SIGFPE;
506       si.si_code = FPE_FLTRES;
507       break;
508     case STATUS_FLOAT_OVERFLOW:
509       si.si_signo = SIGFPE;
510       si.si_code = FPE_FLTOVF;
511       break;
512     case STATUS_FLOAT_UNDERFLOW:
513       si.si_signo = SIGFPE;
514       si.si_code = FPE_FLTUND;
515       break;
516     case STATUS_INTEGER_DIVIDE_BY_ZERO:
517       si.si_signo = SIGFPE;
518       si.si_code = FPE_INTDIV;
519       break;
520     case STATUS_INTEGER_OVERFLOW:
521       si.si_signo = SIGFPE;
522       si.si_code = FPE_INTOVF;
523       break;
524
525     case STATUS_ILLEGAL_INSTRUCTION:
526       si.si_signo = SIGILL;
527       si.si_code = ILL_ILLOPC;
528       break;
529
530     case STATUS_PRIVILEGED_INSTRUCTION:
531       si.si_signo = SIGILL;
532       si.si_code = ILL_PRVOPC;
533       break;
534
535     case STATUS_NONCONTINUABLE_EXCEPTION:
536       si.si_signo = SIGILL;
537       si.si_code = ILL_ILLADR;
538       break;
539
540     case STATUS_TIMEOUT:
541       si.si_signo = SIGALRM;
542       break;
543
544     case STATUS_GUARD_PAGE_VIOLATION:
545       si.si_signo = SIGBUS;
546       si.si_code = BUS_OBJERR;
547       break;
548
549     case STATUS_DATATYPE_MISALIGNMENT:
550       si.si_signo = SIGBUS;
551       si.si_code = BUS_ADRALN;
552       break;
553
554     case STATUS_ACCESS_VIOLATION:
555       switch (mmap_is_attached_or_noreserve ((void *)e->ExceptionInformation[1],
556                                              1))
557         {
558         case MMAP_NORESERVE_COMMITED:
559           return 0;
560         case MMAP_RAISE_SIGBUS: /* MAP_NORESERVE page, commit failed, or
561                                    access to mmap page beyond EOF. */
562           si.si_signo = SIGBUS;
563           si.si_code = BUS_OBJERR;
564           break;
565         default:
566           MEMORY_BASIC_INFORMATION m;
567           VirtualQuery ((PVOID) e->ExceptionInformation[1], &m, sizeof m);
568           si.si_signo = SIGSEGV;
569           si.si_code = m.State == MEM_FREE ? SEGV_MAPERR : SEGV_ACCERR;
570           break;
571         }
572       break;
573
574     case STATUS_ARRAY_BOUNDS_EXCEEDED:
575     case STATUS_IN_PAGE_ERROR:
576     case STATUS_NO_MEMORY:
577     case STATUS_INVALID_DISPOSITION:
578     case STATUS_STACK_OVERFLOW:
579       si.si_signo = SIGSEGV;
580       si.si_code = SEGV_MAPERR;
581       break;
582
583     case STATUS_CONTROL_C_EXIT:
584       si.si_signo = SIGINT;
585       break;
586
587     case STATUS_INVALID_HANDLE:
588       /* CloseHandle will throw this exception if it is given an
589          invalid handle.  We don't care about the exception; we just
590          want CloseHandle to return an error.  This can be revisited
591          if gcc ever supports Windows style structured exception
592          handling.  */
593       return 0;
594
595     default:
596       /* If we don't recognize the exception, we have to assume that
597          we are doing structured exception handling, and we let
598          something else handle it.  */
599       return 1;
600     }
601
602   rtl_unwind (frame, e);
603
604   debug_printf ("In cygwin_except_handler exc %p at %p sp %p", e->ExceptionCode, in->Eip, in->Esp);
605   debug_printf ("In cygwin_except_handler sig %d at %p", si.si_signo, in->Eip);
606
607   if (global_sigs[si.si_signo].sa_mask & SIGTOMASK (si.si_signo))
608     syscall_printf ("signal %d, masked %p", si.si_signo,
609                     global_sigs[si.si_signo].sa_mask);
610
611   debug_printf ("In cygwin_except_handler calling %p",
612                  global_sigs[si.si_signo].sa_handler);
613
614   DWORD *ebp = (DWORD *) in->Esp;
615   for (DWORD *bpend = (DWORD *) __builtin_frame_address (0); ebp > bpend; ebp--)
616     if (*ebp == in->SegCs && ebp[-1] == in->Eip)
617       {
618         ebp -= 2;
619         break;
620       }
621
622   if (me.fault_guarded ())
623     me.return_from_fault ();
624
625   me.copy_context (in);
626   if (!cygwin_finished_initializing
627       || &me == _sig_tls
628       || (void *) global_sigs[si.si_signo].sa_handler == (void *) SIG_DFL
629       || (void *) global_sigs[si.si_signo].sa_handler == (void *) SIG_IGN
630       || (void *) global_sigs[si.si_signo].sa_handler == (void *) SIG_ERR)
631     {
632       /* Print the exception to the console */
633       if (!myself->cygstarted)
634         for (int i = 0; status_info[i].name; i++)
635           if (status_info[i].code == e->ExceptionCode)
636             {
637               system_printf ("Exception: %s", status_info[i].name);
638               break;
639             }
640
641       /* Another exception could happen while tracing or while exiting.
642          Only do this once.  */
643       if (recursed++)
644         system_printf ("Error while dumping state (probably corrupted stack)");
645       else
646         {
647           if (try_to_debug (0))
648             {
649               debugging = true;
650               return 0;
651             }
652
653           open_stackdumpfile ();
654           exception (e, in);
655           stackdump ((DWORD) ebp, 0, 1);
656         }
657
658       if (e->ExceptionCode == STATUS_ACCESS_VIOLATION)
659         {
660           int error_code = 0;
661           if (si.si_code == SEGV_ACCERR)        /* Address present */
662             error_code |= 1;
663           if (e->ExceptionInformation[0])       /* Write access */
664             error_code |= 2;
665           if (!me.inside_kernel (in))           /* User space */
666             error_code |= 4;
667           klog (LOG_INFO, "%s[%d]: segfault at %08x rip %08x rsp %08x error %d",
668                           __progname, myself->pid,
669                           e->ExceptionInformation[1], in->Eip, in->Esp,
670                           ((in->Eip >= 0x61000000 && in->Eip < 0x61200000)
671                            ? 0 : 4) | (e->ExceptionInformation[0] << 1));
672         }
673
674       me.signal_exit (0x80 | si.si_signo);      // Flag signal + core dump
675     }
676
677   si.si_addr = (void *) in->Eip;
678   si.si_errno = si.si_pid = si.si_uid = 0;
679   me.incyg++;
680   sig_send (NULL, si, &me);     // Signal myself
681   me.incyg--;
682   e->ExceptionFlags = 0;
683   /* The OS adds an exception list frame to the stack.  It expects to be
684      able to remove this entry after the exception handler returned.
685      However, when unwinding to our frame, our frame becomes the uppermost
686      frame on the stack (%fs:0 points to frame).  This way, our frame
687      is removed from the exception stack and just disappears.  So, we can't
688      just return here or things will be screwed up by the helpful function
689      in (presumably) ntdll.dll.
690
691      So, instead, we will do the equivalent of a longjmp here and return
692      to the caller without visiting any of the helpful code installed prior
693      to this function.  This should work ok, since a longjmp() out of here has
694      to work if linux signal semantics are to be maintained. */
695
696   SetThreadContext (GetCurrentThread (), in);
697   return 0; /* Never actually returns.  This is just to keep gcc happy. */
698 }
699
700 /* Utilities to call a user supplied exception handler.  */
701
702 #define SIG_NONMASKABLE (SIGTOMASK (SIGKILL) | SIGTOMASK (SIGSTOP))
703
704 /* Non-raceable sigsuspend
705  * Note: This implementation is based on the Single UNIX Specification
706  * man page.  This indicates that sigsuspend always returns -1 and that
707  * attempts to block unblockable signals will be silently ignored.
708  * This is counter to what appears to be documented in some UNIX
709  * man pages, e.g. Linux.
710  */
711 int __stdcall
712 handle_sigsuspend (sigset_t tempmask)
713 {
714   if (&_my_tls != _main_tls)
715     {
716       cancelable_wait (signal_arrived, INFINITE, cw_cancel_self);
717       return -1;
718     }
719
720   sigset_t oldmask = _my_tls.sigmask;   // Remember for restoration
721
722   set_signal_mask (tempmask, _my_tls.sigmask);
723   sigproc_printf ("oldmask %p, newmask %p", oldmask, tempmask);
724
725   pthread_testcancel ();
726   cancelable_wait (signal_arrived, INFINITE);
727
728   set_sig_errno (EINTR);        // Per POSIX
729
730   /* A signal dispatch function will have been added to our stack and will
731      be hit eventually.  Set the old mask to be restored when the signal
732      handler returns and indicate its presence by modifying deltamask. */
733
734   _my_tls.deltamask |= SIG_NONMASKABLE;
735   _my_tls.oldmask = oldmask;    // Will be restored by signal handler
736   return -1;
737 }
738
739 extern DWORD exec_exit;         // Possible exit value for exec
740
741 extern "C" {
742 static void
743 sig_handle_tty_stop (int sig)
744 {
745   _my_tls.incyg = 1;
746   /* Silently ignore attempts to suspend if there is no accommodating
747      cygwin parent to deal with this behavior. */
748   if (!myself->cygstarted)
749     {
750       myself->process_state &= ~PID_STOPPED;
751       return;
752     }
753
754   myself->stopsig = sig;
755   myself->alert_parent (sig);
756   sigproc_printf ("process %d stopped by signal %d", myself->pid, sig);
757   HANDLE w4[2];
758   w4[0] = sigCONT;
759   w4[1] = signal_arrived;
760   switch (WaitForMultipleObjects (2, w4, TRUE, INFINITE))
761     {
762     case WAIT_OBJECT_0:
763     case WAIT_OBJECT_0 + 1:
764       reset_signal_arrived ();
765       myself->alert_parent (SIGCONT);
766       break;
767     default:
768       api_fatal ("WaitSingleObject failed, %E");
769       break;
770     }
771   _my_tls.incyg = 0;
772 }
773 }
774
775 bool
776 _cygtls::interrupt_now (CONTEXT *cx, int sig, void *handler,
777                         struct sigaction& siga)
778 {
779   bool interrupted;
780
781   if (incyg || spinning || locked () || inside_kernel (cx))
782     interrupted = false;
783   else
784     {
785       push ((__stack_t) cx->Eip);
786       interrupt_setup (sig, handler, siga);
787       cx->Eip = pop ();
788       SetThreadContext (*this, cx); /* Restart the thread in a new location */
789       interrupted = true;
790     }
791   return interrupted;
792 }
793
794 void __stdcall
795 _cygtls::interrupt_setup (int sig, void *handler, struct sigaction& siga)
796 {
797   push ((__stack_t) sigdelayed);
798   deltamask = siga.sa_mask & ~SIG_NONMASKABLE;
799   sa_flags = siga.sa_flags;
800   func = (void (*) (int)) handler;
801   if (siga.sa_flags & SA_RESETHAND)
802     siga.sa_handler = SIG_DFL;
803   saved_errno = -1;             // Flag: no errno to save
804   if (handler == sig_handle_tty_stop)
805     {
806       myself->stopsig = 0;
807       myself->process_state |= PID_STOPPED;
808     }
809
810   this->sig = sig;                      // Should always be last thing set to avoid a race
811
812   if (!event)
813     threadkill = false;
814   else
815     {
816       HANDLE h = event;
817       event = NULL;
818       SetEvent (h);
819     }
820
821   /* Clear any waiting threads prior to dispatching to handler function */
822   int res = SetEvent (signal_arrived);  // For an EINTR case
823   proc_subproc (PROC_CLEARWAIT, 1);
824   sigproc_printf ("armed signal_arrived %p, sig %d, res %d", signal_arrived,
825                   sig, res);
826 }
827
828 extern "C" void __stdcall
829 set_sig_errno (int e)
830 {
831   *_my_tls.errno_addr = e;
832   _my_tls.saved_errno = e;
833   // sigproc_printf ("errno %d", e);
834 }
835
836 static int setup_handler (int, void *, struct sigaction&, _cygtls *tls)
837   __attribute__((regparm(3)));
838 static int
839 setup_handler (int sig, void *handler, struct sigaction& siga, _cygtls *tls)
840 {
841   CONTEXT cx;
842   bool interrupted = false;
843
844   if (tls->sig)
845     {
846       sigproc_printf ("trying to send sig %d but signal %d already armed",
847                       sig, tls->sig);
848       goto out;
849     }
850
851   for (int i = 0; i < CALL_HANDLER_RETRY; i++)
852     {
853       tls->lock ();
854       if (tls->incyg)
855         {
856           sigproc_printf ("controlled interrupt. stackptr %p, stack %p, stackptr[-1] %p",
857                           tls->stackptr, tls->stack, tls->stackptr[-1]);
858           tls->interrupt_setup (sig, handler, siga);
859           interrupted = true;
860           tls->unlock ();
861           break;
862         }
863
864       tls->unlock ();
865       DWORD res;
866       HANDLE hth = (HANDLE) *tls;
867
868       /* Suspend the thread which will receive the signal.
869          For Windows 95, we also have to ensure that the addresses returned by
870          GetThreadContext are valid.
871          If one of these conditions is not true we loop for a fixed number of times
872          since we don't want to stall the signal handler.  FIXME: Will this result in
873          noticeable delays?
874          If the thread is already suspended (which can occur when a program has called
875          SuspendThread on itself) then just queue the signal. */
876
877 #ifndef DEBUGGING
878       sigproc_printf ("suspending mainthread");
879 #else
880       cx.ContextFlags = CONTEXT_CONTROL | CONTEXT_INTEGER;
881       if (!GetThreadContext (hth, &cx))
882         memset (&cx, 0, sizeof cx);
883       sigproc_printf ("suspending mainthread PC %p", cx.Eip);
884 #endif
885       res = SuspendThread (hth);
886       /* Just set pending if thread is already suspended */
887       if (res)
888         {
889           ResumeThread (hth);
890           break;
891         }
892       cx.ContextFlags = CONTEXT_CONTROL | CONTEXT_INTEGER;
893       if (!GetThreadContext (hth, &cx))
894         system_printf ("couldn't get context of main thread, %E");
895       else
896         interrupted = tls->interrupt_now (&cx, sig, handler, siga);
897
898       res = ResumeThread (hth);
899       if (interrupted)
900         break;
901
902       sigproc_printf ("couldn't interrupt.  trying again.");
903       low_priority_sleep (0);
904     }
905
906 out:
907   sigproc_printf ("signal %d %sdelivered", sig, interrupted ? "" : "not ");
908   return interrupted;
909 }
910
911 static inline bool
912 has_visible_window_station ()
913 {
914   HWINSTA station_hdl;
915   USEROBJECTFLAGS uof;
916   DWORD len;
917
918   /* Check if the process is associated with a visible window station.
919      These are processes running on the local desktop as well as processes
920      running in terminal server sessions.
921      Processes running in a service session not explicitely associated
922      with the desktop (using the "Allow service to interact with desktop"
923      property) are running in an invisible window station. */
924   if ((station_hdl = GetProcessWindowStation ())
925       && GetUserObjectInformationA (station_hdl, UOI_FLAGS, &uof,
926                                     sizeof uof, &len)
927       && (uof.dwFlags & WSF_VISIBLE))
928     return true;
929   return false;
930 }
931
932 /* Keyboard interrupt handler.  */
933 static BOOL WINAPI
934 ctrl_c_handler (DWORD type)
935 {
936   static bool saw_close;
937   lock_process now;
938
939   if (!cygwin_finished_initializing)
940     {
941       if (myself->cygstarted)   /* Was this process created by a cygwin process? */
942         return TRUE;            /* Yes.  Let the parent eventually handle CTRL-C issues. */
943       debug_printf ("exiting with status %p", STATUS_CONTROL_C_EXIT);
944       ExitProcess (STATUS_CONTROL_C_EXIT);
945     }
946
947   _my_tls.remove (INFINITE);
948
949 #if 0
950   if (type == CTRL_C_EVENT || type == CTRL_BREAK_EVENT)
951     proc_subproc (PROC_KILLFORKED, 0);
952 #endif
953
954   /* Return FALSE to prevent an "End task" dialog box from appearing
955      for each Cygwin process window that's open when the computer
956      is shut down or console window is closed. */
957
958   if (type == CTRL_SHUTDOWN_EVENT)
959     {
960 #if 0
961       /* Don't send a signal.  Only NT service applications and their child
962          processes will receive this event and the services typically already
963          handle the shutdown action when getting the SERVICE_CONTROL_SHUTDOWN
964          control message. */
965       sig_send (NULL, SIGTERM);
966 #endif
967       return FALSE;
968     }
969
970   if (myself->ctty != -1)
971     {
972       if (type == CTRL_CLOSE_EVENT)
973         {
974           sig_send (NULL, SIGHUP);
975           saw_close = true;
976           return FALSE;
977         }
978       if (!saw_close && type == CTRL_LOGOFF_EVENT)
979         {
980           /* The CTRL_LOGOFF_EVENT is sent when *any* user logs off.
981              The below code sends a SIGHUP only if it is not performing the
982              default activity for SIGHUP.  Note that it is possible for two
983              SIGHUP signals to arrive if a process group leader is exiting
984              too.  Getting this 100% right is saved for a future cygwin mailing
985              list goad.  */
986           if (global_sigs[SIGHUP].sa_handler != SIG_DFL)
987             {
988               sig_send (myself_nowait, SIGHUP);
989               return TRUE;
990             }
991           return FALSE;
992         }
993     }
994
995   if (chExeced)
996     {
997       chExeced->set_saw_ctrl_c ();
998       return TRUE;
999     }
1000
1001   /* We're only the process group leader when we have a valid pinfo structure.
1002      If we don't have one, then the parent "stub" will handle the signal. */
1003   if (!pinfo (cygwin_pid (GetCurrentProcessId ())))
1004     return TRUE;
1005
1006   tty_min *t = cygwin_shared->tty.get_tty (myself->ctty);
1007   /* Ignore this if we're not the process group leader since it should be handled
1008      *by* the process group leader. */
1009   if (myself->ctty != -1 && t->getpgid () == myself->pid &&
1010        (GetTickCount () - t->last_ctrl_c) >= MIN_CTRL_C_SLOP)
1011     /* Otherwise we just send a SIGINT to the process group and return TRUE (to indicate
1012        that we have handled the signal).  At this point, type should be
1013        a CTRL_C_EVENT or CTRL_BREAK_EVENT. */
1014     {
1015       int sig = SIGINT;
1016       /* If intr and quit are both mapped to ^C, send SIGQUIT on ^BREAK */
1017       if (type == CTRL_BREAK_EVENT
1018           && t->ti.c_cc[VINTR] == 3 && t->ti.c_cc[VQUIT] == 3)
1019         sig = SIGQUIT;
1020       t->last_ctrl_c = GetTickCount ();
1021       killsys (-myself->pid, sig);
1022       t->last_ctrl_c = GetTickCount ();
1023       return TRUE;
1024     }
1025
1026   return TRUE;
1027 }
1028
1029 /* Function used by low level sig wrappers. */
1030 extern "C" void __stdcall
1031 set_process_mask (sigset_t newmask)
1032 {
1033   set_signal_mask (newmask, _my_tls.sigmask);
1034 }
1035
1036 extern "C" int
1037 sighold (int sig)
1038 {
1039   /* check that sig is in right range */
1040   if (sig < 0 || sig >= NSIG)
1041     {
1042       set_errno (EINVAL);
1043       syscall_printf ("signal %d out of range", sig);
1044       return -1;
1045     }
1046   mask_sync.acquire (INFINITE);
1047   sigset_t mask = _my_tls.sigmask;
1048   sigaddset (&mask, sig);
1049   set_signal_mask (mask, _my_tls.sigmask);
1050   mask_sync.release ();
1051   return 0;
1052 }
1053
1054 extern "C" int
1055 sigrelse (int sig)
1056 {
1057   /* check that sig is in right range */
1058   if (sig < 0 || sig >= NSIG)
1059     {
1060       set_errno (EINVAL);
1061       syscall_printf ("signal %d out of range", sig);
1062       return -1;
1063     }
1064   mask_sync.acquire (INFINITE);
1065   sigset_t mask = _my_tls.sigmask;
1066   sigdelset (&mask, sig);
1067   set_signal_mask (mask, _my_tls.sigmask);
1068   mask_sync.release ();
1069   return 0;
1070 }
1071
1072 extern "C" _sig_func_ptr
1073 sigset (int sig, _sig_func_ptr func)
1074 {
1075   sig_dispatch_pending ();
1076   _sig_func_ptr prev;
1077
1078   /* check that sig is in right range */
1079   if (sig < 0 || sig >= NSIG || sig == SIGKILL || sig == SIGSTOP)
1080     {
1081       set_errno (EINVAL);
1082       syscall_printf ("SIG_ERR = sigset (%d, %p)", sig, func);
1083       return (_sig_func_ptr) SIG_ERR;
1084     }
1085
1086   mask_sync.acquire (INFINITE);
1087   sigset_t mask = _my_tls.sigmask;
1088   /* If sig was in the signal mask return SIG_HOLD, otherwise return the
1089      previous disposition. */
1090   if (sigismember (&mask, sig))
1091     prev = SIG_HOLD;
1092   else
1093     prev = global_sigs[sig].sa_handler;
1094   /* If func is SIG_HOLD, add sig to the signal mask, otherwise set the
1095      disposition to func and remove sig from the signal mask. */
1096   if (func == SIG_HOLD)
1097     sigaddset (&mask, sig);
1098   else
1099     {
1100       /* No error checking.  The test which could return SIG_ERR has already
1101          been made above. */
1102       signal (sig, func);
1103       sigdelset (&mask, sig);
1104     }
1105   set_signal_mask (mask, _my_tls.sigmask);
1106   mask_sync.release ();
1107   return prev;
1108 }
1109
1110 extern "C" int
1111 sigignore (int sig)
1112 {
1113   return sigset (sig, SIG_IGN) == SIG_ERR ? -1 : 0;
1114 }
1115
1116 /* Update the signal mask for this process and return the old mask.
1117    Called from sigdelayed */
1118 extern "C" sigset_t
1119 set_process_mask_delta ()
1120 {
1121   mask_sync.acquire (INFINITE);
1122   sigset_t newmask, oldmask;
1123
1124   if (_my_tls.deltamask & SIG_NONMASKABLE)
1125     oldmask = _my_tls.oldmask; /* from handle_sigsuspend */
1126   else
1127     oldmask = _my_tls.sigmask;
1128   newmask = (oldmask | _my_tls.deltamask) & ~SIG_NONMASKABLE;
1129   sigproc_printf ("oldmask %p, newmask %p, deltamask %p", oldmask, newmask,
1130                   _my_tls.deltamask);
1131   _my_tls.sigmask = newmask;
1132   mask_sync.release ();
1133   return oldmask;
1134 }
1135
1136 /* Set the signal mask for this process.
1137    Note that some signals are unmaskable, as in UNIX.  */
1138 extern "C" void __stdcall
1139 set_signal_mask (sigset_t newmask, sigset_t& oldmask)
1140 {
1141 #ifdef CGF
1142   if (&_my_tls == _sig_tls)
1143     small_printf ("********* waiting in signal thread\n");
1144 #endif
1145   mask_sync.acquire (INFINITE);
1146   newmask &= ~SIG_NONMASKABLE;
1147   sigset_t mask_bits = oldmask & ~newmask;
1148   sigproc_printf ("oldmask %p, newmask %p, mask_bits %p", oldmask, newmask,
1149                   mask_bits);
1150   oldmask = newmask;
1151   if (mask_bits)
1152     sig_dispatch_pending (true);
1153   else
1154     sigproc_printf ("not calling sig_dispatch_pending");
1155   mask_sync.release ();
1156 }
1157
1158 int __stdcall
1159 sigpacket::process ()
1160 {
1161   DWORD continue_now;
1162   struct sigaction dummy = global_sigs[SIGSTOP];
1163
1164   if (si.si_signo != SIGCONT)
1165     continue_now = false;
1166   else
1167     {
1168       continue_now = myself->process_state & PID_STOPPED;
1169       myself->stopsig = 0;
1170       myself->process_state &= ~PID_STOPPED;
1171       /* Clear pending stop signals */
1172       sig_clear (SIGSTOP);
1173       sig_clear (SIGTSTP);
1174       sig_clear (SIGTTIN);
1175       sig_clear (SIGTTOU);
1176     }
1177
1178   int rc = 1;
1179
1180   sigproc_printf ("signal %d processing", si.si_signo);
1181   struct sigaction& thissig = global_sigs[si.si_signo];
1182
1183   myself->rusage_self.ru_nsignals++;
1184
1185   bool masked;
1186   void *handler;
1187   if (!hExeced || (void *) thissig.sa_handler == (void *) SIG_IGN)
1188     handler = (void *) thissig.sa_handler;
1189   else if (tls)
1190     return 1;
1191   else
1192     handler = NULL;
1193
1194   if (si.si_signo == SIGKILL)
1195     goto exit_sig;
1196   if (si.si_signo == SIGSTOP)
1197     {
1198       sig_clear (SIGCONT);
1199       if (!tls)
1200         tls = _main_tls;
1201       goto stop;
1202     }
1203
1204   bool insigwait_mask;
1205   if ((masked = ISSTATE (myself, PID_STOPPED)))
1206     insigwait_mask = false;
1207   else if (!tls)
1208     insigwait_mask = !handler && (tls = _cygtls::find_tls (si.si_signo));
1209   else
1210     insigwait_mask = sigismember (&tls->sigwait_mask, si.si_signo);
1211
1212   if (insigwait_mask)
1213     goto thread_specific;
1214
1215   if (masked)
1216     /* nothing to do */;
1217   else if (sigismember (mask, si.si_signo))
1218     masked = true;
1219   else if (tls)
1220     masked  = sigismember (&tls->sigmask, si.si_signo);
1221
1222   if (!tls)
1223     tls = _main_tls;
1224
1225   if (masked)
1226     {
1227       sigproc_printf ("signal %d blocked", si.si_signo);
1228       rc = -1;
1229       goto done;
1230     }
1231
1232   /* Clear pending SIGCONT on stop signals */
1233   if (si.si_signo == SIGTSTP || si.si_signo == SIGTTIN || si.si_signo == SIGTTOU)
1234     sig_clear (SIGCONT);
1235
1236 #ifdef CGF
1237   if (being_debugged ())
1238     {
1239       char sigmsg[sizeof (_CYGWIN_SIGNAL_STRING " 0xffffffff")];
1240       __small_sprintf (sigmsg, _CYGWIN_SIGNAL_STRING " %p", si.si_signo);
1241       OutputDebugString (sigmsg);
1242     }
1243 #endif
1244
1245   if (handler == (void *) SIG_DFL)
1246     {
1247       if (insigwait_mask)
1248         goto thread_specific;
1249       if (si.si_signo == SIGCHLD || si.si_signo == SIGIO || si.si_signo == SIGCONT || si.si_signo == SIGWINCH
1250           || si.si_signo == SIGURG)
1251         {
1252           sigproc_printf ("default signal %d ignored", si.si_signo);
1253           if (continue_now)
1254             SetEvent (signal_arrived);
1255           goto done;
1256         }
1257
1258       if (si.si_signo == SIGTSTP || si.si_signo == SIGTTIN || si.si_signo == SIGTTOU)
1259         goto stop;
1260
1261       goto exit_sig;
1262     }
1263
1264   if (handler == (void *) SIG_IGN)
1265     {
1266       sigproc_printf ("signal %d ignored", si.si_signo);
1267       goto done;
1268     }
1269
1270   if (handler == (void *) SIG_ERR)
1271     goto exit_sig;
1272
1273   tls->set_siginfo (this);
1274   goto dosig;
1275
1276 stop:
1277   /* Eat multiple attempts to STOP */
1278   if (ISSTATE (myself, PID_STOPPED))
1279     goto done;
1280   handler = (void *) sig_handle_tty_stop;
1281   thissig = dummy;
1282
1283 dosig:
1284   /* Dispatch to the appropriate function. */
1285   sigproc_printf ("signal %d, about to call %p", si.si_signo, handler);
1286   rc = setup_handler (si.si_signo, handler, thissig, tls);
1287
1288 done:
1289   if (continue_now)
1290     SetEvent (sigCONT);
1291   sigproc_printf ("returning %d", rc);
1292   return rc;
1293
1294 thread_specific:
1295   tls->sig = si.si_signo;
1296   tls->set_siginfo (this);
1297   sigproc_printf ("releasing sigwait for thread");
1298   SetEvent (tls->event);
1299   goto done;
1300
1301 exit_sig:
1302   if (si.si_signo == SIGQUIT || si.si_signo == SIGABRT)
1303     {
1304       CONTEXT c;
1305       c.ContextFlags = CONTEXT_FULL;
1306       GetThreadContext (hMainThread, &c);
1307       tls->copy_context (&c);
1308       si.si_signo |= 0x80;
1309     }
1310   sigproc_printf ("signal %d, about to call do_exit", si.si_signo);
1311   tls->signal_exit (si.si_signo);       /* never returns */
1312 }
1313
1314 /* Cover function to `do_exit' to handle exiting even in presence of more
1315    exceptions.  We used to call exit, but a SIGSEGV shouldn't cause atexit
1316    routines to run.  */
1317 void
1318 _cygtls::signal_exit (int rc)
1319 {
1320   if (hExeced)
1321     {
1322       sigproc_printf ("terminating captive process");
1323       TerminateProcess (hExeced, sigExeced = rc);
1324     }
1325
1326   signal_debugger (rc & 0x7f);
1327   if ((rc & 0x80) && !try_to_debug ())
1328     stackdump (thread_context.ebp, 1, 1);
1329
1330   lock_process until_exit (true);
1331   if (hExeced || exit_state > ES_PROCESS_LOCKED)
1332     myself.exit (rc);
1333
1334   /* Starve other threads in a vain attempt to stop them from doing something
1335      stupid. */
1336   SetThreadPriority (GetCurrentThread (), THREAD_PRIORITY_TIME_CRITICAL);
1337
1338   sigproc_printf ("about to call do_exit (%x)", rc);
1339   SetEvent (signal_arrived);
1340   do_exit (rc);
1341 }
1342
1343 void
1344 events_init ()
1345 {
1346   mask_sync.init ("mask_sync");
1347   windows_system_directory[0] = '\0';
1348   GetSystemDirectory (windows_system_directory, sizeof (windows_system_directory) - 2);
1349   char *end = strchr (windows_system_directory, '\0');
1350   if (end == windows_system_directory)
1351     api_fatal ("can't find windows system directory");
1352   if (end[-1] != '\\')
1353     {
1354       *end++ = '\\';
1355       *end = '\0';
1356     }
1357   windows_system_directory_length = end - windows_system_directory;
1358   debug_printf ("windows_system_directory '%s', windows_system_directory_length %d",
1359                 windows_system_directory, windows_system_directory_length);
1360 }
1361
1362 void
1363 events_terminate ()
1364 {
1365   exit_already = 1;
1366 }
1367
1368 int
1369 _cygtls::call_signal_handler ()
1370 {
1371   int this_sa_flags = 0;
1372   /* Call signal handler.  */
1373   while (sig)
1374     {
1375       lock ();
1376       this_sa_flags = sa_flags;
1377       int thissig = sig;
1378
1379       pop ();
1380       reset_signal_arrived ();
1381       sigset_t this_oldmask = set_process_mask_delta ();
1382       int this_errno = saved_errno;
1383       sig = 0;
1384       unlock ();        // make sure synchronized
1385       incyg = 0;
1386       if (!(this_sa_flags & SA_SIGINFO))
1387         {
1388           void (*sigfunc) (int) = func;
1389           sigfunc (thissig);
1390         }
1391       else
1392         {
1393           siginfo_t thissi = infodata;
1394           void (*sigact) (int, siginfo_t *, void *) = (void (*) (int, siginfo_t *, void *)) func;
1395           /* no ucontext_t information provided yet */
1396           sigact (thissig, &thissi, NULL);
1397         }
1398       incyg = 1;
1399       set_signal_mask (this_oldmask, _my_tls.sigmask);
1400       if (this_errno >= 0)
1401         set_errno (this_errno);
1402     }
1403
1404   return this_sa_flags & SA_RESTART;
1405 }
1406
1407 extern "C" void __stdcall
1408 reset_signal_arrived ()
1409 {
1410   // NEEDED? WaitForSingleObject (signal_arrived, 10);
1411   ResetEvent (signal_arrived);
1412   sigproc_printf ("reset signal_arrived");
1413   if (_my_tls.stackptr > _my_tls.stack)
1414     debug_printf ("stackptr[-1] %p", _my_tls.stackptr[-1]);
1415 }
1416
1417 void
1418 _cygtls::copy_context (CONTEXT *c)
1419 {
1420   memcpy (&thread_context, c, (&thread_context._internal - (unsigned char *) &thread_context));
1421 }
1422
1423 void
1424 _cygtls::signal_debugger (int sig)
1425 {
1426   if (isinitialized () && being_debugged ())
1427     {
1428       char sigmsg[2 * sizeof (_CYGWIN_SIGNAL_STRING " ffffffff ffffffff")];
1429       __small_sprintf (sigmsg, _CYGWIN_SIGNAL_STRING " %d %p %p", sig, thread_id, &thread_context);
1430       OutputDebugString (sigmsg);
1431     }
1432 }