X-Git-Url: http://git.megacz.com/?a=blobdiff_plain;f=ghc%2Frts%2Fwin32%2FConsoleHandler.c;h=413e13cc277f18d62552ee4103e5185bd40c4e21;hb=86f2671b37507012692a53c2fe45357b0988cb40;hp=a6a53a0e255ad07421c6c498e38eccefa2165e31;hpb=c7fd6356eb1ccab4b92fa548d52023cc221fa7c0;p=ghc-hetmet.git diff --git a/ghc/rts/win32/ConsoleHandler.c b/ghc/rts/win32/ConsoleHandler.c index a6a53a0..413e13c 100644 --- a/ghc/rts/win32/ConsoleHandler.c +++ b/ghc/rts/win32/ConsoleHandler.c @@ -10,6 +10,7 @@ #include "RtsUtils.h" #include "RtsFlags.h" #include "AsyncIO.h" +#include "RtsSignals.h" extern int stg_InstallConsoleEvent(int action, StgStablePtr *handler); @@ -19,6 +20,8 @@ static BOOL WINAPI generic_handler(DWORD dwCtrlType); static rtsBool deliver_event = rtsTrue; static StgInt console_handler = STG_SIG_DFL; +static HANDLE hConsoleEvent = INVALID_HANDLE_VALUE; + #define N_PENDING_EVENTS 16 StgInt stg_pending_events = 0; /* number of undelivered events */ DWORD stg_pending_buf[N_PENDING_EVENTS]; /* their associated event numbers. */ @@ -33,6 +36,13 @@ initUserSignals(void) { stg_pending_events = 0; console_handler = STG_SIG_DFL; + if (hConsoleEvent == INVALID_HANDLE_VALUE) { + hConsoleEvent = + CreateEvent ( NULL, /* default security attributes */ + TRUE, /* manual-reset event */ + FALSE, /* initially non-signalled */ + NULL); /* no name */ + } return; } @@ -60,7 +70,7 @@ static BOOL WINAPI shutdown_handler(DWORD dwCtrlType) // If we're already trying to interrupt the RTS, terminate with // extreme prejudice. So the first ^C tries to exit the program // cleanly, and the second one just kills it. - if (interrupted) { + if (sched_state >= SCHED_INTERRUPTING) { stg_exit(EXIT_INTERRUPTED); } else { interruptStgRts(); @@ -135,27 +145,33 @@ void awaitUserSignals(void) * Run the handlers associated with the stacked up console events. Console * event delivery is blocked for the duration of this call. */ -void startSignalHandlers(void) +void startSignalHandlers(Capability *cap) { StgStablePtr handler; if (console_handler < 0) { return; } + blockUserSignals(); + ACQUIRE_LOCK(&sched_mutex); handler = deRefStablePtr((StgStablePtr)console_handler); while (stg_pending_events > 0) { stg_pending_events--; - scheduleThread( - createIOThread(RtsFlags.GcFlags.initialStkSize, - rts_apply((StgClosure *)handler, - rts_mkInt(stg_pending_buf[stg_pending_events])))); + scheduleThread(cap, + createIOThread(cap, + RtsFlags.GcFlags.initialStkSize, + rts_apply(cap, + (StgClosure *)handler, + rts_mkInt(cap, + stg_pending_buf[stg_pending_events])))); } + + RELEASE_LOCK(&sched_mutex); unblockUserSignals(); } - /* * Function: markSignalHandlers() * @@ -171,17 +187,6 @@ void markSignalHandlers (evac_fn evac) } -/* - * Function: handleSignalsInThisThread() - * - * Have current (OS) thread assume responsibility of handling console events/signals. - * Currently not used (by the console event handling code.) - */ -void handleSignalsInThisThread(void) -{ - return; -} - /* * Function: generic_handler() * @@ -190,6 +195,8 @@ void handleSignalsInThisThread(void) */ static BOOL WINAPI generic_handler(DWORD dwCtrlType) { + ACQUIRE_LOCK(&sched_mutex); + /* Ultra-simple -- up the counter + signal a switch. */ switch(dwCtrlType) { case CTRL_CLOSE_EVENT: @@ -212,16 +219,18 @@ static BOOL WINAPI generic_handler(DWORD dwCtrlType) resetAbandonRequestWait(); return TRUE; } + + RELEASE_LOCK(&sched_mutex); } /* - * Function: stg_InstallConsoleEvent() + * Function: rts_InstallConsoleEvent() * * Install/remove a console event handler. */ int -stg_InstallConsoleEvent(int action, StgStablePtr *handler) +rts_InstallConsoleEvent(int action, StgStablePtr *handler) { StgInt previous_hdlr = console_handler; @@ -257,3 +266,48 @@ stg_InstallConsoleEvent(int action, StgStablePtr *handler) return STG_SIG_HAN; } } + +/* + * Function: rts_HandledConsoleEvent() + * + * Signal that a Haskell console event handler has completed its run. + * The explicit notification that a Haskell handler has completed is + * required to better handle the delivery of Ctrl-C/Break events whilst + * an async worker thread is handling a read request on stdin. The + * Win32 console implementation will abort such a read request when Ctrl-C + * is delivered. That leaves the worker thread in a bind: should it + * abandon the request (the Haskell thread reading from stdin has been + * thrown an exception to signal the delivery of Ctrl-C & hence have + * aborted the I/O request) or simply ignore the aborted read and retry? + * (the Haskell thread reading from stdin isn't concerned with the + * delivery and handling of Ctrl-C.) With both scenarios being + * possible, the worker thread needs to be told -- that is, did the + * console event handler cause the IO request to be abandoned? + * + */ +void +rts_ConsoleHandlerDone(int ev) +{ + if ( (DWORD)ev == CTRL_BREAK_EVENT || + (DWORD)ev == CTRL_C_EVENT ) { + /* only these two cause stdin system calls to abort.. */ + SetEvent(hConsoleEvent); /* event is manual-reset */ + Sleep(0); /* yield */ + ResetEvent(hConsoleEvent); /* turn it back off again */ + } +} + +/* + * Function: rts_waitConsoleHandlerCompletion() + * + * Esoteric entry point used by worker thread that got woken + * up as part Ctrl-C delivery. + */ +int +rts_waitConsoleHandlerCompletion() +{ + /* As long as the worker doesn't need to do a multiple wait, + * let's keep this HANDLE private to this 'module'. + */ + return (WaitForSingleObject(hConsoleEvent, INFINITE) == WAIT_OBJECT_0); +}