From a5aa03acaff46aaaac0d0c3462cbd968b0a1df59 Mon Sep 17 00:00:00 2001 From: stijn Date: Mon, 21 Dec 2015 10:17:37 +0100 Subject: [PATCH] windows: Better handling of Ctrl-C This builds upon the changes made in 2195046365c. Using signal() does not produce reliable results so SetConsoleCtrlHandler is used, and the handler is installed only once during initialization instead of removing it in mp_hal_set_interrupt_char when it is not strictly needed anymore, since removing it might lead to Ctrl-C events being missed because they are fired on a seperate thread which might only become alive after the handler was removed. --- windows/init.c | 5 +++++ windows/windows_mphal.c | 19 ++++++++++++++----- 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/windows/init.c b/windows/init.c index 5e96af046e..d4533f9b47 100644 --- a/windows/init.c +++ b/windows/init.c @@ -26,9 +26,13 @@ #include #include +#include #include "sleep.h" +extern BOOL WINAPI console_sighandler(DWORD evt); + void init() { + SetConsoleCtrlHandler(console_sighandler, TRUE); init_sleep(); #ifdef __MINGW32__ putenv("PRINTF_EXPONENT_DIGITS=2"); @@ -40,5 +44,6 @@ void init() { } void deinit() { + SetConsoleCtrlHandler(console_sighandler, FALSE); deinit_sleep(); } diff --git a/windows/windows_mphal.c b/windows/windows_mphal.c index 91025d6cf4..6cc4f65428 100644 --- a/windows/windows_mphal.c +++ b/windows/windows_mphal.c @@ -30,7 +30,6 @@ #include #include -#include HANDLE std_in = NULL; HANDLE con_out = NULL; @@ -67,15 +66,27 @@ void mp_hal_stdio_mode_orig(void) { SetConsoleMode(std_in, orig_mode); } -STATIC void sighandler(int signum) { - if (signum == SIGINT) { +// Handler to be installed by SetConsoleCtrlHandler, currently used only to handle Ctrl-C. +// This handler has to be installed just once (this has to be done elswhere in init code). +// Previous versions of the mp_hal code would install a handler whenever Ctrl-C input is +// allowed and remove the handler again when it is not. That is not necessary though (1), +// and it might introduce problems (2) because console notifications are delivered to the +// application in a seperate thread. +// (1) mp_hal_set_interrupt_char effectively enables/disables processing of Ctrl-C via the +// ENABLE_PROCESSED_INPUT flag so in raw mode console_sighandler won't be called. +// (2) if mp_hal_set_interrupt_char would remove the handler while Ctrl-C was issued earlier, +// the thread created for handling it might not be running yet so we'd miss the notification. +BOOL WINAPI console_sighandler(DWORD evt) { + if (evt == CTRL_C_EVENT) { if (MP_STATE_VM(mp_pending_exception) == MP_STATE_VM(keyboard_interrupt_obj)) { // this is the second time we are called, so die straight away exit(1); } mp_obj_exception_clear_traceback(MP_STATE_VM(keyboard_interrupt_obj)); MP_STATE_VM(mp_pending_exception) = MP_STATE_VM(keyboard_interrupt_obj); + return TRUE; } + return FALSE; } void mp_hal_set_interrupt_char(char c) { @@ -85,13 +96,11 @@ void mp_hal_set_interrupt_char(char c) { GetConsoleMode(std_in, &mode); mode |= ENABLE_PROCESSED_INPUT; SetConsoleMode(std_in, mode); - signal(SIGINT, sighandler); } else { DWORD mode; GetConsoleMode(std_in, &mode); mode &= ~ENABLE_PROCESSED_INPUT; SetConsoleMode(std_in, mode); - signal(SIGINT, SIG_DFL); } }