Skip to content

Commit a5aa03a

Browse files
stinospfalcon
authored andcommitted
windows: Better handling of Ctrl-C
This builds upon the changes made in 2195046. 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.
1 parent 1b7f622 commit a5aa03a

File tree

2 files changed

+19
-5
lines changed

2 files changed

+19
-5
lines changed

windows/init.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,13 @@
2626

2727
#include <stdlib.h>
2828
#include <stdio.h>
29+
#include <windows.h>
2930
#include "sleep.h"
3031

32+
extern BOOL WINAPI console_sighandler(DWORD evt);
33+
3134
void init() {
35+
SetConsoleCtrlHandler(console_sighandler, TRUE);
3236
init_sleep();
3337
#ifdef __MINGW32__
3438
putenv("PRINTF_EXPONENT_DIGITS=2");
@@ -40,5 +44,6 @@ void init() {
4044
}
4145

4246
void deinit() {
47+
SetConsoleCtrlHandler(console_sighandler, FALSE);
4348
deinit_sleep();
4449
}

windows/windows_mphal.c

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@
3030

3131
#include <windows.h>
3232
#include <unistd.h>
33-
#include <signal.h>
3433

3534
HANDLE std_in = NULL;
3635
HANDLE con_out = NULL;
@@ -67,15 +66,27 @@ void mp_hal_stdio_mode_orig(void) {
6766
SetConsoleMode(std_in, orig_mode);
6867
}
6968

70-
STATIC void sighandler(int signum) {
71-
if (signum == SIGINT) {
69+
// Handler to be installed by SetConsoleCtrlHandler, currently used only to handle Ctrl-C.
70+
// This handler has to be installed just once (this has to be done elswhere in init code).
71+
// Previous versions of the mp_hal code would install a handler whenever Ctrl-C input is
72+
// allowed and remove the handler again when it is not. That is not necessary though (1),
73+
// and it might introduce problems (2) because console notifications are delivered to the
74+
// application in a seperate thread.
75+
// (1) mp_hal_set_interrupt_char effectively enables/disables processing of Ctrl-C via the
76+
// ENABLE_PROCESSED_INPUT flag so in raw mode console_sighandler won't be called.
77+
// (2) if mp_hal_set_interrupt_char would remove the handler while Ctrl-C was issued earlier,
78+
// the thread created for handling it might not be running yet so we'd miss the notification.
79+
BOOL WINAPI console_sighandler(DWORD evt) {
80+
if (evt == CTRL_C_EVENT) {
7281
if (MP_STATE_VM(mp_pending_exception) == MP_STATE_VM(keyboard_interrupt_obj)) {
7382
// this is the second time we are called, so die straight away
7483
exit(1);
7584
}
7685
mp_obj_exception_clear_traceback(MP_STATE_VM(keyboard_interrupt_obj));
7786
MP_STATE_VM(mp_pending_exception) = MP_STATE_VM(keyboard_interrupt_obj);
87+
return TRUE;
7888
}
89+
return FALSE;
7990
}
8091

8192
void mp_hal_set_interrupt_char(char c) {
@@ -85,13 +96,11 @@ void mp_hal_set_interrupt_char(char c) {
8596
GetConsoleMode(std_in, &mode);
8697
mode |= ENABLE_PROCESSED_INPUT;
8798
SetConsoleMode(std_in, mode);
88-
signal(SIGINT, sighandler);
8999
} else {
90100
DWORD mode;
91101
GetConsoleMode(std_in, &mode);
92102
mode &= ~ENABLE_PROCESSED_INPUT;
93103
SetConsoleMode(std_in, mode);
94-
signal(SIGINT, SIG_DFL);
95104
}
96105
}
97106

0 commit comments

Comments
 (0)