windows: Better handling of Ctrl-C

This builds upon the changes made in 2195046365. 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.
pull/1737/merge
stijn 2015-12-21 10:17:37 +01:00 zatwierdzone przez Paul Sokolovsky
rodzic 1b7f622410
commit a5aa03acaf
2 zmienionych plików z 19 dodań i 5 usunięć

Wyświetl plik

@ -26,9 +26,13 @@
#include <stdlib.h>
#include <stdio.h>
#include <windows.h>
#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();
}

Wyświetl plik

@ -30,7 +30,6 @@
#include <windows.h>
#include <unistd.h>
#include <signal.h>
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);
}
}