OSDN Git Service

Merge branch 'master' of git://github.com/monaka/binutils
[pf3gnuchains/pf3gnuchains3x.git] / winsup / cygwin / exceptions.cc
1 /* exceptions.cc
2
3    Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
4    2005, 2006, 2007, 2008, 2009 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 #define CYGTLS_HANDLE
13 #include "winsup.h"
14 #include "miscfuncs.h"
15 #include <wingdi.h>
16 #include <winuser.h>
17 #include <imagehlp.h>
18 #include <stdlib.h>
19 #include <syslog.h>
20 #include <wchar.h>
21
22 #include "pinfo.h"
23 #include "cygtls.h"
24 #include "sigproc.h"
25 #include "shared_info.h"
26 #include "perprocess.h"
27 #include "path.h"
28 #include "fhandler.h"
29 #include "dtable.h"
30 #include "cygheap.h"
31 #include "child_info.h"
32 #include "ntdll.h"
33
34 #define CALL_HANDLER_RETRY 20
35
36 char debugger_command[2 * NT_MAX_PATH + 20];
37
38 extern "C" {
39 extern void sigdelayed ();
40 };
41
42 extern child_info_spawn *chExeced;
43
44 static BOOL WINAPI ctrl_c_handler (DWORD);
45 static WCHAR windows_system_directory[1024];
46 static size_t windows_system_directory_length;
47
48 /* This is set to indicate that we have already exited.  */
49
50 static NO_COPY int exit_already = 0;
51 static muto NO_COPY mask_sync;
52
53 NO_COPY static struct
54 {
55   unsigned int code;
56   const char *name;
57 } status_info[] =
58 {
59 #define X(s) s, #s
60   { X (STATUS_ABANDONED_WAIT_0) },
61   { X (STATUS_ACCESS_VIOLATION) },
62   { X (STATUS_ARRAY_BOUNDS_EXCEEDED) },
63   { X (STATUS_BREAKPOINT) },
64   { X (STATUS_CONTROL_C_EXIT) },
65   { X (STATUS_DATATYPE_MISALIGNMENT) },
66   { X (STATUS_FLOAT_DENORMAL_OPERAND) },
67   { X (STATUS_FLOAT_DIVIDE_BY_ZERO) },
68   { X (STATUS_FLOAT_INEXACT_RESULT) },
69   { X (STATUS_FLOAT_INVALID_OPERATION) },
70   { X (STATUS_FLOAT_OVERFLOW) },
71   { X (STATUS_FLOAT_STACK_CHECK) },
72   { X (STATUS_FLOAT_UNDERFLOW) },
73   { X (STATUS_GUARD_PAGE_VIOLATION) },
74   { X (STATUS_ILLEGAL_INSTRUCTION) },
75   { X (STATUS_INTEGER_DIVIDE_BY_ZERO) },
76   { X (STATUS_INTEGER_OVERFLOW) },
77   { X (STATUS_INVALID_DISPOSITION) },
78   { X (STATUS_IN_PAGE_ERROR) },
79   { X (STATUS_NONCONTINUABLE_EXCEPTION) },
80   { X (STATUS_NO_MEMORY) },
81   { X (STATUS_PENDING) },
82   { X (STATUS_PRIVILEGED_INSTRUCTION) },
83   { X (STATUS_SINGLE_STEP) },
84   { X (STATUS_STACK_OVERFLOW) },
85   { X (STATUS_TIMEOUT) },
86   { X (STATUS_USER_APC) },
87   { X (STATUS_WAIT_0) },
88   { 0, 0 }
89 #undef X
90 };
91
92 /* Initialization code.  */
93
94 void
95 init_console_handler (bool install_handler)
96 {
97   BOOL res;
98
99   SetConsoleCtrlHandler (ctrl_c_handler, FALSE);
100   SetConsoleCtrlHandler (NULL, FALSE);
101   if (install_handler)
102     res = SetConsoleCtrlHandler (ctrl_c_handler, TRUE);
103   else
104     res = SetConsoleCtrlHandler (NULL, TRUE);
105   if (!res)
106     system_printf ("SetConsoleCtrlHandler failed, %E");
107 }
108
109 extern "C" void
110 error_start_init (const char *buf)
111 {
112   if (!buf || !*buf)
113     {
114       debugger_command[0] = '\0';
115       return;
116     }
117
118   char pgm[NT_MAX_PATH];
119   if (!GetModuleFileName (NULL, pgm, NT_MAX_PATH))
120     strcpy (pgm, "cygwin1.dll");
121   for (char *p = strchr (pgm, '\\'); p; p = strchr (p, '\\'))
122     *p = '/';
123
124   __small_sprintf (debugger_command, "%s \"%s\"", buf, pgm);
125 }
126
127 static void
128 open_stackdumpfile ()
129 {
130   if (myself->progname[0])
131     {
132       const char *p;
133       /* write to progname.stackdump if possible */
134       if (!myself->progname[0])
135         p = "unknown";
136       else if ((p = strrchr (myself->progname, '\\')))
137         p++;
138       else
139         p = myself->progname;
140
141       WCHAR corefile[strlen (p) + sizeof (".stackdump")];
142       UNICODE_STRING ucore;
143       OBJECT_ATTRIBUTES attr;
144       /* Create the UNICODE variation of <progname>.stackdump. */
145       RtlInitEmptyUnicodeString (&ucore, corefile,
146                                  sizeof corefile - sizeof (WCHAR));
147       ucore.Length = sys_mbstowcs (ucore.Buffer,
148                                    ucore.MaximumLength / sizeof (WCHAR),
149                                    p, strlen (p)) * sizeof (WCHAR);
150       RtlAppendUnicodeToString (&ucore, L".stackdump");
151       /* Create an object attribute which refers to <progname>.stackdump
152          in Cygwin's cwd.  Stick to caseinsensitivity. */
153       InitializeObjectAttributes (&attr, &ucore, OBJ_CASE_INSENSITIVE,
154                                   cygheap->cwd.get_handle (), NULL);
155       HANDLE h;
156       IO_STATUS_BLOCK io;
157       NTSTATUS status;
158       /* Try to open it to dump the stack in it. */
159       status = NtCreateFile (&h, GENERIC_WRITE | SYNCHRONIZE, &attr, &io,
160                              NULL, FILE_ATTRIBUTE_NORMAL, 0, FILE_OVERWRITE_IF,
161                              FILE_SYNCHRONOUS_IO_NONALERT
162                              | FILE_OPEN_FOR_BACKUP_INTENT, NULL, 0);
163       if (NT_SUCCESS (status))
164         {
165           if (!myself->cygstarted)
166             system_printf ("Dumping stack trace to %S", &ucore);
167           else
168             debug_printf ("Dumping stack trace to %S", &ucore);
169           SetStdHandle (STD_ERROR_HANDLE, h);
170         }
171     }
172 }
173
174 /* Utilities for dumping the stack, etc.  */
175
176 static void
177 exception (EXCEPTION_RECORD *e,  CONTEXT *in)
178 {
179   const char *exception_name = NULL;
180
181   if (e)
182     {
183       for (int i = 0; status_info[i].name; i++)
184         {
185           if (status_info[i].code == e->ExceptionCode)
186             {
187               exception_name = status_info[i].name;
188               break;
189             }
190         }
191     }
192
193   if (exception_name)
194     small_printf ("Exception: %s at eip=%08x\r\n", exception_name, in->Eip);
195   else
196     small_printf ("Signal %d at eip=%08x\r\n", e->ExceptionCode, in->Eip);
197   small_printf ("eax=%08x ebx=%08x ecx=%08x edx=%08x esi=%08x edi=%08x\r\n",
198                 in->Eax, in->Ebx, in->Ecx, in->Edx, in->Esi, in->Edi);
199   small_printf ("ebp=%08x esp=%08x program=%s, pid %u, thread %s\r\n",
200                 in->Ebp, in->Esp, myself->progname, myself->pid, cygthread::name ());
201   small_printf ("cs=%04x ds=%04x es=%04x fs=%04x gs=%04x ss=%04x\r\n",
202                 in->SegCs, in->SegDs, in->SegEs, in->SegFs, in->SegGs, in->SegSs);
203 }
204
205 /* A class for manipulating the stack. */
206 class stack_info
207 {
208   int walk ();                  /* Uses the "old" method */
209   char *next_offset () {return *((char **) sf.AddrFrame.Offset);}
210   bool needargs;
211   DWORD dummy_frame;
212 public:
213   STACKFRAME sf;                 /* For storing the stack information */
214   void init (DWORD, bool, bool); /* Called the first time that stack info is needed */
215
216   /* Postfix ++ iterates over the stack, returning zero when nothing is left. */
217   int operator ++(int) { return walk (); }
218 };
219
220 /* The number of parameters used in STACKFRAME */
221 #define NPARAMS (sizeof (thestack.sf.Params) / sizeof (thestack.sf.Params[0]))
222
223 /* This is the main stack frame info for this process. */
224 static NO_COPY stack_info thestack;
225
226 /* Initialize everything needed to start iterating. */
227 void
228 stack_info::init (DWORD ebp, bool wantargs, bool goodframe)
229 {
230 # define debp ((DWORD *) ebp)
231   memset (&sf, 0, sizeof (sf));
232   if (!goodframe)
233     sf.AddrFrame.Offset = ebp;
234   else
235     {
236       dummy_frame = ebp;
237       sf.AddrFrame.Offset = (DWORD) &dummy_frame;
238     }
239   sf.AddrReturn.Offset = debp[1];
240   sf.AddrFrame.Mode = AddrModeFlat;
241   needargs = wantargs;
242 # undef debp
243 }
244
245 extern "C" void _cygwin_exit_return ();
246
247 /* Walk the stack by looking at successive stored 'bp' frames.
248    This is not foolproof. */
249 int
250 stack_info::walk ()
251 {
252   char **ebp;
253
254   if ((void (*) ()) sf.AddrPC.Offset == _cygwin_exit_return)
255     return 0;           /* stack frames are exhausted */
256
257   if (((ebp = (char **) next_offset ()) == NULL) || (ebp >= (char **) cygwin_hmodule))
258     return 0;
259
260   sf.AddrFrame.Offset = (DWORD) ebp;
261   sf.AddrPC.Offset = sf.AddrReturn.Offset;
262
263   /* The return address always follows the stack pointer */
264   sf.AddrReturn.Offset = (DWORD) *++ebp;
265
266   if (needargs)
267     {
268       unsigned nparams = NPARAMS;
269
270       /* The arguments follow the return address */
271       sf.Params[0] = (DWORD) *++ebp;
272       /* Hack for XP/2K3 WOW64.  If the first stack param points to the
273          application entry point, we can only fetch one additional
274          parameter.  Accessing anything beyond this address results in
275          a SEGV.  This is fixed in Vista/2K8 WOW64. */
276       if (wincap.has_restricted_stack_args () && sf.Params[0] == 0x401000)
277         nparams = 2;
278       for (unsigned i = 1; i < nparams; i++)
279         sf.Params[i] = (DWORD) *++ebp;
280     }
281
282   return 1;
283 }
284
285 static void
286 stackdump (DWORD ebp, int open_file, bool isexception)
287 {
288   extern unsigned long rlim_core;
289   static bool already_dumped;
290
291   if (rlim_core == 0UL || (open_file && already_dumped))
292     return;
293
294   if (open_file)
295     open_stackdumpfile ();
296
297   already_dumped = true;
298
299   int i;
300
301   thestack.init (ebp, 1, !isexception); /* Initialize from the input CONTEXT */
302   small_printf ("Stack trace:\r\nFrame     Function  Args\r\n");
303   for (i = 0; i < 16 && thestack++; i++)
304     {
305       small_printf ("%08x  %08x ", thestack.sf.AddrFrame.Offset,
306                     thestack.sf.AddrPC.Offset);
307       for (unsigned j = 0; j < NPARAMS; j++)
308         small_printf ("%s%08x", j == 0 ? " (" : ", ", thestack.sf.Params[j]);
309       small_printf (")\r\n");
310     }
311   small_printf ("End of stack trace%s\n",
312               i == 16 ? " (more stack frames may be present)" : "");
313 }
314
315 bool
316 _cygtls::inside_kernel (CONTEXT *cx)
317 {
318   int res;
319   MEMORY_BASIC_INFORMATION m;
320
321   if (!isinitialized ())
322     return true;
323
324   memset (&m, 0, sizeof m);
325   if (!VirtualQuery ((LPCVOID) cx->Eip, &m, sizeof m))
326     sigproc_printf ("couldn't get memory info, pc %p, %E", cx->Eip);
327
328   size_t size = (windows_system_directory_length + 6) * sizeof (WCHAR);
329   PWCHAR checkdir = (PWCHAR) alloca (size);
330   memset (checkdir, 0, size);
331
332 # define h ((HMODULE) m.AllocationBase)
333   /* Apparently Windows 95 can sometimes return bogus addresses from
334      GetThreadContext.  These resolve to a strange allocation base.
335      These should *never* be treated as interruptible. */
336   if (!h || m.State != MEM_COMMIT)
337     res = true;
338   else if (h == user_data->hmodule)
339     res = false;
340   else if (!GetModuleFileNameW (h, checkdir, windows_system_directory_length + 6))
341     res = false;
342   else
343     {
344       /* Skip potential long path prefix. */
345       if (!wcsncmp (checkdir, L"\\\\?\\", 4))
346         checkdir += 4;
347       res = !wcsncasecmp (windows_system_directory, checkdir,
348                           windows_system_directory_length);
349     }
350   sigproc_printf ("pc %p, h %p, inside_kernel %d", cx->Eip, h, res);
351 # undef h
352   return res;
353 }
354
355 /* Temporary (?) function for external callers to get a stack dump */
356 extern "C" void
357 cygwin_stackdump ()
358 {
359   CONTEXT c;
360   c.ContextFlags = CONTEXT_FULL;
361   GetThreadContext (GetCurrentThread (), &c);
362   stackdump (c.Ebp, 0, 0);
363 }
364
365 #define TIME_TO_WAIT_FOR_DEBUGGER 10000
366
367 extern "C" int
368 try_to_debug (bool waitloop)
369 {
370   debug_printf ("debugger_command '%s'", debugger_command);
371   if (*debugger_command == '\0')
372     return 0;
373   if (being_debugged ())
374     {
375       extern void break_here ();
376       break_here ();
377       return 0;
378     }
379
380   __small_sprintf (strchr (debugger_command, '\0'), " %u", GetCurrentProcessId ());
381
382   LONG prio = GetThreadPriority (GetCurrentThread ());
383   SetThreadPriority (GetCurrentThread (), THREAD_PRIORITY_HIGHEST);
384   PROCESS_INFORMATION pi = {NULL, 0, 0, 0};
385
386   STARTUPINFOW si = {0, NULL, NULL, NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL};
387   si.lpReserved = NULL;
388   si.lpDesktop = NULL;
389   si.dwFlags = 0;
390   si.cb = sizeof (si);
391
392   /* FIXME: need to know handles of all running threads to
393      suspend_all_threads_except (current_thread_id);
394   */
395
396   /* if any of these mutexes is owned, we will fail to start any cygwin app
397      until trapped app exits */
398
399   lock_ttys::release ();
400
401   /* prevent recursive exception handling */
402   PWCHAR rawenv = GetEnvironmentStringsW () ;
403   for (PWCHAR p = rawenv; *p != L'\0'; p = wcschr (p, L'\0') + 1)
404     {
405       if (wcsncmp (p, L"CYGWIN=", wcslen (L"CYGWIN=")) == 0)
406         {
407           PWCHAR q = wcsstr (p, L"error_start") ;
408           /* replace 'error_start=...' with '_rror_start=...' */
409           if (q)
410             {
411               *q = L'_' ;
412               SetEnvironmentVariableW (L"CYGWIN", p + wcslen (L"CYGWIN=")) ;
413             }
414           break ;
415         }
416     }
417
418   console_printf ("*** starting debugger for pid %u, tid %u\n",
419                   cygwin_pid (GetCurrentProcessId ()), GetCurrentThreadId ());
420   BOOL dbg;
421   WCHAR dbg_cmd[strlen(debugger_command)];
422   sys_mbstowcs (dbg_cmd, strlen(debugger_command) + 1, debugger_command);
423   dbg = CreateProcessW (NULL,
424                         dbg_cmd,
425                         NULL,
426                         NULL,
427                         FALSE,
428                         CREATE_NEW_CONSOLE | CREATE_NEW_PROCESS_GROUP,
429                         NULL,
430                         NULL,
431                         &si,
432                         &pi);
433
434   if (!dbg)
435     system_printf ("Failed to start debugger, %E");
436   else
437     {
438       if (!waitloop)
439         return dbg;
440       SetThreadPriority (GetCurrentThread (), THREAD_PRIORITY_IDLE);
441       while (!being_debugged ())
442         low_priority_sleep (0);
443       Sleep (2000);
444     }
445
446   console_printf ("*** continuing pid %u from debugger call (%d)\n",
447                   cygwin_pid (GetCurrentProcessId ()), dbg);
448
449   SetThreadPriority (GetCurrentThread (), prio);
450   return dbg;
451 }
452
453 extern "C" DWORD __stdcall RtlUnwind (void *, void *, void *, DWORD);
454 static void __stdcall rtl_unwind (exception_list *, PEXCEPTION_RECORD) __attribute__ ((noinline, regparm (3)));
455 void __stdcall
456 rtl_unwind (exception_list *frame, PEXCEPTION_RECORD e)
457 {
458   __asm__ ("\n\
459   pushl         %%ebx                                   \n\
460   pushl         %%edi                                   \n\
461   pushl         %%esi                                   \n\
462   pushl         $0                                      \n\
463   pushl         %1                                      \n\
464   pushl         $1f                                     \n\
465   pushl         %0                                      \n\
466   call          _RtlUnwind@16                           \n\
467 1:                                                      \n\
468   popl          %%esi                                   \n\
469   popl          %%edi                                   \n\
470   popl          %%ebx                                   \n\
471 ": : "r" (frame), "r" (e));
472 }
473
474 /* Main exception handler. */
475
476 extern exception_list *_except_list asm ("%fs:0");
477
478 int
479 _cygtls::handle_exceptions (EXCEPTION_RECORD *e, exception_list *frame, CONTEXT *in, void *)
480 {
481   static bool NO_COPY debugging;
482   static int NO_COPY recursed;
483   _cygtls& me = _my_tls;
484
485   if (debugging && ++debugging < 500000)
486     {
487       SetThreadPriority (hMainThread, THREAD_PRIORITY_NORMAL);
488       return 0;
489     }
490
491   /* If we've already exited, don't do anything here.  Returning 1
492      tells Windows to keep looking for an exception handler.  */
493   if (exit_already || e->ExceptionFlags)
494     return 1;
495
496   siginfo_t si = {0};
497   si.si_code = SI_KERNEL;
498   /* Coerce win32 value to posix value.  */
499   switch (e->ExceptionCode)
500     {
501     case STATUS_FLOAT_DENORMAL_OPERAND:
502     case STATUS_FLOAT_DIVIDE_BY_ZERO:
503     case STATUS_FLOAT_INVALID_OPERATION:
504     case STATUS_FLOAT_STACK_CHECK:
505       si.si_signo = SIGFPE;
506       si.si_code = FPE_FLTSUB;
507       break;
508     case STATUS_FLOAT_INEXACT_RESULT:
509       si.si_signo = SIGFPE;
510       si.si_code = FPE_FLTRES;
511       break;
512     case STATUS_FLOAT_OVERFLOW:
513       si.si_signo = SIGFPE;
514       si.si_code = FPE_FLTOVF;
515       break;
516     case STATUS_FLOAT_UNDERFLOW:
517       si.si_signo = SIGFPE;
518       si.si_code = FPE_FLTUND;
519       break;
520     case STATUS_INTEGER_DIVIDE_BY_ZERO:
521       si.si_signo = SIGFPE;
522       si.si_code = FPE_INTDIV;
523       break;
524     case STATUS_INTEGER_OVERFLOW:
525       si.si_signo = SIGFPE;
526       si.si_code = FPE_INTOVF;
527       break;
528
529     case STATUS_ILLEGAL_INSTRUCTION:
530       si.si_signo = SIGILL;
531       si.si_code = ILL_ILLOPC;
532       break;
533
534     case STATUS_PRIVILEGED_INSTRUCTION:
535       si.si_signo = SIGILL;
536       si.si_code = ILL_PRVOPC;
537       break;
538
539     case STATUS_NONCONTINUABLE_EXCEPTION:
540       si.si_signo = SIGILL;
541       si.si_code = ILL_ILLADR;
542       break;
543
544     case STATUS_TIMEOUT:
545       si.si_signo = SIGALRM;
546       break;
547
548     case STATUS_GUARD_PAGE_VIOLATION:
549       si.si_signo = SIGBUS;
550       si.si_code = BUS_OBJERR;
551       break;
552
553     case STATUS_DATATYPE_MISALIGNMENT:
554       si.si_signo = SIGBUS;
555       si.si_code = BUS_ADRALN;
556       break;
557
558     case STATUS_ACCESS_VIOLATION:
559       switch (mmap_is_attached_or_noreserve ((void *)e->ExceptionInformation[1],
560                                              1))
561         {
562         case MMAP_NORESERVE_COMMITED:
563           return 0;
564         case MMAP_RAISE_SIGBUS: /* MAP_NORESERVE page, commit failed, or
565                                    access to mmap page beyond EOF. */
566           si.si_signo = SIGBUS;
567           si.si_code = BUS_OBJERR;
568           break;
569         default:
570           MEMORY_BASIC_INFORMATION m;
571           VirtualQuery ((PVOID) e->ExceptionInformation[1], &m, sizeof m);
572           si.si_signo = SIGSEGV;
573           si.si_code = m.State == MEM_FREE ? SEGV_MAPERR : SEGV_ACCERR;
574           break;
575         }
576       break;
577
578     case STATUS_ARRAY_BOUNDS_EXCEEDED:
579     case STATUS_IN_PAGE_ERROR:
580     case STATUS_NO_MEMORY:
581     case STATUS_INVALID_DISPOSITION:
582     case STATUS_STACK_OVERFLOW:
583       si.si_signo = SIGSEGV;
584       si.si_code = SEGV_MAPERR;
585       break;
586
587     case STATUS_CONTROL_C_EXIT:
588       si.si_signo = SIGINT;
589       break;
590
591     case STATUS_INVALID_HANDLE:
592       /* CloseHandle will throw this exception if it is given an
593          invalid handle.  We don't care about the exception; we just
594          want CloseHandle to return an error.  This can be revisited
595          if gcc ever supports Windows style structured exception
596          handling.  */
597       return 0;
598
599     default:
600       /* If we don't recognize the exception, we have to assume that
601          we are doing structured exception handling, and we let
602          something else handle it.  */
603       return 1;
604     }
605
606   debug_printf ("In cygwin_except_handler exc %p at %p sp %p", e->ExceptionCode, in->Eip, in->Esp);
607   debug_printf ("In cygwin_except_handler sig %d at %p", si.si_signo, in->Eip);
608
609   bool masked = !!(me.sigmask & SIGTOMASK (si.si_signo));
610   if (masked)
611     syscall_printf ("signal %d, masked %p", si.si_signo,
612                     global_sigs[si.si_signo].sa_mask);
613
614   debug_printf ("In cygwin_except_handler calling %p",
615                  global_sigs[si.si_signo].sa_handler);
616
617   DWORD *ebp = (DWORD *) in->Esp;
618   for (DWORD *bpend = (DWORD *) __builtin_frame_address (0); ebp > bpend; ebp--)
619     if (*ebp == in->SegCs && ebp[-1] == in->Eip)
620       {
621         ebp -= 2;
622         break;
623       }
624
625   if (me.fault_guarded ())
626     me.return_from_fault ();
627
628   me.copy_context (in);
629
630   /* Temporarily replace windows top level SEH with our own handler.
631      We don't want any Windows magic kicking in.  This top level frame
632      will be removed automatically after our exception handler returns. */
633   _except_list->handler = _cygtls::handle_exceptions;
634
635   if (masked
636       || &me == _sig_tls
637       || !cygwin_finished_initializing
638       || (void *) global_sigs[si.si_signo].sa_handler == (void *) SIG_DFL
639       || (void *) global_sigs[si.si_signo].sa_handler == (void *) SIG_IGN
640       || (void *) global_sigs[si.si_signo].sa_handler == (void *) SIG_ERR)
641     {
642       /* Print the exception to the console */
643       if (!myself->cygstarted)
644         for (int i = 0; status_info[i].name; i++)
645           if (status_info[i].code == e->ExceptionCode)
646             {
647               system_printf ("Exception: %s", status_info[i].name);
648               break;
649             }
650
651       /* Another exception could happen while tracing or while exiting.
652          Only do this once.  */
653       if (recursed++)
654         system_printf ("Error while dumping state (probably corrupted stack)");
655       else
656         {
657           if (try_to_debug (0))
658             {
659               debugging = true;
660               return 0;
661             }
662
663           rtl_unwind (frame, e);
664           open_stackdumpfile ();
665           exception (e, in);
666           stackdump ((DWORD) ebp, 0, 1);
667         }
668
669       if (e->ExceptionCode == STATUS_ACCESS_VIOLATION)
670         {
671           int error_code = 0;
672           if (si.si_code == SEGV_ACCERR)        /* Address present */
673             error_code |= 1;
674           if (e->ExceptionInformation[0])       /* Write access */
675             error_code |= 2;
676           if (!me.inside_kernel (in))           /* User space */
677             error_code |= 4;
678           klog (LOG_INFO, "%s[%d]: segfault at %08x rip %08x rsp %08x error %d",
679                           __progname, myself->pid,
680                           e->ExceptionInformation[1], in->Eip, in->Esp,
681                           ((in->Eip >= 0x61000000 && in->Eip < 0x61200000)
682                            ? 0 : 4) | (e->ExceptionInformation[0] << 1));
683         }
684
685       me.signal_exit (0x80 | si.si_signo);      // Flag signal + core dump
686     }
687
688   si.si_addr =  (si.si_signo == SIGSEGV || si.si_signo == SIGBUS
689                  ? (void *) e->ExceptionInformation[1]
690                  : (void *) in->Eip);
691   si.si_errno = si.si_pid = si.si_uid = 0;
692   me.incyg++;
693   sig_send (NULL, si, &me);     // Signal myself
694   me.incyg--;
695   e->ExceptionFlags = 0;
696   return 0;
697 }
698
699 /* Utilities to call a user supplied exception handler.  */
700
701 #define SIG_NONMASKABLE (SIGTOMASK (SIGKILL) | SIGTOMASK (SIGSTOP))
702
703 /* Non-raceable sigsuspend
704  * Note: This implementation is based on the Single UNIX Specification
705  * man page.  This indicates that sigsuspend always returns -1 and that
706  * attempts to block unblockable signals will be silently ignored.
707  * This is counter to what appears to be documented in some UNIX
708  * man pages, e.g. Linux.
709  */
710 int __stdcall
711 handle_sigsuspend (sigset_t tempmask)
712 {
713   if (&_my_tls != _main_tls)
714     {
715       cancelable_wait (signal_arrived, INFINITE, cw_cancel_self);
716       return -1;
717     }
718
719   sigset_t oldmask = _my_tls.sigmask;   // Remember for restoration
720
721   set_signal_mask (tempmask, _my_tls.sigmask);
722   sigproc_printf ("oldmask %p, newmask %p", oldmask, tempmask);
723
724   pthread_testcancel ();
725   cancelable_wait (signal_arrived, INFINITE);
726
727   set_sig_errno (EINTR);        // Per POSIX
728
729   /* A signal dispatch function will have been added to our stack and will
730      be hit eventually.  Set the old mask to be restored when the signal
731      handler returns and indicate its presence by modifying deltamask. */
732
733   _my_tls.deltamask |= SIG_NONMASKABLE;
734   _my_tls.oldmask = oldmask;    // Will be restored by signal handler
735   return -1;
736 }
737
738 extern DWORD exec_exit;         // Possible exit value for exec
739
740 extern "C" {
741 static void
742 sig_handle_tty_stop (int sig)
743 {
744   _my_tls.incyg = 1;
745   /* Silently ignore attempts to suspend if there is no accommodating
746      cygwin parent to deal with this behavior. */
747   if (!myself->cygstarted)
748     {
749       myself->process_state &= ~PID_STOPPED;
750       return;
751     }
752
753   myself->stopsig = sig;
754   myself->alert_parent (sig);
755   sigproc_printf ("process %d stopped by signal %d", myself->pid, sig);
756   HANDLE w4[2];
757   w4[0] = sigCONT;
758   w4[1] = signal_arrived;
759   switch (WaitForMultipleObjects (2, w4, TRUE, INFINITE))
760     {
761     case WAIT_OBJECT_0:
762     case WAIT_OBJECT_0 + 1:
763       reset_signal_arrived ();
764       myself->stopsig = SIGCONT;
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       && GetUserObjectInformationW (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   _cygtls *use_tls = tls ?: _main_tls;
1195
1196   if (si.si_signo == SIGKILL)
1197     goto exit_sig;
1198   if (si.si_signo == SIGSTOP)
1199     {
1200       sig_clear (SIGCONT);
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 = sigismember (&tls->sigwait_mask, si.si_signo);
1209   else if (!(tls = _cygtls::find_tls (si.si_signo)))
1210     insigwait_mask = false;
1211   else
1212     {
1213       use_tls = tls;
1214       insigwait_mask = true;
1215     }
1216
1217   if (insigwait_mask)
1218     goto thread_specific;
1219
1220   if (masked)
1221     /* nothing to do */;
1222   else if (sigismember (mask, si.si_signo))
1223     masked = true;
1224   else if (tls)
1225     masked  = sigismember (&tls->sigmask, si.si_signo);
1226
1227   if (masked)
1228     {
1229       sigproc_printf ("signal %d blocked", si.si_signo);
1230       rc = -1;
1231       goto done;
1232     }
1233
1234   /* Clear pending SIGCONT on stop signals */
1235   if (si.si_signo == SIGTSTP || si.si_signo == SIGTTIN || si.si_signo == SIGTTOU)
1236     sig_clear (SIGCONT);
1237
1238 #ifdef CGF
1239   if (being_debugged ())
1240     {
1241       char sigmsg[sizeof (_CYGWIN_SIGNAL_STRING " 0xffffffff")];
1242       __small_sprintf (sigmsg, _CYGWIN_SIGNAL_STRING " %p", si.si_signo);
1243       OutputDebugString (sigmsg);
1244     }
1245 #endif
1246
1247   if (handler == (void *) SIG_DFL)
1248     {
1249       if (insigwait_mask)
1250         goto thread_specific;
1251       if (si.si_signo == SIGCHLD || si.si_signo == SIGIO || si.si_signo == SIGCONT || si.si_signo == SIGWINCH
1252           || si.si_signo == SIGURG)
1253         {
1254           sigproc_printf ("default signal %d ignored", si.si_signo);
1255           if (continue_now)
1256             SetEvent (signal_arrived);
1257           goto done;
1258         }
1259
1260       if (si.si_signo == SIGTSTP || si.si_signo == SIGTTIN || si.si_signo == SIGTTOU)
1261         goto stop;
1262
1263       goto exit_sig;
1264     }
1265
1266   if (handler == (void *) SIG_IGN)
1267     {
1268       sigproc_printf ("signal %d ignored", si.si_signo);
1269       goto done;
1270     }
1271
1272   if (handler == (void *) SIG_ERR)
1273     goto exit_sig;
1274
1275   use_tls->set_siginfo (this);
1276   goto dosig;
1277
1278 stop:
1279   /* Eat multiple attempts to STOP */
1280   if (ISSTATE (myself, PID_STOPPED))
1281     goto done;
1282   handler = (void *) sig_handle_tty_stop;
1283   thissig = dummy;
1284
1285 dosig:
1286   /* Dispatch to the appropriate function. */
1287   sigproc_printf ("signal %d, about to call %p", si.si_signo, handler);
1288   rc = setup_handler (si.si_signo, handler, thissig, use_tls);
1289
1290 done:
1291   tls = use_tls;
1292   if (continue_now)
1293     SetEvent (sigCONT);
1294   sigproc_printf ("returning %d", rc);
1295   return rc;
1296
1297 thread_specific:
1298   use_tls->sig = si.si_signo;
1299   use_tls->set_siginfo (this);
1300   use_tls->func = NULL;
1301   sigproc_printf ("releasing sigwait for thread");
1302   SetEvent (use_tls->event);
1303   goto done;
1304
1305 exit_sig:
1306   if (si.si_signo == SIGQUIT || si.si_signo == SIGABRT)
1307     {
1308       CONTEXT c;
1309       c.ContextFlags = CONTEXT_FULL;
1310       GetThreadContext (hMainThread, &c);
1311       use_tls->copy_context (&c);
1312       si.si_signo |= 0x80;
1313     }
1314   sigproc_printf ("signal %d, about to call do_exit", si.si_signo);
1315   use_tls->signal_exit (si.si_signo);   /* never returns */
1316 }
1317
1318 /* Cover function to `do_exit' to handle exiting even in presence of more
1319    exceptions.  We used to call exit, but a SIGSEGV shouldn't cause atexit
1320    routines to run.  */
1321 void
1322 _cygtls::signal_exit (int rc)
1323 {
1324   if (hExeced)
1325     {
1326       sigproc_printf ("terminating captive process");
1327       TerminateProcess (hExeced, sigExeced = rc);
1328     }
1329
1330   signal_debugger (rc & 0x7f);
1331   if ((rc & 0x80) && !try_to_debug ())
1332     stackdump (thread_context.ebp, 1, 1);
1333
1334   lock_process until_exit (true);
1335   if (hExeced || exit_state > ES_PROCESS_LOCKED)
1336     myself.exit (rc);
1337
1338   /* Starve other threads in a vain attempt to stop them from doing something
1339      stupid. */
1340   SetThreadPriority (GetCurrentThread (), THREAD_PRIORITY_TIME_CRITICAL);
1341
1342   sigproc_printf ("about to call do_exit (%x)", rc);
1343   do_exit (rc);
1344 }
1345
1346 void
1347 events_init ()
1348 {
1349   mask_sync.init ("mask_sync");
1350   windows_system_directory[0] = L'\0';
1351   GetSystemDirectoryW (windows_system_directory, sizeof (windows_system_directory) / sizeof (WCHAR) - 2);
1352   PWCHAR end = wcschr (windows_system_directory, L'\0');
1353   if (end == windows_system_directory)
1354     api_fatal ("can't find windows system directory");
1355   if (end[-1] != L'\\')
1356     {
1357       *end++ = L'\\';
1358       *end = L'\0';
1359     }
1360   windows_system_directory_length = end - windows_system_directory;
1361   debug_printf ("windows_system_directory '%W', windows_system_directory_length %d",
1362                 windows_system_directory, windows_system_directory_length);
1363 }
1364
1365 void
1366 events_terminate ()
1367 {
1368   exit_already = 1;
1369 }
1370
1371 int
1372 _cygtls::call_signal_handler ()
1373 {
1374   int this_sa_flags = 0;
1375   /* Call signal handler.  */
1376   while (sig && func)
1377     {
1378       lock ();
1379       this_sa_flags = sa_flags;
1380       int thissig = sig;
1381
1382       pop ();
1383       reset_signal_arrived ();
1384       sigset_t this_oldmask = set_process_mask_delta ();
1385       int this_errno = saved_errno;
1386       sig = 0;
1387       unlock ();        // make sure synchronized
1388       incyg = 0;
1389       if (!(this_sa_flags & SA_SIGINFO))
1390         {
1391           void (*sigfunc) (int) = func;
1392           sigfunc (thissig);
1393         }
1394       else
1395         {
1396           siginfo_t thissi = infodata;
1397           void (*sigact) (int, siginfo_t *, void *) = (void (*) (int, siginfo_t *, void *)) func;
1398           /* no ucontext_t information provided yet */
1399           sigact (thissig, &thissi, NULL);
1400         }
1401       incyg = 1;
1402       set_signal_mask (this_oldmask, _my_tls.sigmask);
1403       if (this_errno >= 0)
1404         set_errno (this_errno);
1405     }
1406
1407   return this_sa_flags & SA_RESTART;
1408 }
1409
1410 extern "C" void __stdcall
1411 reset_signal_arrived ()
1412 {
1413   // NEEDED? WaitForSingleObject (signal_arrived, 10);
1414   ResetEvent (signal_arrived);
1415   sigproc_printf ("reset signal_arrived");
1416   if (_my_tls.stackptr > _my_tls.stack)
1417     debug_printf ("stackptr[-1] %p", _my_tls.stackptr[-1]);
1418 }
1419
1420 void
1421 _cygtls::copy_context (CONTEXT *c)
1422 {
1423   memcpy (&thread_context, c, (&thread_context._internal - (unsigned char *) &thread_context));
1424 }
1425
1426 void
1427 _cygtls::signal_debugger (int sig)
1428 {
1429   if (isinitialized () && being_debugged ())
1430     {
1431       char sigmsg[2 * sizeof (_CYGWIN_SIGNAL_STRING " ffffffff ffffffff")];
1432       __small_sprintf (sigmsg, _CYGWIN_SIGNAL_STRING " %d %p %p", sig, thread_id, &thread_context);
1433       OutputDebugString (sigmsg);
1434     }
1435 }