OSDN Git Service

* globals.cc (enum exit_states::ES_GLOBAL_DTORS): Delete.
[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, 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 int NO_COPY sigExeced;
44
45 static BOOL WINAPI ctrl_c_handler (DWORD);
46 static WCHAR windows_system_directory[1024];
47 static size_t windows_system_directory_length;
48
49 /* This is set to indicate that we have already exited.  */
50
51 static NO_COPY int exit_already = 0;
52 static muto NO_COPY mask_sync;
53
54 NO_COPY static struct
55 {
56   unsigned int code;
57   const char *name;
58 } status_info[] =
59 {
60 #define X(s) s, #s
61   { X (STATUS_ABANDONED_WAIT_0) },
62   { X (STATUS_ACCESS_VIOLATION) },
63   { X (STATUS_ARRAY_BOUNDS_EXCEEDED) },
64   { X (STATUS_BREAKPOINT) },
65   { X (STATUS_CONTROL_C_EXIT) },
66   { X (STATUS_DATATYPE_MISALIGNMENT) },
67   { X (STATUS_FLOAT_DENORMAL_OPERAND) },
68   { X (STATUS_FLOAT_DIVIDE_BY_ZERO) },
69   { X (STATUS_FLOAT_INEXACT_RESULT) },
70   { X (STATUS_FLOAT_INVALID_OPERATION) },
71   { X (STATUS_FLOAT_OVERFLOW) },
72   { X (STATUS_FLOAT_STACK_CHECK) },
73   { X (STATUS_FLOAT_UNDERFLOW) },
74   { X (STATUS_GUARD_PAGE_VIOLATION) },
75   { X (STATUS_ILLEGAL_INSTRUCTION) },
76   { X (STATUS_INTEGER_DIVIDE_BY_ZERO) },
77   { X (STATUS_INTEGER_OVERFLOW) },
78   { X (STATUS_INVALID_DISPOSITION) },
79   { X (STATUS_IN_PAGE_ERROR) },
80   { X (STATUS_NONCONTINUABLE_EXCEPTION) },
81   { X (STATUS_NO_MEMORY) },
82   { X (STATUS_PENDING) },
83   { X (STATUS_PRIVILEGED_INSTRUCTION) },
84   { X (STATUS_SINGLE_STEP) },
85   { X (STATUS_STACK_OVERFLOW) },
86   { X (STATUS_TIMEOUT) },
87   { X (STATUS_USER_APC) },
88   { X (STATUS_WAIT_0) },
89   { 0, 0 }
90 #undef X
91 };
92
93 /* Initialization code.  */
94
95 void
96 init_console_handler (bool install_handler)
97 {
98   BOOL res;
99
100   SetConsoleCtrlHandler (ctrl_c_handler, FALSE);
101   SetConsoleCtrlHandler (NULL, FALSE);
102   if (install_handler)
103     res = SetConsoleCtrlHandler (ctrl_c_handler, TRUE);
104   else
105     res = SetConsoleCtrlHandler (NULL, TRUE);
106   if (!res)
107     system_printf ("SetConsoleCtrlHandler failed, %E");
108 }
109
110 extern "C" void
111 error_start_init (const char *buf)
112 {
113   if (!buf || !*buf)
114     {
115       debugger_command[0] = '\0';
116       return;
117     }
118
119   char pgm[NT_MAX_PATH];
120   if (!GetModuleFileName (NULL, pgm, NT_MAX_PATH))
121     strcpy (pgm, "cygwin1.dll");
122   for (char *p = strchr (pgm, '\\'); p; p = strchr (p, '\\'))
123     *p = '/';
124
125   __small_sprintf (debugger_command, "%s \"%s\"", buf, pgm);
126 }
127
128 static void
129 open_stackdumpfile ()
130 {
131   if (myself->progname[0])
132     {
133       const char *p;
134       /* write to progname.stackdump if possible */
135       if (!myself->progname[0])
136         p = "unknown";
137       else if ((p = strrchr (myself->progname, '\\')))
138         p++;
139       else
140         p = myself->progname;
141
142       WCHAR corefile[strlen (p) + sizeof (".stackdump")];
143       UNICODE_STRING ucore;
144       OBJECT_ATTRIBUTES attr;
145       /* Create the UNICODE variation of <progname>.stackdump. */
146       RtlInitEmptyUnicodeString (&ucore, corefile,
147                                  sizeof corefile - sizeof (WCHAR));
148       ucore.Length = sys_mbstowcs (ucore.Buffer,
149                                    ucore.MaximumLength / sizeof (WCHAR),
150                                    p, strlen (p)) * sizeof (WCHAR);
151       RtlAppendUnicodeToString (&ucore, L".stackdump");
152       /* Create an object attribute which refers to <progname>.stackdump
153          in Cygwin's cwd.  Stick to caseinsensitivity. */
154       InitializeObjectAttributes (&attr, &ucore, OBJ_CASE_INSENSITIVE,
155                                   cygheap->cwd.get_handle (), NULL);
156       HANDLE h;
157       IO_STATUS_BLOCK io;
158       NTSTATUS status;
159       /* Try to open it to dump the stack in it. */
160       status = NtCreateFile (&h, GENERIC_WRITE | SYNCHRONIZE, &attr, &io,
161                              NULL, FILE_ATTRIBUTE_NORMAL, 0, FILE_OVERWRITE_IF,
162                              FILE_SYNCHRONOUS_IO_NONALERT
163                              | FILE_OPEN_FOR_BACKUP_INTENT, NULL, 0);
164       if (NT_SUCCESS (status))
165         {
166           if (!myself->cygstarted)
167             system_printf ("Dumping stack trace to %S", &ucore);
168           else
169             debug_printf ("Dumping stack trace to %S", &ucore);
170           SetStdHandle (STD_ERROR_HANDLE, h);
171         }
172     }
173 }
174
175 /* Utilities for dumping the stack, etc.  */
176
177 static void
178 exception (EXCEPTION_RECORD *e,  CONTEXT *in)
179 {
180   const char *exception_name = NULL;
181
182   if (e)
183     {
184       for (int i = 0; status_info[i].name; i++)
185         {
186           if (status_info[i].code == e->ExceptionCode)
187             {
188               exception_name = status_info[i].name;
189               break;
190             }
191         }
192     }
193
194   if (exception_name)
195     small_printf ("Exception: %s at eip=%08x\r\n", exception_name, in->Eip);
196   else
197     small_printf ("Signal %d at eip=%08x\r\n", e->ExceptionCode, in->Eip);
198   small_printf ("eax=%08x ebx=%08x ecx=%08x edx=%08x esi=%08x edi=%08x\r\n",
199                 in->Eax, in->Ebx, in->Ecx, in->Edx, in->Esi, in->Edi);
200   small_printf ("ebp=%08x esp=%08x program=%s, pid %u, thread %s\r\n",
201                 in->Ebp, in->Esp, myself->progname, myself->pid, cygthread::name ());
202   small_printf ("cs=%04x ds=%04x es=%04x fs=%04x gs=%04x ss=%04x\r\n",
203                 in->SegCs, in->SegDs, in->SegEs, in->SegFs, in->SegGs, in->SegSs);
204 }
205
206 /* A class for manipulating the stack. */
207 class stack_info
208 {
209   int walk ();                  /* Uses the "old" method */
210   char *next_offset () {return *((char **) sf.AddrFrame.Offset);}
211   bool needargs;
212   DWORD dummy_frame;
213 public:
214   STACKFRAME sf;                 /* For storing the stack information */
215   void init (DWORD, bool, bool); /* Called the first time that stack info is needed */
216
217   /* Postfix ++ iterates over the stack, returning zero when nothing is left. */
218   int operator ++(int) { return walk (); }
219 };
220
221 /* The number of parameters used in STACKFRAME */
222 #define NPARAMS (sizeof (thestack.sf.Params) / sizeof (thestack.sf.Params[0]))
223
224 /* This is the main stack frame info for this process. */
225 static NO_COPY stack_info thestack;
226
227 /* Initialize everything needed to start iterating. */
228 void
229 stack_info::init (DWORD ebp, bool wantargs, bool goodframe)
230 {
231 # define debp ((DWORD *) ebp)
232   memset (&sf, 0, sizeof (sf));
233   if (!goodframe)
234     sf.AddrFrame.Offset = ebp;
235   else
236     {
237       dummy_frame = ebp;
238       sf.AddrFrame.Offset = (DWORD) &dummy_frame;
239     }
240   sf.AddrReturn.Offset = debp[1];
241   sf.AddrFrame.Mode = AddrModeFlat;
242   needargs = wantargs;
243 # undef debp
244 }
245
246 extern "C" void _cygwin_exit_return ();
247
248 /* Walk the stack by looking at successive stored 'bp' frames.
249    This is not foolproof. */
250 int
251 stack_info::walk ()
252 {
253   char **ebp;
254
255   if ((void (*) ()) sf.AddrPC.Offset == _cygwin_exit_return)
256     return 0;           /* stack frames are exhausted */
257
258   if (((ebp = (char **) next_offset ()) == NULL) || (ebp >= (char **) cygwin_hmodule))
259     return 0;
260
261   sf.AddrFrame.Offset = (DWORD) ebp;
262   sf.AddrPC.Offset = sf.AddrReturn.Offset;
263
264   /* The return address always follows the stack pointer */
265   sf.AddrReturn.Offset = (DWORD) *++ebp;
266
267   if (needargs)
268     {
269       unsigned nparams = NPARAMS;
270
271       /* The arguments follow the return address */
272       sf.Params[0] = (DWORD) *++ebp;
273       /* Hack for XP/2K3 WOW64.  If the first stack param points to the
274          application entry point, we can only fetch one additional
275          parameter.  Accessing anything beyond this address results in
276          a SEGV.  This is fixed in Vista/2K8 WOW64. */
277       if (wincap.has_restricted_stack_args () && sf.Params[0] == 0x401000)
278         nparams = 2;
279       for (unsigned i = 1; i < nparams; i++)
280         sf.Params[i] = (DWORD) *++ebp;
281     }
282
283   return 1;
284 }
285
286 static void
287 stackdump (DWORD ebp, int open_file, bool isexception)
288 {
289   extern unsigned long rlim_core;
290   static bool already_dumped;
291
292   if (rlim_core == 0UL || (open_file && already_dumped))
293     return;
294
295   if (open_file)
296     open_stackdumpfile ();
297
298   already_dumped = true;
299
300   int i;
301
302   thestack.init (ebp, 1, !isexception); /* Initialize from the input CONTEXT */
303   small_printf ("Stack trace:\r\nFrame     Function  Args\r\n");
304   for (i = 0; i < 16 && thestack++; i++)
305     {
306       small_printf ("%08x  %08x ", thestack.sf.AddrFrame.Offset,
307                     thestack.sf.AddrPC.Offset);
308       for (unsigned j = 0; j < NPARAMS; j++)
309         small_printf ("%s%08x", j == 0 ? " (" : ", ", thestack.sf.Params[j]);
310       small_printf (")\r\n");
311     }
312   small_printf ("End of stack trace%s\n",
313               i == 16 ? " (more stack frames may be present)" : "");
314 }
315
316 bool
317 _cygtls::inside_kernel (CONTEXT *cx)
318 {
319   int res;
320   MEMORY_BASIC_INFORMATION m;
321
322   if (!isinitialized ())
323     return true;
324
325   memset (&m, 0, sizeof m);
326   if (!VirtualQuery ((LPCVOID) cx->Eip, &m, sizeof m))
327     sigproc_printf ("couldn't get memory info, pc %p, %E", cx->Eip);
328
329   size_t size = (windows_system_directory_length + 6) * sizeof (WCHAR);
330   PWCHAR checkdir = (PWCHAR) alloca (size);
331   memset (checkdir, 0, size);
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 (!GetModuleFileNameW (h, checkdir, windows_system_directory_length + 6))
342     res = false;
343   else
344     {
345       /* Skip potential long path prefix. */
346       if (!wcsncmp (checkdir, L"\\\\?\\", 4))
347         checkdir += 4;
348       res = !wcsncasecmp (windows_system_directory, checkdir,
349                           windows_system_directory_length);
350     }
351   sigproc_printf ("pc %p, h %p, inside_kernel %d", cx->Eip, h, res);
352 # undef h
353   return res;
354 }
355
356 /* Temporary (?) function for external callers to get a stack dump */
357 extern "C" void
358 cygwin_stackdump ()
359 {
360   CONTEXT c;
361   c.ContextFlags = CONTEXT_FULL;
362   GetThreadContext (GetCurrentThread (), &c);
363   stackdump (c.Ebp, 0, 0);
364 }
365
366 #define TIME_TO_WAIT_FOR_DEBUGGER 10000
367
368 extern "C" int
369 try_to_debug (bool waitloop)
370 {
371   debug_printf ("debugger_command '%s'", debugger_command);
372   if (*debugger_command == '\0')
373     return 0;
374   if (being_debugged ())
375     {
376       extern void break_here ();
377       break_here ();
378       return 0;
379     }
380
381   __small_sprintf (strchr (debugger_command, '\0'), " %u", GetCurrentProcessId ());
382
383   LONG prio = GetThreadPriority (GetCurrentThread ());
384   SetThreadPriority (GetCurrentThread (), THREAD_PRIORITY_HIGHEST);
385   PROCESS_INFORMATION pi = {NULL, 0, 0, 0};
386
387   STARTUPINFOW si = {0, NULL, NULL, NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL};
388   si.lpReserved = NULL;
389   si.lpDesktop = NULL;
390   si.dwFlags = 0;
391   si.cb = sizeof (si);
392
393   /* FIXME: need to know handles of all running threads to
394      suspend_all_threads_except (current_thread_id);
395   */
396
397   /* if any of these mutexes is owned, we will fail to start any cygwin app
398      until trapped app exits */
399
400   lock_ttys::release ();
401
402   /* prevent recursive exception handling */
403   PWCHAR rawenv = GetEnvironmentStringsW () ;
404   for (PWCHAR p = rawenv; *p != L'\0'; p = wcschr (p, L'\0') + 1)
405     {
406       if (wcsncmp (p, L"CYGWIN=", wcslen (L"CYGWIN=")) == 0)
407         {
408           PWCHAR q = wcsstr (p, L"error_start") ;
409           /* replace 'error_start=...' with '_rror_start=...' */
410           if (q)
411             {
412               *q = L'_' ;
413               SetEnvironmentVariableW (L"CYGWIN", p + wcslen (L"CYGWIN=")) ;
414             }
415           break ;
416         }
417     }
418
419   console_printf ("*** starting debugger for pid %u, tid %u\n",
420                   cygwin_pid (GetCurrentProcessId ()), GetCurrentThreadId ());
421   BOOL dbg;
422   WCHAR dbg_cmd[strlen(debugger_command)];
423   sys_mbstowcs (dbg_cmd, strlen(debugger_command) + 1, debugger_command);
424   dbg = CreateProcessW (NULL,
425                         dbg_cmd,
426                         NULL,
427                         NULL,
428                         FALSE,
429                         CREATE_NEW_CONSOLE | CREATE_NEW_PROCESS_GROUP,
430                         NULL,
431                         NULL,
432                         &si,
433                         &pi);
434
435   if (!dbg)
436     system_printf ("Failed to start debugger, %E");
437   else
438     {
439       if (!waitloop)
440         return dbg;
441       SetThreadPriority (GetCurrentThread (), THREAD_PRIORITY_IDLE);
442       while (!being_debugged ())
443         low_priority_sleep (0);
444       Sleep (2000);
445     }
446
447   console_printf ("*** continuing pid %u from debugger call (%d)\n",
448                   cygwin_pid (GetCurrentProcessId ()), dbg);
449
450   SetThreadPriority (GetCurrentThread (), prio);
451   return dbg;
452 }
453
454 extern "C" DWORD __stdcall RtlUnwind (void *, void *, void *, DWORD);
455 static void __stdcall rtl_unwind (exception_list *, PEXCEPTION_RECORD) __attribute__ ((noinline, regparm (3)));
456 void __stdcall
457 rtl_unwind (exception_list *frame, PEXCEPTION_RECORD e)
458 {
459   __asm__ ("\n\
460   pushl         %%ebx                                   \n\
461   pushl         %%edi                                   \n\
462   pushl         %%esi                                   \n\
463   pushl         $0                                      \n\
464   pushl         %1                                      \n\
465   pushl         $1f                                     \n\
466   pushl         %0                                      \n\
467   call          _RtlUnwind@16                           \n\
468 1:                                                      \n\
469   popl          %%esi                                   \n\
470   popl          %%edi                                   \n\
471   popl          %%ebx                                   \n\
472 ": : "r" (frame), "r" (e));
473 }
474
475 /* Main exception handler. */
476
477 extern exception_list *_except_list asm ("%fs:0");
478
479 int
480 _cygtls::handle_exceptions (EXCEPTION_RECORD *e, exception_list *frame, CONTEXT *in, void *)
481 {
482   static bool NO_COPY debugging;
483   static int NO_COPY recursed;
484   _cygtls& me = _my_tls;
485
486   if (debugging && ++debugging < 500000)
487     {
488       SetThreadPriority (hMainThread, THREAD_PRIORITY_NORMAL);
489       return 0;
490     }
491
492   /* If we've already exited, don't do anything here.  Returning 1
493      tells Windows to keep looking for an exception handler.  */
494   if (exit_already || e->ExceptionFlags)
495     return 1;
496
497   siginfo_t si = {0};
498   si.si_code = SI_KERNEL;
499   /* Coerce win32 value to posix value.  */
500   switch (e->ExceptionCode)
501     {
502     case STATUS_FLOAT_DENORMAL_OPERAND:
503     case STATUS_FLOAT_DIVIDE_BY_ZERO:
504     case STATUS_FLOAT_INVALID_OPERATION:
505     case STATUS_FLOAT_STACK_CHECK:
506       si.si_signo = SIGFPE;
507       si.si_code = FPE_FLTSUB;
508       break;
509     case STATUS_FLOAT_INEXACT_RESULT:
510       si.si_signo = SIGFPE;
511       si.si_code = FPE_FLTRES;
512       break;
513     case STATUS_FLOAT_OVERFLOW:
514       si.si_signo = SIGFPE;
515       si.si_code = FPE_FLTOVF;
516       break;
517     case STATUS_FLOAT_UNDERFLOW:
518       si.si_signo = SIGFPE;
519       si.si_code = FPE_FLTUND;
520       break;
521     case STATUS_INTEGER_DIVIDE_BY_ZERO:
522       si.si_signo = SIGFPE;
523       si.si_code = FPE_INTDIV;
524       break;
525     case STATUS_INTEGER_OVERFLOW:
526       si.si_signo = SIGFPE;
527       si.si_code = FPE_INTOVF;
528       break;
529
530     case STATUS_ILLEGAL_INSTRUCTION:
531       si.si_signo = SIGILL;
532       si.si_code = ILL_ILLOPC;
533       break;
534
535     case STATUS_PRIVILEGED_INSTRUCTION:
536       si.si_signo = SIGILL;
537       si.si_code = ILL_PRVOPC;
538       break;
539
540     case STATUS_NONCONTINUABLE_EXCEPTION:
541       si.si_signo = SIGILL;
542       si.si_code = ILL_ILLADR;
543       break;
544
545     case STATUS_TIMEOUT:
546       si.si_signo = SIGALRM;
547       break;
548
549     case STATUS_GUARD_PAGE_VIOLATION:
550       si.si_signo = SIGBUS;
551       si.si_code = BUS_OBJERR;
552       break;
553
554     case STATUS_DATATYPE_MISALIGNMENT:
555       si.si_signo = SIGBUS;
556       si.si_code = BUS_ADRALN;
557       break;
558
559     case STATUS_ACCESS_VIOLATION:
560       switch (mmap_is_attached_or_noreserve ((void *)e->ExceptionInformation[1],
561                                              1))
562         {
563         case MMAP_NORESERVE_COMMITED:
564           return 0;
565         case MMAP_RAISE_SIGBUS: /* MAP_NORESERVE page, commit failed, or
566                                    access to mmap page beyond EOF. */
567           si.si_signo = SIGBUS;
568           si.si_code = BUS_OBJERR;
569           break;
570         default:
571           MEMORY_BASIC_INFORMATION m;
572           VirtualQuery ((PVOID) e->ExceptionInformation[1], &m, sizeof m);
573           si.si_signo = SIGSEGV;
574           si.si_code = m.State == MEM_FREE ? SEGV_MAPERR : SEGV_ACCERR;
575           break;
576         }
577       break;
578
579     case STATUS_ARRAY_BOUNDS_EXCEEDED:
580     case STATUS_IN_PAGE_ERROR:
581     case STATUS_NO_MEMORY:
582     case STATUS_INVALID_DISPOSITION:
583     case STATUS_STACK_OVERFLOW:
584       si.si_signo = SIGSEGV;
585       si.si_code = SEGV_MAPERR;
586       break;
587
588     case STATUS_CONTROL_C_EXIT:
589       si.si_signo = SIGINT;
590       break;
591
592     case STATUS_INVALID_HANDLE:
593       /* CloseHandle will throw this exception if it is given an
594          invalid handle.  We don't care about the exception; we just
595          want CloseHandle to return an error.  This can be revisited
596          if gcc ever supports Windows style structured exception
597          handling.  */
598       return 0;
599
600     default:
601       /* If we don't recognize the exception, we have to assume that
602          we are doing structured exception handling, and we let
603          something else handle it.  */
604       return 1;
605     }
606
607   debug_printf ("In cygwin_except_handler exc %p at %p sp %p", e->ExceptionCode, in->Eip, in->Esp);
608   debug_printf ("In cygwin_except_handler sig %d at %p", si.si_signo, in->Eip);
609
610   bool masked = !!(me.sigmask & SIGTOMASK (si.si_signo));
611   if (masked)
612     syscall_printf ("signal %d, masked %p", si.si_signo,
613                     global_sigs[si.si_signo].sa_mask);
614
615   debug_printf ("In cygwin_except_handler calling %p",
616                  global_sigs[si.si_signo].sa_handler);
617
618   DWORD *ebp = (DWORD *) in->Esp;
619   for (DWORD *bpend = (DWORD *) __builtin_frame_address (0); ebp > bpend; ebp--)
620     if (*ebp == in->SegCs && ebp[-1] == in->Eip)
621       {
622         ebp -= 2;
623         break;
624       }
625
626   if (me.fault_guarded ())
627     me.return_from_fault ();
628
629   me.copy_context (in);
630
631   /* Temporarily replace windows top level SEH with our own handler.
632      We don't want any Windows magic kicking in.  This top level frame
633      will be removed automatically after our exception handler returns. */
634   _except_list->handler = _cygtls::handle_exceptions;
635
636   if (masked
637       || &me == _sig_tls
638       || !cygwin_finished_initializing
639       || (void *) global_sigs[si.si_signo].sa_handler == (void *) SIG_DFL
640       || (void *) global_sigs[si.si_signo].sa_handler == (void *) SIG_IGN
641       || (void *) global_sigs[si.si_signo].sa_handler == (void *) SIG_ERR)
642     {
643       /* Print the exception to the console */
644       if (!myself->cygstarted)
645         for (int i = 0; status_info[i].name; i++)
646           if (status_info[i].code == e->ExceptionCode)
647             {
648               system_printf ("Exception: %s", status_info[i].name);
649               break;
650             }
651
652       /* Another exception could happen while tracing or while exiting.
653          Only do this once.  */
654       if (recursed++)
655         system_printf ("Error while dumping state (probably corrupted stack)");
656       else
657         {
658           if (try_to_debug (0))
659             {
660               debugging = true;
661               return 0;
662             }
663
664           rtl_unwind (frame, e);
665           open_stackdumpfile ();
666           exception (e, in);
667           stackdump ((DWORD) ebp, 0, 1);
668         }
669
670       if (e->ExceptionCode == STATUS_ACCESS_VIOLATION)
671         {
672           int error_code = 0;
673           if (si.si_code == SEGV_ACCERR)        /* Address present */
674             error_code |= 1;
675           if (e->ExceptionInformation[0])       /* Write access */
676             error_code |= 2;
677           if (!me.inside_kernel (in))           /* User space */
678             error_code |= 4;
679           klog (LOG_INFO, "%s[%d]: segfault at %08x rip %08x rsp %08x error %d",
680                           __progname, myself->pid,
681                           e->ExceptionInformation[1], in->Eip, in->Esp,
682                           ((in->Eip >= 0x61000000 && in->Eip < 0x61200000)
683                            ? 0 : 4) | (e->ExceptionInformation[0] << 1));
684         }
685
686       me.signal_exit (0x80 | si.si_signo);      // Flag signal + core dump
687     }
688
689   si.si_addr =  (si.si_signo == SIGSEGV || si.si_signo == SIGBUS
690                  ? (void *) e->ExceptionInformation[1]
691                  : (void *) in->Eip);
692   si.si_errno = si.si_pid = si.si_uid = 0;
693   me.incyg++;
694   sig_send (NULL, si, &me);     // Signal myself
695   me.incyg--;
696   e->ExceptionFlags = 0;
697   return 0;
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->stopsig = SIGCONT;
766       myself->alert_parent (SIGCONT);
767       break;
768     default:
769       api_fatal ("WaitSingleObject failed, %E");
770       break;
771     }
772   _my_tls.incyg = 0;
773 }
774 }
775
776 bool
777 _cygtls::interrupt_now (CONTEXT *cx, int sig, void *handler,
778                         struct sigaction& siga)
779 {
780   bool interrupted;
781
782   if (incyg || spinning || locked () || inside_kernel (cx))
783     interrupted = false;
784   else
785     {
786       push ((__stack_t) cx->Eip);
787       interrupt_setup (sig, handler, siga);
788       cx->Eip = pop ();
789       SetThreadContext (*this, cx); /* Restart the thread in a new location */
790       interrupted = true;
791     }
792   return interrupted;
793 }
794
795 void __stdcall
796 _cygtls::interrupt_setup (int sig, void *handler, struct sigaction& siga)
797 {
798   push ((__stack_t) sigdelayed);
799   deltamask = siga.sa_mask & ~SIG_NONMASKABLE;
800   sa_flags = siga.sa_flags;
801   func = (void (*) (int)) handler;
802   if (siga.sa_flags & SA_RESETHAND)
803     siga.sa_handler = SIG_DFL;
804   saved_errno = -1;             // Flag: no errno to save
805   if (handler == sig_handle_tty_stop)
806     {
807       myself->stopsig = 0;
808       myself->process_state |= PID_STOPPED;
809     }
810
811   this->sig = sig;                      // Should always be last thing set to avoid a race
812
813   if (!event)
814     threadkill = false;
815   else
816     {
817       HANDLE h = event;
818       event = NULL;
819       SetEvent (h);
820     }
821
822   /* Clear any waiting threads prior to dispatching to handler function */
823   int res = SetEvent (signal_arrived);  // For an EINTR case
824   proc_subproc (PROC_CLEARWAIT, 1);
825   sigproc_printf ("armed signal_arrived %p, sig %d, res %d", signal_arrived,
826                   sig, res);
827 }
828
829 extern "C" void __stdcall
830 set_sig_errno (int e)
831 {
832   *_my_tls.errno_addr = e;
833   _my_tls.saved_errno = e;
834   // sigproc_printf ("errno %d", e);
835 }
836
837 static int setup_handler (int, void *, struct sigaction&, _cygtls *tls)
838   __attribute__((regparm(3)));
839 static int
840 setup_handler (int sig, void *handler, struct sigaction& siga, _cygtls *tls)
841 {
842   CONTEXT cx;
843   bool interrupted = false;
844
845   if (tls->sig)
846     {
847       sigproc_printf ("trying to send sig %d but signal %d already armed",
848                       sig, tls->sig);
849       goto out;
850     }
851
852   for (int i = 0; i < CALL_HANDLER_RETRY; i++)
853     {
854       tls->lock ();
855       if (tls->incyg)
856         {
857           sigproc_printf ("controlled interrupt. stackptr %p, stack %p, stackptr[-1] %p",
858                           tls->stackptr, tls->stack, tls->stackptr[-1]);
859           tls->interrupt_setup (sig, handler, siga);
860           interrupted = true;
861           tls->unlock ();
862           break;
863         }
864
865       tls->unlock ();
866       DWORD res;
867       HANDLE hth = (HANDLE) *tls;
868
869       /* Suspend the thread which will receive the signal.
870          For Windows 95, we also have to ensure that the addresses returned by
871          GetThreadContext are valid.
872          If one of these conditions is not true we loop for a fixed number of times
873          since we don't want to stall the signal handler.  FIXME: Will this result in
874          noticeable delays?
875          If the thread is already suspended (which can occur when a program has called
876          SuspendThread on itself) then just queue the signal. */
877
878 #ifndef DEBUGGING
879       sigproc_printf ("suspending mainthread");
880 #else
881       cx.ContextFlags = CONTEXT_CONTROL | CONTEXT_INTEGER;
882       if (!GetThreadContext (hth, &cx))
883         memset (&cx, 0, sizeof cx);
884       sigproc_printf ("suspending mainthread PC %p", cx.Eip);
885 #endif
886       res = SuspendThread (hth);
887       /* Just set pending if thread is already suspended */
888       if (res)
889         {
890           ResumeThread (hth);
891           break;
892         }
893       cx.ContextFlags = CONTEXT_CONTROL | CONTEXT_INTEGER;
894       if (!GetThreadContext (hth, &cx))
895         system_printf ("couldn't get context of main thread, %E");
896       else
897         interrupted = tls->interrupt_now (&cx, sig, handler, siga);
898
899       res = ResumeThread (hth);
900       if (interrupted)
901         break;
902
903       sigproc_printf ("couldn't interrupt.  trying again.");
904       low_priority_sleep (0);
905     }
906
907 out:
908   sigproc_printf ("signal %d %sdelivered", sig, interrupted ? "" : "not ");
909   return interrupted;
910 }
911
912 static inline bool
913 has_visible_window_station ()
914 {
915   HWINSTA station_hdl;
916   USEROBJECTFLAGS uof;
917   DWORD len;
918
919   /* Check if the process is associated with a visible window station.
920      These are processes running on the local desktop as well as processes
921      running in terminal server sessions.
922      Processes running in a service session not explicitely associated
923      with the desktop (using the "Allow service to interact with desktop"
924      property) are running in an invisible window station. */
925   if ((station_hdl = GetProcessWindowStation ())
926       && GetUserObjectInformationW (station_hdl, UOI_FLAGS, &uof,
927                                     sizeof uof, &len)
928       && (uof.dwFlags & WSF_VISIBLE))
929     return true;
930   return false;
931 }
932
933 /* Keyboard interrupt handler.  */
934 static BOOL WINAPI
935 ctrl_c_handler (DWORD type)
936 {
937   static bool saw_close;
938   lock_process now;
939
940   if (!cygwin_finished_initializing)
941     {
942       if (myself->cygstarted)   /* Was this process created by a cygwin process? */
943         return TRUE;            /* Yes.  Let the parent eventually handle CTRL-C issues. */
944       debug_printf ("exiting with status %p", STATUS_CONTROL_C_EXIT);
945       ExitProcess (STATUS_CONTROL_C_EXIT);
946     }
947
948   _my_tls.remove (INFINITE);
949
950 #if 0
951   if (type == CTRL_C_EVENT || type == CTRL_BREAK_EVENT)
952     proc_subproc (PROC_KILLFORKED, 0);
953 #endif
954
955   /* Return FALSE to prevent an "End task" dialog box from appearing
956      for each Cygwin process window that's open when the computer
957      is shut down or console window is closed. */
958
959   if (type == CTRL_SHUTDOWN_EVENT)
960     {
961 #if 0
962       /* Don't send a signal.  Only NT service applications and their child
963          processes will receive this event and the services typically already
964          handle the shutdown action when getting the SERVICE_CONTROL_SHUTDOWN
965          control message. */
966       sig_send (NULL, SIGTERM);
967 #endif
968       return FALSE;
969     }
970
971   if (myself->ctty != -1)
972     {
973       if (type == CTRL_CLOSE_EVENT)
974         {
975           sig_send (NULL, SIGHUP);
976           saw_close = true;
977           return FALSE;
978         }
979       if (!saw_close && type == CTRL_LOGOFF_EVENT)
980         {
981           /* The CTRL_LOGOFF_EVENT is sent when *any* user logs off.
982              The below code sends a SIGHUP only if it is not performing the
983              default activity for SIGHUP.  Note that it is possible for two
984              SIGHUP signals to arrive if a process group leader is exiting
985              too.  Getting this 100% right is saved for a future cygwin mailing
986              list goad.  */
987           if (global_sigs[SIGHUP].sa_handler != SIG_DFL)
988             {
989               sig_send (myself_nowait, SIGHUP);
990               return TRUE;
991             }
992           return FALSE;
993         }
994     }
995
996   if (chExeced)
997     {
998       chExeced->set_saw_ctrl_c ();
999       return TRUE;
1000     }
1001
1002   /* We're only the process group leader when we have a valid pinfo structure.
1003      If we don't have one, then the parent "stub" will handle the signal. */
1004   if (!pinfo (cygwin_pid (GetCurrentProcessId ())))
1005     return TRUE;
1006
1007   tty_min *t = cygwin_shared->tty.get_tty (myself->ctty);
1008   /* Ignore this if we're not the process group leader since it should be handled
1009      *by* the process group leader. */
1010   if (myself->ctty != -1 && t->getpgid () == myself->pid &&
1011        (GetTickCount () - t->last_ctrl_c) >= MIN_CTRL_C_SLOP)
1012     /* Otherwise we just send a SIGINT to the process group and return TRUE (to indicate
1013        that we have handled the signal).  At this point, type should be
1014        a CTRL_C_EVENT or CTRL_BREAK_EVENT. */
1015     {
1016       int sig = SIGINT;
1017       /* If intr and quit are both mapped to ^C, send SIGQUIT on ^BREAK */
1018       if (type == CTRL_BREAK_EVENT
1019           && t->ti.c_cc[VINTR] == 3 && t->ti.c_cc[VQUIT] == 3)
1020         sig = SIGQUIT;
1021       t->last_ctrl_c = GetTickCount ();
1022       killsys (-myself->pid, sig);
1023       t->last_ctrl_c = GetTickCount ();
1024       return TRUE;
1025     }
1026
1027   return TRUE;
1028 }
1029
1030 /* Function used by low level sig wrappers. */
1031 extern "C" void __stdcall
1032 set_process_mask (sigset_t newmask)
1033 {
1034   set_signal_mask (newmask, _my_tls.sigmask);
1035 }
1036
1037 extern "C" int
1038 sighold (int sig)
1039 {
1040   /* check that sig is in right range */
1041   if (sig < 0 || sig >= NSIG)
1042     {
1043       set_errno (EINVAL);
1044       syscall_printf ("signal %d out of range", sig);
1045       return -1;
1046     }
1047   mask_sync.acquire (INFINITE);
1048   sigset_t mask = _my_tls.sigmask;
1049   sigaddset (&mask, sig);
1050   set_signal_mask (mask, _my_tls.sigmask);
1051   mask_sync.release ();
1052   return 0;
1053 }
1054
1055 extern "C" int
1056 sigrelse (int sig)
1057 {
1058   /* check that sig is in right range */
1059   if (sig < 0 || sig >= NSIG)
1060     {
1061       set_errno (EINVAL);
1062       syscall_printf ("signal %d out of range", sig);
1063       return -1;
1064     }
1065   mask_sync.acquire (INFINITE);
1066   sigset_t mask = _my_tls.sigmask;
1067   sigdelset (&mask, sig);
1068   set_signal_mask (mask, _my_tls.sigmask);
1069   mask_sync.release ();
1070   return 0;
1071 }
1072
1073 extern "C" _sig_func_ptr
1074 sigset (int sig, _sig_func_ptr func)
1075 {
1076   sig_dispatch_pending ();
1077   _sig_func_ptr prev;
1078
1079   /* check that sig is in right range */
1080   if (sig < 0 || sig >= NSIG || sig == SIGKILL || sig == SIGSTOP)
1081     {
1082       set_errno (EINVAL);
1083       syscall_printf ("SIG_ERR = sigset (%d, %p)", sig, func);
1084       return (_sig_func_ptr) SIG_ERR;
1085     }
1086
1087   mask_sync.acquire (INFINITE);
1088   sigset_t mask = _my_tls.sigmask;
1089   /* If sig was in the signal mask return SIG_HOLD, otherwise return the
1090      previous disposition. */
1091   if (sigismember (&mask, sig))
1092     prev = SIG_HOLD;
1093   else
1094     prev = global_sigs[sig].sa_handler;
1095   /* If func is SIG_HOLD, add sig to the signal mask, otherwise set the
1096      disposition to func and remove sig from the signal mask. */
1097   if (func == SIG_HOLD)
1098     sigaddset (&mask, sig);
1099   else
1100     {
1101       /* No error checking.  The test which could return SIG_ERR has already
1102          been made above. */
1103       signal (sig, func);
1104       sigdelset (&mask, sig);
1105     }
1106   set_signal_mask (mask, _my_tls.sigmask);
1107   mask_sync.release ();
1108   return prev;
1109 }
1110
1111 extern "C" int
1112 sigignore (int sig)
1113 {
1114   return sigset (sig, SIG_IGN) == SIG_ERR ? -1 : 0;
1115 }
1116
1117 /* Update the signal mask for this process and return the old mask.
1118    Called from sigdelayed */
1119 extern "C" sigset_t
1120 set_process_mask_delta ()
1121 {
1122   mask_sync.acquire (INFINITE);
1123   sigset_t newmask, oldmask;
1124
1125   if (_my_tls.deltamask & SIG_NONMASKABLE)
1126     oldmask = _my_tls.oldmask; /* from handle_sigsuspend */
1127   else
1128     oldmask = _my_tls.sigmask;
1129   newmask = (oldmask | _my_tls.deltamask) & ~SIG_NONMASKABLE;
1130   sigproc_printf ("oldmask %p, newmask %p, deltamask %p", oldmask, newmask,
1131                   _my_tls.deltamask);
1132   _my_tls.sigmask = newmask;
1133   mask_sync.release ();
1134   return oldmask;
1135 }
1136
1137 /* Set the signal mask for this process.
1138    Note that some signals are unmaskable, as in UNIX.  */
1139 extern "C" void __stdcall
1140 set_signal_mask (sigset_t newmask, sigset_t& oldmask)
1141 {
1142 #ifdef CGF
1143   if (&_my_tls == _sig_tls)
1144     small_printf ("********* waiting in signal thread\n");
1145 #endif
1146   mask_sync.acquire (INFINITE);
1147   newmask &= ~SIG_NONMASKABLE;
1148   sigset_t mask_bits = oldmask & ~newmask;
1149   sigproc_printf ("oldmask %p, newmask %p, mask_bits %p", oldmask, newmask,
1150                   mask_bits);
1151   oldmask = newmask;
1152   if (mask_bits)
1153     sig_dispatch_pending (true);
1154   else
1155     sigproc_printf ("not calling sig_dispatch_pending");
1156   mask_sync.release ();
1157 }
1158
1159 int __stdcall
1160 sigpacket::process ()
1161 {
1162   DWORD continue_now;
1163   struct sigaction dummy = global_sigs[SIGSTOP];
1164
1165   if (si.si_signo != SIGCONT)
1166     continue_now = false;
1167   else
1168     {
1169       continue_now = myself->process_state & PID_STOPPED;
1170       myself->stopsig = 0;
1171       myself->process_state &= ~PID_STOPPED;
1172       /* Clear pending stop signals */
1173       sig_clear (SIGSTOP);
1174       sig_clear (SIGTSTP);
1175       sig_clear (SIGTTIN);
1176       sig_clear (SIGTTOU);
1177     }
1178
1179   int rc = 1;
1180
1181   sigproc_printf ("signal %d processing", si.si_signo);
1182   struct sigaction& thissig = global_sigs[si.si_signo];
1183
1184   myself->rusage_self.ru_nsignals++;
1185
1186   bool masked;
1187   void *handler;
1188   if (!hExeced || (void *) thissig.sa_handler == (void *) SIG_IGN)
1189     handler = (void *) thissig.sa_handler;
1190   else if (tls)
1191     return 1;
1192   else
1193     handler = NULL;
1194
1195   _cygtls *use_tls = tls ?: _main_tls;
1196
1197   if (si.si_signo == SIGKILL)
1198     goto exit_sig;
1199   if (si.si_signo == SIGSTOP)
1200     {
1201       sig_clear (SIGCONT);
1202       goto stop;
1203     }
1204
1205   bool insigwait_mask;
1206   if ((masked = ISSTATE (myself, PID_STOPPED)))
1207     insigwait_mask = false;
1208   else if (tls)
1209     insigwait_mask = sigismember (&tls->sigwait_mask, si.si_signo);
1210   else
1211     {
1212       insigwait_mask = !handler && (tls = _cygtls::find_tls (si.si_signo));
1213       if (tls)
1214         use_tls = tls;
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   sigproc_printf ("releasing sigwait for thread");
1301   SetEvent (use_tls->event);
1302   goto done;
1303
1304 exit_sig:
1305   if (si.si_signo == SIGQUIT || si.si_signo == SIGABRT)
1306     {
1307       CONTEXT c;
1308       c.ContextFlags = CONTEXT_FULL;
1309       GetThreadContext (hMainThread, &c);
1310       use_tls->copy_context (&c);
1311       si.si_signo |= 0x80;
1312     }
1313   sigproc_printf ("signal %d, about to call do_exit", si.si_signo);
1314   use_tls->signal_exit (si.si_signo);   /* never returns */
1315 }
1316
1317 /* Cover function to `do_exit' to handle exiting even in presence of more
1318    exceptions.  We used to call exit, but a SIGSEGV shouldn't cause atexit
1319    routines to run.  */
1320 void
1321 _cygtls::signal_exit (int rc)
1322 {
1323   if (hExeced)
1324     {
1325       sigproc_printf ("terminating captive process");
1326       TerminateProcess (hExeced, sigExeced = rc);
1327     }
1328
1329   signal_debugger (rc & 0x7f);
1330   if ((rc & 0x80) && !try_to_debug ())
1331     stackdump (thread_context.ebp, 1, 1);
1332
1333   lock_process until_exit (true);
1334   if (hExeced || exit_state > ES_PROCESS_LOCKED)
1335     myself.exit (rc);
1336
1337   /* Starve other threads in a vain attempt to stop them from doing something
1338      stupid. */
1339   SetThreadPriority (GetCurrentThread (), THREAD_PRIORITY_TIME_CRITICAL);
1340
1341   sigproc_printf ("about to call do_exit (%x)", rc);
1342   SetEvent (signal_arrived);
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)
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 }