2 * Console control handler support.
7 #include "ConsoleHandler.h"
13 extern int stg_InstallConsoleEvent(int action, StgStablePtr *handler);
15 static BOOL WINAPI shutdown_handler(DWORD dwCtrlType);
16 static BOOL WINAPI generic_handler(DWORD dwCtrlType);
18 static rtsBool deliver_event = rtsTrue;
19 static StgInt console_handler = STG_SIG_DFL;
21 #define N_PENDING_EVENTS 16
22 StgInt stg_pending_events = 0; /* number of undelivered events */
23 DWORD stg_pending_buf[N_PENDING_EVENTS]; /* their associated event numbers. */
26 * Function: initUserSignals()
28 * Initialize the console handling substrate.
33 stg_pending_events = 0;
34 console_handler = STG_SIG_DFL;
39 * Function: shutdown_handler()
41 * Local function that performs the default handling of Ctrl+C kind
42 * events; gently shutting down the RTS
44 * To repeat Signals.c remark -- user code may choose to override the
45 * default handler. Which is fine, assuming they put back the default
46 * handler when/if they de-install the custom handler.
49 static BOOL WINAPI shutdown_handler(DWORD dwCtrlType)
54 case CTRL_BREAK_EVENT:
55 case CTRL_CLOSE_EVENT:
57 // If we're already trying to interrupt the RTS, terminate with
58 // extreme prejudice. So the first ^C tries to exit the program
59 // cleanly, and the second one just kills it.
61 stg_exit(EXIT_INTERRUPTED);
67 /* shutdown + logoff events are not handled here. */
75 * Function: initDefaultHandlers()
77 * Install any default signal/console handlers. Currently we install a
78 * Ctrl+C handler that shuts down the RTS in an orderly manner.
80 void initDefaultHandlers(void)
82 if ( !SetConsoleCtrlHandler(shutdown_handler, TRUE) ) {
83 errorBelch("warning: failed to install default console handler");
89 * Function: blockUserSignals()
91 * Temporarily block the delivery of further console events. Needed to
92 * avoid race conditions when GCing the stack of outstanding handlers or
93 * when emptying the stack by running the handlers.
97 blockUserSignals(void)
99 deliver_event = rtsFalse;
104 * Function: unblockUserSignals()
106 * The inverse of blockUserSignals(); re-enable the deliver of console events.
109 unblockUserSignals(void)
111 deliver_event = rtsTrue;
116 * Function: awaitUserSignals()
118 * Wait for the next console event. Currently a NOP (returns immediately.)
120 void awaitUserSignals(void)
127 * Function: startSignalHandlers()
129 * Run the handlers associated with the stacked up console events. Console
130 * event delivery is blocked for the duration of this call.
132 void startSignalHandlers(void)
134 StgStablePtr handler;
136 if (console_handler < 0) {
141 handler = deRefStablePtr((StgStablePtr)console_handler);
142 while (stg_pending_events > 0) {
143 stg_pending_events--;
145 createIOThread(RtsFlags.GcFlags.initialStkSize,
146 rts_apply((StgClosure *)handler,
147 rts_mkInt(stg_pending_buf[stg_pending_events]))));
149 unblockUserSignals();
154 * Function: markSignalHandlers()
156 * Evacuate the handler stack. _Assumes_ that console event delivery
157 * has already been blocked.
159 void markSignalHandlers (evac_fn evac)
161 if (console_handler >= 0) {
162 StgPtr p = deRefStablePtr((StgStablePtr)console_handler);
163 evac((StgClosure**)&p);
169 * Function: handleSignalsInThisThread()
171 * Have current (OS) thread assume responsibility of handling console events/signals.
172 * Currently not used (by the console event handling code.)
174 void handleSignalsInThisThread(void)
180 * Function: generic_handler()
182 * Local function which handles incoming console event (done in a sep OS thread),
183 * recording the event in stg_pending_events.
185 static BOOL WINAPI generic_handler(DWORD dwCtrlType)
187 /* Ultra-simple -- up the counter + signal a switch. */
188 if ( stg_pending_events < N_PENDING_EVENTS ) {
189 stg_pending_buf[stg_pending_events] = dwCtrlType;
190 stg_pending_events++;
198 * Function: stg_InstallConsoleEvent()
200 * Install/remove a console event handler.
203 stg_InstallConsoleEvent(int action, StgStablePtr *handler)
205 StgInt previous_hdlr = console_handler;
209 console_handler = STG_SIG_IGN;
210 if ( !SetConsoleCtrlHandler(NULL, TRUE) ) {
211 errorBelch("warning: unable to ignore console events");
215 console_handler = STG_SIG_IGN;
216 if ( !SetConsoleCtrlHandler(NULL, FALSE) ) {
217 errorBelch("warning: unable to restore default console event handling");
221 console_handler = (StgInt)*handler;
222 if ( previous_hdlr < 0 ) {
223 /* Only install generic_handler() once */
224 if ( !SetConsoleCtrlHandler(generic_handler, TRUE) ) {
225 errorBelch("warning: unable to install console event handler");
231 if (previous_hdlr == STG_SIG_DFL ||
232 previous_hdlr == STG_SIG_IGN) {
233 return previous_hdlr;
235 *handler = (StgStablePtr)previous_hdlr;