Skip to content

Commit 1c9210b

Browse files
committed
unix/unix_mphal: Raise KeyboardInterrupt straight from signal handler.
POSIX doesn't guarantee something like that to work, but it works on any system with careful signal implementation. Roughly, the requirement is that signal handler is executed in the context of the process, its main thread, etc. This is true for Linux. Also tested to work without issues on MacOSX.
1 parent e9751d2 commit 1c9210b

File tree

3 files changed

+17
-0
lines changed

3 files changed

+17
-0
lines changed

py/mpconfig.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -371,6 +371,12 @@
371371
# endif
372372
#endif
373373

374+
// Prefer to raise KeyboardInterrupt asynchronously (from signal or interrupt
375+
// handler) - if supported by a particular port.
376+
#ifndef MICROPY_ASYNC_KBD_INTR
377+
#define MICROPY_ASYNC_KBD_INTR (0)
378+
#endif
379+
374380
// Whether to include REPL helper function
375381
#ifndef MICROPY_HELPER_REPL
376382
#define MICROPY_HELPER_REPL (0)

unix/mpconfigport.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,7 @@
128128

129129
#define MICROPY_ENABLE_EMERGENCY_EXCEPTION_BUF (1)
130130
#define MICROPY_EMERGENCY_EXCEPTION_BUF_SIZE (256)
131+
#define MICROPY_ASYNC_KBD_INTR (1)
131132

132133
extern const struct _mp_obj_module_t mp_module_machine;
133134
extern const struct _mp_obj_module_t mp_module_os;

unix/unix_mphal.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,12 +37,22 @@
3737

3838
STATIC void sighandler(int signum) {
3939
if (signum == SIGINT) {
40+
#if MICROPY_ASYNC_KBD_INTR
41+
mp_obj_exception_clear_traceback(MP_STATE_VM(keyboard_interrupt_obj));
42+
sigset_t mask;
43+
sigemptyset(&mask);
44+
// On entry to handler, its signal is blocked, and unblocked on
45+
// normal exit. As we instead perform longjmp, unblock it manually.
46+
sigprocmask(SIG_SETMASK, &mask, NULL);
47+
nlr_raise(MP_STATE_VM(keyboard_interrupt_obj));
48+
#else
4049
if (MP_STATE_VM(mp_pending_exception) == MP_STATE_VM(keyboard_interrupt_obj)) {
4150
// this is the second time we are called, so die straight away
4251
exit(1);
4352
}
4453
mp_obj_exception_clear_traceback(MP_STATE_VM(keyboard_interrupt_obj));
4554
MP_STATE_VM(mp_pending_exception) = MP_STATE_VM(keyboard_interrupt_obj);
55+
#endif
4656
}
4757
}
4858
#endif

0 commit comments

Comments
 (0)