diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog index 77c3a5cfe..36f02a4ba 100644 --- a/winsup/cygwin/ChangeLog +++ b/winsup/cygwin/ChangeLog @@ -1,3 +1,33 @@ +Thu Mar 9 15:25:01 2000 Christopher Faylor + + * environ.cc: Eliminate oldstack CYGWIN option. + * exceptions.cc (sfta): Eliminate obsolete function. + (sgmb): Eliminate obsolete function. + (class stack_info): Remove MS method for walking the stack. + (stack_info::init): Just initialize required fields. + (stack_info::brute_force): Rename to stack_info::walk. + (handle_exceptions): Pass derived frame pointer to sig_send. + (interrupt_setup): Clear saved frame pointer here. + (interrupt_on_return): thestack is no longer a pointer. + (call_handler): Accept a flag to indicate when a signal was sent from + other than the main thread. Use saved frame pointer for determining + where to place signal handler call. + (sig_handle): Accept "nonmain" argument. Pass it to call_handler. + * fhandler_tty.cc (fhandler_tty_common::__acquire_output_mutex): Change + debugging output slightly. + * (fhandler_tty_common::__release_output_mutex): Ditto. + (fhandler_tty_slave::read): Fix a comment, remove a goto. + * sigproc.cc (sig_send): Accept an optional frame pointer argument for + use when suspending the main process. sigcomplete_main is an autoreset + event now. Save frame pointer for non-main operation. + (wait_sig): Make sigcomplete_main an autoreset event. Eliminate + NOSIGQUEUE. Pass rc to sig_handle to signify if this was a nonmain + process. + * sigproc.h: Reflect change to sig_send argument. + * syscalls.cc (swab): Eliminate swab function since it is now available + in newlib. + * winsup.h (signal_dispatch): Change CONTEXT cx to DWORD ebp. + Tue Mar 7 13:31:10 2000 Christopher Faylor * sigproc.cc (sig_send): Eliminate sync_sig_send synchronization since diff --git a/winsup/cygwin/environ.cc b/winsup/cygwin/environ.cc index 56ec6d847..ba3120fe3 100644 --- a/winsup/cygwin/environ.cc +++ b/winsup/cygwin/environ.cc @@ -19,7 +19,6 @@ extern BOOL allow_glob; extern BOOL allow_ntea; extern BOOL strip_title_path; extern DWORD chunksize; -extern BOOL oldstack; BOOL threadsafe; BOOL reset_com = TRUE; static BOOL envcache = TRUE; @@ -320,7 +319,6 @@ struct parse_thing {"glob", {&allow_glob}, justset, NULL, {{FALSE}, {TRUE}}}, {"ntea", {&allow_ntea}, justset, NULL, {{FALSE}, {TRUE}}}, {"ntsec", {&allow_ntsec}, justset, NULL, {{FALSE}, {TRUE}}}, - {"oldstack", {&oldstack}, justset, NULL, {{FALSE}, {TRUE}}}, {"reset_com", {&reset_com}, justset, NULL, {{FALSE}, {TRUE}}}, {"strip_title", {&strip_title_path}, justset, NULL, {{FALSE}, {TRUE}}}, {"title", {&display_title}, justset, NULL, {{FALSE}, {TRUE}}}, diff --git a/winsup/cygwin/exceptions.cc b/winsup/cygwin/exceptions.cc index dae689285..57cb232c9 100644 --- a/winsup/cygwin/exceptions.cc +++ b/winsup/cygwin/exceptions.cc @@ -191,27 +191,11 @@ exception (EXCEPTION_RECORD *e, CONTEXT *in) #endif } -extern "C" { -static LPVOID __stdcall -sfta(HANDLE, DWORD) -{ - return NULL; -} - -static DWORD __stdcall -sgmb(HANDLE, DWORD) -{ - return 4; -} - #ifdef __i386__ /* Print a stack backtrace. */ #define HAVE_STACK_TRACE -/* Set from CYGWIN environment variable if want to use old method. */ -BOOL NO_COPY oldstack = 0; - /* The function used to load the imagehlp DLL. Returns TRUE if the DLL was found. */ static LoadDLLinitfunc (imagehlp) @@ -227,53 +211,38 @@ LoadDLLfunc (StackWalk, StackWalk@36, imagehlp) class stack_info { int first_time; /* True if just starting to iterate. */ - HANDLE hproc; /* Handle of process to inspect. */ - HANDLE hthread; /* Handle of thread to inspect. */ - int (stack_info::*get) (HANDLE, HANDLE); /* Gets the next stack frame */ + int walk (); /* Uses the "old" method */ public: STACKFRAME sf; /* For storing the stack information */ - int walk (HANDLE, HANDLE); /* Uses the StackWalk function */ - int brute_force (HANDLE, HANDLE); /* Uses the "old" method */ - void init (CONTEXT *); /* Called the first time that stack info is needed */ + void init (DWORD); /* Called the first time that stack info is needed */ + stack_info (): first_time(1) {} - /* The constructor remembers hproc and hthread and determines which stack walking - method to use */ - stack_info (int use_old_stack, HANDLE hp, HANDLE ht): hproc(hp), hthread(ht) - { - if (!use_old_stack && LoadDLLinitnow (imagehlp)) - get = &stack_info::walk; - else - get = &stack_info::brute_force; - } /* Postfix ++ iterates over the stack, returning zero when nothing is left. */ - int operator ++(int) { return (this->*get) (hproc, hthread); } + int operator ++(int) { return this->walk (); } }; /* The number of parameters used in STACKFRAME */ -#define NPARAMS (sizeof(thestack->sf.Params) / sizeof(thestack->sf.Params[0])) +#define NPARAMS (sizeof(thestack.sf.Params) / sizeof(thestack.sf.Params[0])) /* This is the main stack frame info for this process. */ -static stack_info *thestack = NULL; -static signal_dispatch sigsave; +static NO_COPY stack_info thestack; +signal_dispatch NO_COPY sigsave; /* Initialize everything needed to start iterating. */ void -stack_info::init (CONTEXT *cx) +stack_info::init (DWORD ebp) { first_time = 1; memset (&sf, 0, sizeof(sf)); - sf.AddrPC.Offset = cx->Eip; - sf.AddrPC.Mode = AddrModeFlat; - sf.AddrStack.Offset = cx->Esp; - sf.AddrStack.Mode = AddrModeFlat; - sf.AddrFrame.Offset = cx->Ebp; + sf.AddrFrame.Offset = ebp; + sf.AddrPC.Offset = ((DWORD *) ebp)[1]; sf.AddrFrame.Mode = AddrModeFlat; } /* Walk the stack by looking at successive stored 'bp' frames. This is not foolproof. */ int -stack_info::brute_force (HANDLE, HANDLE) +stack_info::walk () { char **ebp; if (first_time) @@ -300,44 +269,20 @@ stack_info::brute_force (HANDLE, HANDLE) return 1; } -/* Use Win32 StackWalk() API to display the stack. This is theoretically - more foolproof than the brute force method above. */ -int -stack_info::walk (HANDLE hproc, HANDLE hthread) -{ -#ifdef SOMEDAY - /* It would be nice to get more information (like DLL symbols and module name) - for each stack frame but in order to do that we have to call SymInitialize. - It doesn't seem to be possible to do this inside of an excaption handler for - some reason. */ - static int initialized = 0; - if (!initialized && !SymInitialize(hproc, NULL, TRUE)) - small_printf("SymInitialize error, %E\n"); - initialized = 1; -#endif - - return StackWalk (IMAGE_FILE_MACHINE_I386, hproc, hthread, &sf, NULL, NULL, - sfta, sgmb, NULL) && !!sf.AddrFrame.Offset; -} - /* Dump the stack using either the old method or the new Win32 API method */ void stack (HANDLE hproc, HANDLE hthread, CONTEXT *cx) { int i; - /* Set this up if it's the first time. */ - if (!thestack) - thestack = new stack_info (oldstack, hproc, hthread); - - thestack->init (cx); /* Initialize from the input CONTEXT */ + thestack.init (cx->Ebp); /* Initialize from the input CONTEXT */ small_printf ("Stack trace:\r\nFrame Function Args\r\n"); - for (i = 0; i < 16 && (*thestack)++ ; i++) + for (i = 0; i < 16 && thestack++ ; i++) { - small_printf ("%08x %08x ", thestack->sf.AddrFrame.Offset, - thestack->sf.AddrPC.Offset); + small_printf ("%08x %08x ", thestack.sf.AddrFrame.Offset, + thestack.sf.AddrPC.Offset); for (unsigned j = 0; j < NPARAMS; j++) - small_printf ("%s%08x", j == 0 ? " (" : ", ", thestack->sf.Params[j]); + small_printf ("%s%08x", j == 0 ? " (" : ", ", thestack.sf.Params[j]); small_printf (")\r\n"); } small_printf ("End of stack trace%s", @@ -551,18 +496,15 @@ handle_exceptions (EXCEPTION_RECORD *e, void *, CONTEXT *in, void *) debug_printf ("In cygwin_except_handler calling %p", myself->getsig(sig).sa_handler); - DWORD *bp = (DWORD *)in->Esp; - for (DWORD *bpend = bp - 8; bp > bpend; bp--) - if (*bp == in->SegCs && bp[-1] == in->Eip) + DWORD *ebp = (DWORD *)in->Esp; + for (DWORD *bpend = ebp - 8; ebp > bpend; ebp--) + if (*ebp == in->SegCs && ebp[-1] == in->Eip) { - bp -= 2; + ebp -= 2; break; } - in->Ebp = (DWORD) bp; - sigsave.cx = in; - sig_send (NULL, sig); // Signal myself - sigsave.cx = NULL; + sig_send (NULL, sig, (DWORD) ebp); // Signal myself return 0; } #endif /* __i386__ */ @@ -574,7 +516,6 @@ stack (void) system_printf ("Stack trace not yet supported on this machine."); } #endif -} /* Utilities to call a user supplied exception handler. */ @@ -659,6 +600,7 @@ interrupt_setup (int sig, struct sigaction& siga, void *handler, DWORD retaddr) sigsave.func = (void (*)(int)) handler; sigsave.sig = sig; sigsave.saved_errno = -1; // Flag: no errno to save + sigsave.ebp = 0; } static void @@ -670,24 +612,19 @@ interrupt_now (CONTEXT *ctx, int sig, struct sigaction& siga, void *handler) } static int -interrupt_on_return (CONTEXT *ctx, int sig, struct sigaction& siga, void *handler) +interrupt_on_return (DWORD ebp, int sig, struct sigaction& siga, void *handler) { int i; if (sigsave.sig) return 0; /* Already have a signal stacked up */ - /* Set this up if it's the first time. */ - /* FIXME: Eventually augment to handle more than one thread */ - if (!thestack) - thestack = new stack_info (oldstack, hMainProc, hMainThread); - - thestack->init (ctx); /* Initialize from the input CONTEXT */ - for (i = 0; i < 32 && (*thestack)++ ; i++) - if (interruptible (thestack->sf.AddrReturn.Offset)) + thestack.init (ebp); /* Initialize from the input CONTEXT */ + for (i = 0; i < 32 && thestack++ ; i++) + if (interruptible (thestack.sf.AddrReturn.Offset)) { - DWORD *addr_retaddr = ((DWORD *)thestack->sf.AddrFrame.Offset) + 1; - if (*addr_retaddr == thestack->sf.AddrReturn.Offset) + DWORD *addr_retaddr = ((DWORD *)thestack.sf.AddrFrame.Offset) + 1; + if (*addr_retaddr == thestack.sf.AddrReturn.Offset) { interrupt_setup (sig, siga, handler, *addr_retaddr); *addr_retaddr = (DWORD) sigdelayed; @@ -707,11 +644,12 @@ set_sig_errno (int e) } static int -call_handler (int sig, struct sigaction& siga, void *handler) +call_handler (int sig, struct sigaction& siga, void *handler, int nonmain) { - CONTEXT *cx, orig; + CONTEXT cx; + DWORD ebp; int interrupted = 1; - HANDLE hth; + HANDLE hth = NULL; int res; if (hExeced != NULL && hExeced != INVALID_HANDLE_VALUE) @@ -721,56 +659,52 @@ call_handler (int sig, struct sigaction& siga, void *handler) exec_exit = sig; // Maybe we'll exit with this value goto out1; } - hth = myself->getthread2signal (); - /* Suspend the thread which will receive the signal. But first ensure that - this thread doesn't have the sync_proc_subproc and mask_sync mutos, since - we need those (hack alert). If the thread-to-be-suspended has either of - these mutos, enter a busy loop until it is released. If the thread is - already suspended (which should never occur) then just queue the signal. */ - for (;;) - { - sigproc_printf ("suspending mainthread"); - res = SuspendThread (hth); - - /* FIXME: Make multi-thread aware */ - for (muto *m = muto_start.next; m != NULL; m = m->next) - if (m->unstable () || m->owner () == maintid) - goto keep_looping; - - break; - - keep_looping: - sigproc_printf ("suspended thread owns a muto"); - if (res) - goto set_pending; - - ResumeThread (hth); - Sleep (0); - } - - sigproc_printf ("SuspendThread returned %d", res); - - if (sigsave.cx) - { - cx = sigsave.cx; - sigsave.cx = NULL; - } + if (!nonmain) + ebp = sigsave.ebp; else { - cx = &orig; - /* FIXME - this does not preserve FPU state */ - orig.ContextFlags = CONTEXT_CONTROL | CONTEXT_INTEGER; - if (!GetThreadContext (hth, cx)) + hth = myself->getthread2signal (); + /* Suspend the thread which will receive the signal. But first ensure that + this thread doesn't have the sync_proc_subproc and mask_sync mutos, since + we need those (hack alert). If the thread-to-be-suspended has either of + these mutos, enter a busy loop until it is released. If the thread is + already suspended (which should never occur) then just queue the signal. */ + for (;;) + { + sigproc_printf ("suspending mainthread"); + res = SuspendThread (hth); + + /* FIXME: Make multi-thread aware */ + for (muto *m = muto_start.next; m != NULL; m = m->next) + if (m->unstable () || m->owner () == maintid) + goto keep_looping; + + break; + + keep_looping: + sigproc_printf ("suspended thread owns a muto"); + if (res) + goto set_pending; + + ResumeThread (hth); + Sleep (0); + } + + sigproc_printf ("SuspendThread returned %d", res); + + cx.ContextFlags = CONTEXT_CONTROL | CONTEXT_INTEGER; + if (!GetThreadContext (hth, &cx)) { system_printf ("couldn't get context of main thread, %E"); goto out; } + ebp = cx.Ebp; } - if (cx == &orig && interruptible (cx->Eip)) - interrupt_now (cx, sig, siga, handler); - else if (!interrupt_on_return (cx, sig, siga, handler)) + if (nonmain && interruptible (cx.Eip)) + interrupt_now (&cx, sig, siga, handler); + else if (!interrupt_on_return (ebp, sig, siga, handler)) { set_pending: pending_signals = 1; /* FIXME: Probably need to be more tricky here */ @@ -780,15 +714,20 @@ call_handler (int sig, struct sigaction& siga, void *handler) if (interrupted) { - (void) SetEvent (signal_arrived); // For an EINTR case + res = SetEvent (signal_arrived); // For an EINTR case sigproc_printf ("armed signal_arrived %p, res %d", signal_arrived, res); /* Clear any waiting threads prior to dispatching to handler function */ proc_subproc(PROC_CLEARWAIT, 1); } out: - res = ResumeThread (hth); - sigproc_printf ("ResumeThread returned %d", res); + if (!hth) + sigproc_printf ("modified main-thread stack"); + else + { + res = ResumeThread (hth); + sigproc_printf ("ResumeThread returned %d", res); + } out1: sigproc_printf ("returning %d", interrupted); @@ -892,7 +831,7 @@ sig_handle_tty_stop (int sig) } int __stdcall -sig_handle (int sig) +sig_handle (int sig, int nonmain) { int rc = 0; @@ -971,7 +910,7 @@ stop: dosig: /* Dispatch to the appropriate function. */ sigproc_printf ("signal %d, about to call %p", sig, thissig.sa_handler); - rc = call_handler (sig, thissig, handler); + rc = call_handler (sig, thissig, handler, nonmain); done: sigproc_printf ("returning %d", rc); diff --git a/winsup/cygwin/fhandler_tty.cc b/winsup/cygwin/fhandler_tty.cc index 0e6a6edc1..3261ea2ce 100644 --- a/winsup/cygwin/fhandler_tty.cc +++ b/winsup/cygwin/fhandler_tty.cc @@ -110,7 +110,10 @@ fhandler_tty_common::__acquire_output_mutex (const char *fn, int ln, DWORD res = WaitForSingleObject (output_mutex, ms); if (res == WAIT_OBJECT_0) { -#ifdef DEBUGGING +#ifndef DEBUGGING + if (strace.active) + strace.prntf (_STRACE_TERMIOS, "%F (%d): tty output_mutex: acquired", fn, ln, res); +#else ostack[osi].fn = fn; ostack[osi].ln = ln; ostack[osi].tname = threadname (0, 0); @@ -118,8 +121,6 @@ fhandler_tty_common::__acquire_output_mutex (const char *fn, int ln, osi++; #endif } - if (strace.active) - strace.prntf (_STRACE_TERMIOS, "%F (%d): tty output_mutex: acquired", fn, ln, res); return res; } @@ -128,7 +129,10 @@ fhandler_tty_common::__release_output_mutex (const char *fn, int ln) { if (ReleaseMutex (output_mutex)) { -#ifdef DEBUGGING +#ifndef DEBUGGING + if (strace.active) + strace.prntf (_STRACE_TERMIOS, "%F (%d): tty output_mutex released", fn, ln); +#else if (osi > 0) osi--; termios_printf ("released at %s:%d, osi %d", fn, ln, osi); @@ -136,8 +140,6 @@ fhandler_tty_common::__release_output_mutex (const char *fn, int ln) ostack[osi].ln = -ln; #endif } - if (strace.active) - strace.prntf (_STRACE_TERMIOS, "%F (%d): tty output_mutex released", fn, ln); } #define acquire_output_mutex(ms) \ @@ -288,7 +290,10 @@ again: } if (get_ttyp ()->OutputStopped) - WaitForSingleObject (restart_output_event, INFINITE); + { + termios_printf ("waiting for restart_output_event"); + WaitForSingleObject (restart_output_event, INFINITE); + } if (get_ttyp ()->ti.c_oflag & OPOST) // post-process output { @@ -575,7 +580,6 @@ fhandler_tty_slave::read (void *ptr, size_t len) while (len) { - wait: termios_printf ("reading %d bytes (vtime %d)", min ((unsigned) vmin, min (len, sizeof (buf))), vtime); if (ReadFile (get_handle (), (unsigned *) buf, @@ -614,7 +618,7 @@ fhandler_tty_slave::read (void *ptr, size_t len) if (get_flags () & (O_NONBLOCK | O_NDELAY)) break; - /* We can't enter to blocking Readfile - signals will be lost! + /* We can't enter the blocking Readfile as signals will be lost. * So, poll the pipe for data. * FIXME: try to avoid polling... * FIXME: Current EINTR scheme does not take vmin/vtime into account. @@ -625,7 +629,7 @@ fhandler_tty_slave::read (void *ptr, size_t len) if (vmin == 0 && vtime == 0) return 0; // min = 0, time = 0 if (vtime == 0) - goto wait; // min > 0, time = 0 + continue; // min > 0, time = 0 while (vtime--) { PeekNamedPipe (get_handle (), NULL, 0, NULL, &n, NULL); diff --git a/winsup/cygwin/sigproc.cc b/winsup/cygwin/sigproc.cc index 28db48d8d..2a8826a6f 100644 --- a/winsup/cygwin/sigproc.cc +++ b/winsup/cygwin/sigproc.cc @@ -708,7 +708,7 @@ sigproc_terminate (void) * completed before returning. */ int __stdcall -sig_send (pinfo *p, int sig) +sig_send (pinfo *p, int sig, DWORD ebp) { int rc = 1; DWORD tid = GetCurrentThreadId (); @@ -716,6 +716,7 @@ sig_send (pinfo *p, int sig) HANDLE thiscatch = NULL; HANDLE thiscomplete = NULL; BOOL wait_for_completion; + extern signal_dispatch sigsave; if (p == myself_nowait_nonmain) p = (tid == maintid) ? myself : myself_nowait; @@ -756,7 +757,7 @@ sig_send (pinfo *p, int sig) { thiscatch = sigcatch_main; thiscomplete = sigcomplete_main; - ResetEvent (thiscomplete); + sigsave.ebp = ebp ?: (DWORD) __builtin_frame_address (1); } } else if (!(thiscatch = getsem (p, "sigcatch", 0, 0))) @@ -1158,7 +1159,7 @@ wait_sig (VOID *) sigcatch_nonmain = CreateSemaphore (&sec_none_nih, 0, MAXLONG, NULL); sigcatch_main = CreateSemaphore (&sec_none_nih, 0, MAXLONG, NULL); sigcomplete_nonmain = CreateSemaphore (&sec_none_nih, 0, MAXLONG, NULL); - sigcomplete_main = CreateEvent (&sec_none_nih, TRUE, FALSE, NULL); + sigcomplete_main = CreateEvent (&sec_none_nih, FALSE, FALSE, NULL); sigproc_printf ("sigcatch_nonmain %p", sigcatch_nonmain); /* Setting dwProcessId flags that this process is now capable of receiving @@ -1231,11 +1232,7 @@ wait_sig (VOID *) int dispatched_sigchld = 0; for (int sig = -__SIGOFFSET; sig < NSIG; sig++) { -#ifdef NOSIGQUEUE - if (InterlockedExchange (myself->getsigtodo(sig), 0L) > 0) -#else while (InterlockedDecrement (myself->getsigtodo(sig)) >= 0) -#endif { if (sig == SIGCHLD) saw_sigchld = 1; @@ -1263,7 +1260,7 @@ wait_sig (VOID *) /* Signalled from a child process that it has stopped */ case __SIGCHILDSTOPPED: sip_printf ("Received child stopped notification"); - dispatched |= sig_handle (SIGCHLD); + dispatched |= sig_handle (SIGCHLD, rc); if (proc_subproc (PROC_CHILDSTOPPED, 0)) dispatched |= 1; break; @@ -1271,18 +1268,16 @@ wait_sig (VOID *) /* A normal UNIX signal */ default: sip_printf ("Got signal %d", sig); - int wasdispatched = sig_handle (sig); + int wasdispatched = sig_handle (sig, rc); dispatched |= wasdispatched; if (sig == SIGCHLD && wasdispatched) dispatched_sigchld = 1; goto nextsig; } } -#ifndef NOSIGQUEUE /* Decremented too far. */ if (InterlockedIncrement (myself->getsigtodo(sig)) > 0) pending_signals = 1; -#endif nextsig: continue; } diff --git a/winsup/cygwin/sigproc.h b/winsup/cygwin/sigproc.h index b1b4eafc0..342e3f5ae 100644 --- a/winsup/cygwin/sigproc.h +++ b/winsup/cygwin/sigproc.h @@ -37,7 +37,7 @@ extern HANDLE signal_arrived; BOOL __stdcall my_parent_is_alive (); extern "C" int __stdcall sig_dispatch_pending (int force = FALSE) __asm__ ("sig_dispatch_pending"); extern "C" void __stdcall set_process_mask (sigset_t newmask); -int __stdcall sig_handle (int); +int __stdcall sig_handle (int, int); void __stdcall sig_clear (int); void __stdcall sig_set_pending (int); int __stdcall handle_sigsuspend (sigset_t); @@ -48,7 +48,7 @@ void __stdcall subproc_init (); void __stdcall sigproc_terminate (); BOOL __stdcall proc_exists (pinfo *); int __stdcall proc_subproc (DWORD, DWORD); -int __stdcall sig_send (pinfo *, int); +int __stdcall sig_send (pinfo *, int, DWORD ebp = 0); extern char myself_nowait_dummy[]; extern char myself_nowait_nonmain_dummy[]; diff --git a/winsup/cygwin/syscalls.cc b/winsup/cygwin/syscalls.cc index b958a0619..9b03f5863 100644 --- a/winsup/cygwin/syscalls.cc +++ b/winsup/cygwin/syscalls.cc @@ -1841,21 +1841,6 @@ ffs (int i) return table[x >> a] + a; } -extern "C" -void -swab (const void *src, void *dst, ssize_t n) -{ - const char *from = (const char *) src; - char *to = (char *) dst; - - while (n > 1) - { - const char b0 = from[--n], b1 = from[--n]; - to[n] = b0; - to[n + 1] = b1; - } -} - extern "C" void login (struct utmp *ut) diff --git a/winsup/cygwin/winsup.h b/winsup/cygwin/winsup.h index a59d19230..a1b287e6e 100644 --- a/winsup/cygwin/winsup.h +++ b/winsup/cygwin/winsup.h @@ -307,7 +307,7 @@ struct signal_dispatch void (*func) (int); int sig; int saved_errno; - CONTEXT *cx; + DWORD ebp; DWORD oldmask; DWORD retaddr; };