Skip to content

Commit

Permalink
py/mpstate: Schedule KeyboardInterrupt on main thread.
Browse files Browse the repository at this point in the history
This introduces a new macro to get the main thread and uses it to ensure
that asynchronous exceptions such as KeyboardInterrupt (CTRL+C) are only
scheduled on the main thread. This is more deterministic than being
scheduled on a random thread and is more in line with CPython that only
allow signal handlers to run on the main thread.

Issue: #7026
  • Loading branch information
dlech committed May 11, 2021
1 parent 862dcb1 commit b2df361
Show file tree
Hide file tree
Showing 5 changed files with 7 additions and 5 deletions.
2 changes: 1 addition & 1 deletion ports/pic16bit/board.c
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ int switch_get(int sw) {
// TODO need an irq
void uart_rx_irq(void) {
if (c == interrupt_char) {
MP_STATE_THREAD(mp_pending_exception) = MP_STATE_PORT(keyboard_interrupt_obj);
MP_STATE_MAIN_THREAD(mp_pending_exception) = MP_STATE_PORT(keyboard_interrupt_obj);
}
}
*/
Expand Down
2 changes: 1 addition & 1 deletion ports/unix/unix_mphal.c
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ STATIC void sighandler(int signum) {
sigprocmask(SIG_SETMASK, &mask, NULL);
nlr_raise(MP_OBJ_FROM_PTR(&MP_STATE_VM(mp_kbd_exception)));
#else
if (MP_STATE_THREAD(mp_pending_exception) == MP_OBJ_FROM_PTR(&MP_STATE_VM(mp_kbd_exception))) {
if (MP_STATE_MAIN_THREAD(mp_pending_exception) == MP_OBJ_FROM_PTR(&MP_STATE_VM(mp_kbd_exception))) {
// this is the second time we are called, so die straight away
exit(1);
}
Expand Down
2 changes: 1 addition & 1 deletion ports/windows/windows_mphal.c
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ void mp_hal_stdio_mode_orig(void) {
// 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_THREAD(mp_pending_exception) == MP_OBJ_FROM_PTR(&MP_STATE_VM(mp_kbd_exception))) {
if (MP_STATE_MAIN_THREAD(mp_pending_exception) == MP_OBJ_FROM_PTR(&MP_STATE_VM(mp_kbd_exception))) {
// this is the second time we are called, so die straight away
exit(1);
}
Expand Down
4 changes: 3 additions & 1 deletion py/mpstate.h
Original file line number Diff line number Diff line change
Expand Up @@ -286,11 +286,13 @@ extern mp_state_ctx_t mp_state_ctx;
#define MP_STATE_VM(x) (mp_state_ctx.vm.x)
#define MP_STATE_MEM(x) (mp_state_ctx.mem.x)

#define MP_STATE_MAIN_THREAD(x) (mp_state_ctx.thread.x)

#if MICROPY_PY_THREAD
extern mp_state_thread_t *mp_thread_get_state(void);
#define MP_STATE_THREAD(x) (mp_thread_get_state()->x)
#else
#define MP_STATE_THREAD(x) (mp_state_ctx.thread.x)
#define MP_STATE_THREAD(x) MP_STATE_MAIN_THREAD(x)
#endif

#endif // MICROPY_INCLUDED_PY_MPSTATE_H
2 changes: 1 addition & 1 deletion py/scheduler.c
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
#include "py/runtime.h"

void MICROPY_WRAP_MP_SCHED_EXCEPTION(mp_sched_exception)(mp_obj_t exc) {
MP_STATE_THREAD(mp_pending_exception) = exc;
MP_STATE_MAIN_THREAD(mp_pending_exception) = exc;
#if MICROPY_ENABLE_SCHEDULER
if (MP_STATE_VM(sched_state) == MP_SCHED_IDLE) {
MP_STATE_VM(sched_state) = MP_SCHED_PENDING;
Expand Down

0 comments on commit b2df361

Please sign in to comment.