{
switch (dwCtrlType) {
+ case CTRL_CLOSE_EVENT:
+ /* see generic_handler() comment re: this event */
+ return FALSE;
case CTRL_C_EVENT:
case CTRL_BREAK_EVENT:
- case CTRL_CLOSE_EVENT:
// If we're already trying to interrupt the RTS, terminate with
// extreme prejudice. So the first ^C tries to exit the program
static BOOL WINAPI generic_handler(DWORD dwCtrlType)
{
/* Ultra-simple -- up the counter + signal a switch. */
- if ( stg_pending_events < N_PENDING_EVENTS ) {
- stg_pending_buf[stg_pending_events] = dwCtrlType;
- stg_pending_events++;
+ switch(dwCtrlType) {
+ case CTRL_CLOSE_EVENT:
+ /* Don't support the delivery of this event; if we
+ * indicate that we've handled it here and the Haskell handler
+ * doesn't take proper action (e.g., terminate the OS process),
+ * the user of the app will be unable to kill/close it. Not
+ * good, so disable the delivery for now.
+ */
+ return FALSE;
+ default:
+ if ( stg_pending_events < N_PENDING_EVENTS ) {
+ stg_pending_buf[stg_pending_events] = dwCtrlType;
+ stg_pending_events++;
+ }
+ context_switch = 1;
+ return TRUE;
}
- context_switch = 1;
- return TRUE;
}
WorkQueue* pq = iom->workQueue;
WorkItem* work;
int len = 0, fd = 0;
- DWORD errCode;
+ DWORD errCode = 0;
void* complData;
hWaits[0] = (HANDLE)iom->hExitEvent;
errCode = WSAGetLastError();
}
} else {
+ DWORD dw;
+
+ /* Do the read(), with extra-special handling for Ctrl+C */
len = read(work->workData.ioData.fd,
work->workData.ioData.buf,
work->workData.ioData.len);
+ if ( len == 0 && work->workData.ioData.len != 0 ) {
+ /* Given the following scenario:
+ * - a console handler has been registered that handles Ctrl+C
+ * events.
+ * - we've not tweaked the 'console mode' settings to turn on
+ * ENABLE_PROCESSED_INPUT.
+ * - we're blocked waiting on input from standard input.
+ * - the user hits Ctrl+C.
+ *
+ * The OS will invoke the console handler (in a separate OS thread),
+ * and the above read() (i.e., under the hood, a ReadFile() op) returns
+ * 0, with the error set to ERROR_OPERATION_ABORTED. We don't
+ * want to percolate this non-EOF condition too far back up, but ignore
+ * it. However, we do want to give the RTS an opportunity to deliver the
+ * console event.
+ *
+ * Hence, we set 'errorCode' to (-2), which we then look out for in
+ * GHC.Conc.asyncRead.
+ */
+ dw = GetLastError();
+ if ( dw == ERROR_OPERATION_ABORTED ) {
+ /* Only do the retry when dealing with the standard input handle. */
+ HANDLE h = (HANDLE)GetStdHandle(STD_INPUT_HANDLE);
+ if ( _get_osfhandle(work->workData.ioData.fd) == (long)h ) {
+ errCode = (DWORD)-2;
+ }
+ }
+ }
if (len == -1) { errCode = errno; }
}
complData = work->workData.ioData.buf;