2 * Console control handler support.
7 #include "ConsoleHandler.h"
14 extern int stg_InstallConsoleEvent(int action, StgStablePtr *handler);
16 static BOOL WINAPI shutdown_handler(DWORD dwCtrlType);
17 static BOOL WINAPI generic_handler(DWORD dwCtrlType);
19 static rtsBool deliver_event = rtsTrue;
20 static StgInt console_handler = STG_SIG_DFL;
22 #define N_PENDING_EVENTS 16
23 StgInt stg_pending_events = 0; /* number of undelivered events */
24 DWORD stg_pending_buf[N_PENDING_EVENTS]; /* their associated event numbers. */
27 * Function: initUserSignals()
29 * Initialize the console handling substrate.
34 stg_pending_events = 0;
35 console_handler = STG_SIG_DFL;
40 * Function: shutdown_handler()
42 * Local function that performs the default handling of Ctrl+C kind
43 * events; gently shutting down the RTS
45 * To repeat Signals.c remark -- user code may choose to override the
46 * default handler. Which is fine, assuming they put back the default
47 * handler when/if they de-install the custom handler.
50 static BOOL WINAPI shutdown_handler(DWORD dwCtrlType)
54 case CTRL_CLOSE_EVENT:
55 /* see generic_handler() comment re: this event */
58 case CTRL_BREAK_EVENT:
60 // If we're already trying to interrupt the RTS, terminate with
61 // extreme prejudice. So the first ^C tries to exit the program
62 // cleanly, and the second one just kills it.
64 stg_exit(EXIT_INTERRUPTED);
67 /* Cheesy pulsing of an event to wake up a waiting RTS thread, if any */
69 resetAbandonRequestWait();
73 /* shutdown + logoff events are not handled here. */
81 * Function: initDefaultHandlers()
83 * Install any default signal/console handlers. Currently we install a
84 * Ctrl+C handler that shuts down the RTS in an orderly manner.
86 void initDefaultHandlers(void)
88 if ( !SetConsoleCtrlHandler(shutdown_handler, TRUE) ) {
89 errorBelch("warning: failed to install default console handler");
95 * Function: blockUserSignals()
97 * Temporarily block the delivery of further console events. Needed to
98 * avoid race conditions when GCing the stack of outstanding handlers or
99 * when emptying the stack by running the handlers.
103 blockUserSignals(void)
105 deliver_event = rtsFalse;
110 * Function: unblockUserSignals()
112 * The inverse of blockUserSignals(); re-enable the deliver of console events.
115 unblockUserSignals(void)
117 deliver_event = rtsTrue;
122 * Function: awaitUserSignals()
124 * Wait for the next console event. Currently a NOP (returns immediately.)
126 void awaitUserSignals(void)
133 * Function: startSignalHandlers()
135 * Run the handlers associated with the stacked up console events. Console
136 * event delivery is blocked for the duration of this call.
138 void startSignalHandlers(void)
140 StgStablePtr handler;
142 if (console_handler < 0) {
147 handler = deRefStablePtr((StgStablePtr)console_handler);
148 while (stg_pending_events > 0) {
149 stg_pending_events--;
151 createIOThread(RtsFlags.GcFlags.initialStkSize,
152 rts_apply((StgClosure *)handler,
153 rts_mkInt(stg_pending_buf[stg_pending_events]))));
155 unblockUserSignals();
160 * Function: markSignalHandlers()
162 * Evacuate the handler stack. _Assumes_ that console event delivery
163 * has already been blocked.
165 void markSignalHandlers (evac_fn evac)
167 if (console_handler >= 0) {
168 StgPtr p = deRefStablePtr((StgStablePtr)console_handler);
169 evac((StgClosure**)&p);
175 * Function: handleSignalsInThisThread()
177 * Have current (OS) thread assume responsibility of handling console events/signals.
178 * Currently not used (by the console event handling code.)
180 void handleSignalsInThisThread(void)
186 * Function: generic_handler()
188 * Local function which handles incoming console event (done in a sep OS thread),
189 * recording the event in stg_pending_events.
191 static BOOL WINAPI generic_handler(DWORD dwCtrlType)
193 /* Ultra-simple -- up the counter + signal a switch. */
195 case CTRL_CLOSE_EVENT:
196 /* Don't support the delivery of this event; if we
197 * indicate that we've handled it here and the Haskell handler
198 * doesn't take proper action (e.g., terminate the OS process),
199 * the user of the app will be unable to kill/close it. Not
200 * good, so disable the delivery for now.
204 if (!deliver_event) return TRUE;
206 if ( stg_pending_events < N_PENDING_EVENTS ) {
207 stg_pending_buf[stg_pending_events] = dwCtrlType;
208 stg_pending_events++;
210 /* Cheesy pulsing of an event to wake up a waiting RTS thread, if any */
211 abandonRequestWait();
212 resetAbandonRequestWait();
219 * Function: stg_InstallConsoleEvent()
221 * Install/remove a console event handler.
224 stg_InstallConsoleEvent(int action, StgStablePtr *handler)
226 StgInt previous_hdlr = console_handler;
230 console_handler = STG_SIG_IGN;
231 if ( !SetConsoleCtrlHandler(NULL, TRUE) ) {
232 errorBelch("warning: unable to ignore console events");
236 console_handler = STG_SIG_IGN;
237 if ( !SetConsoleCtrlHandler(NULL, FALSE) ) {
238 errorBelch("warning: unable to restore default console event handling");
242 console_handler = (StgInt)*handler;
243 if ( previous_hdlr < 0 ) {
244 /* Only install generic_handler() once */
245 if ( !SetConsoleCtrlHandler(generic_handler, TRUE) ) {
246 errorBelch("warning: unable to install console event handler");
252 if (previous_hdlr == STG_SIG_DFL ||
253 previous_hdlr == STG_SIG_IGN) {
254 return previous_hdlr;
256 *handler = (StgStablePtr)previous_hdlr;