Skip to content

Commit

Permalink
py/mpstate: thread-local exceptions
Browse files Browse the repository at this point in the history
This moves mp_pending_exception from mp_state_vm_t to mp_state_thread_t.
This allows exceptions to be scheduled on a specific thread.
  • Loading branch information
dlech committed Apr 26, 2021
1 parent 4065bf0 commit 4d22401
Show file tree
Hide file tree
Showing 13 changed files with 33 additions and 32 deletions.
6 changes: 3 additions & 3 deletions ports/esp8266/modnetwork.c
Original file line number Diff line number Diff line change
Expand Up @@ -237,10 +237,10 @@ STATIC mp_obj_t esp_scan(mp_obj_t self_in) {
while (esp_scan_list != NULL) {
// our esp_scan_cb is called via ets_loop_iter so it's safe to set the
// esp_scan_list variable to NULL without disabling interrupts
if (MP_STATE_VM(mp_pending_exception) != NULL) {
if (MP_STATE_THREAD(mp_pending_exception) != NULL) {
esp_scan_list = NULL;
mp_obj_t obj = MP_STATE_VM(mp_pending_exception);
MP_STATE_VM(mp_pending_exception) = MP_OBJ_NULL;
mp_obj_t obj = MP_STATE_THREAD(mp_pending_exception);
MP_STATE_THREAD(mp_pending_exception) = MP_OBJ_NULL;
nlr_raise(obj);
}
ets_loop_iter();
Expand Down
6 changes: 3 additions & 3 deletions ports/nrf/boards/microbit/modules/microbitdisplay.c
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ STATIC void async_stop(void) {
STATIC void wait_for_event(void) {
while (!wakeup_event) {
// allow CTRL-C to stop the animation
if (MP_STATE_VM(mp_pending_exception) != MP_OBJ_NULL) {
if (MP_STATE_THREAD(mp_pending_exception) != MP_OBJ_NULL) {
async_stop();
return;
}
Expand Down Expand Up @@ -305,7 +305,7 @@ static void draw_object(mp_obj_t obj) {
async_stop();
}
} else {
MP_STATE_VM(mp_pending_exception) = mp_obj_new_exception_msg(&mp_type_TypeError, MP_ERROR_TEXT("not an image."));
MP_STATE_THREAD(mp_pending_exception) = mp_obj_new_exception_msg(&mp_type_TypeError, MP_ERROR_TEXT("not an image."));
async_stop();
}
}
Expand Down Expand Up @@ -341,7 +341,7 @@ static void microbit_display_update(void) {
if (mp_obj_get_type(nlr.ret_val) == &mp_type_MemoryError) {
mp_printf(&mp_plat_print, "Allocation in interrupt handler");
}
MP_STATE_VM(mp_pending_exception) = MP_OBJ_FROM_PTR(nlr.ret_val);
MP_STATE_THREAD(mp_pending_exception) = MP_OBJ_FROM_PTR(nlr.ret_val);
}
obj = MP_OBJ_STOP_ITERATION;
}
Expand Down
2 changes: 1 addition & 1 deletion ports/nrf/modules/music/modmusic.c
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ STATIC void wait_async_music_idle(void) {
// wait for the async music state to become idle
while (music_data->async_state != ASYNC_MUSIC_STATE_IDLE) {
// allow CTRL-C to stop the music
if (MP_STATE_VM(mp_pending_exception) != MP_OBJ_NULL) {
if (MP_STATE_THREAD(mp_pending_exception) != MP_OBJ_NULL) {
music_data->async_state = ASYNC_MUSIC_STATE_IDLE;
pwm_set_duty_cycle(music_data->async_pin->pin, 0); // TODO: remove pin setting.
break;
Expand Down
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_VM(mp_pending_exception) = MP_STATE_PORT(keyboard_interrupt_obj);
MP_STATE_THREAD(mp_pending_exception) = MP_STATE_PORT(keyboard_interrupt_obj);
}
}
*/
Expand Down
4 changes: 2 additions & 2 deletions ports/stm32/pendsv.c
Original file line number Diff line number Diff line change
Expand Up @@ -60,10 +60,10 @@ void pendsv_init(void) {
// the given exception object using nlr_jump in the context of the top-level
// thread.
void pendsv_kbd_intr(void) {
if (MP_STATE_VM(mp_pending_exception) == MP_OBJ_NULL) {
if (MP_STATE_THREAD(mp_pending_exception) == MP_OBJ_NULL) {
mp_keyboard_interrupt();
} else {
MP_STATE_VM(mp_pending_exception) = MP_OBJ_NULL;
MP_STATE_THREAD(mp_pending_exception) = MP_OBJ_NULL;
pendsv_object = &MP_STATE_VM(mp_kbd_exception);
SCB->ICSR = SCB_ICSR_PENDSVSET_Msk;
}
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_VM(mp_pending_exception) == MP_OBJ_FROM_PTR(&MP_STATE_VM(mp_kbd_exception))) {
if (MP_STATE_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_VM(mp_pending_exception) == MP_OBJ_FROM_PTR(&MP_STATE_VM(mp_kbd_exception))) {
if (MP_STATE_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
3 changes: 2 additions & 1 deletion py/modthread.c
Original file line number Diff line number Diff line change
Expand Up @@ -179,13 +179,14 @@ STATIC void *thread_entry(void *args_in) {
mp_locals_set(args->dict_locals);
mp_globals_set(args->dict_globals);

ts.mp_pending_exception = MP_OBJ_NULL;

MP_THREAD_GIL_ENTER();

// signal that we are set up and running
mp_thread_start();

// TODO set more thread-specific state here:
// mp_pending_exception? (root pointer)
// cur_exception (root pointer)

DEBUG_printf("[thread] start ts=%p args=%p stack=%p\n", &ts, &args, MP_STATE_THREAD(stack_top));
Expand Down
6 changes: 3 additions & 3 deletions py/mpstate.h
Original file line number Diff line number Diff line change
Expand Up @@ -138,9 +138,6 @@ typedef struct _mp_state_vm_t {
// dictionary with loaded modules (may be exposed as sys.modules)
mp_obj_dict_t mp_loaded_modules_dict;

// pending exception object (MP_OBJ_NULL if not pending)
volatile mp_obj_t mp_pending_exception;

#if MICROPY_ENABLE_SCHEDULER
mp_sched_item_t sched_queue[MICROPY_SCHEDULER_DEPTH];
#endif
Expand Down Expand Up @@ -269,6 +266,9 @@ typedef struct _mp_state_thread_t {
bool prof_callback_is_executing;
struct _mp_code_state_t *current_code_state;
#endif

// pending exception object (MP_OBJ_NULL if not pending)
volatile mp_obj_t mp_pending_exception;
} mp_state_thread_t;

// This structure combines the above 3 structures.
Expand Down
6 changes: 3 additions & 3 deletions py/profile.c
Original file line number Diff line number Diff line change
Expand Up @@ -297,9 +297,9 @@ STATIC mp_obj_t mp_prof_callback_invoke(mp_obj_t callback, prof_callback_args_t

mp_prof_is_executing = false;

if (MP_STATE_VM(mp_pending_exception) != MP_OBJ_NULL) {
mp_obj_t obj = MP_STATE_VM(mp_pending_exception);
MP_STATE_VM(mp_pending_exception) = MP_OBJ_NULL;
if (MP_STATE_THREAD(mp_pending_exception) != MP_OBJ_NULL) {
mp_obj_t obj = MP_STATE_THREAD(mp_pending_exception);
MP_STATE_THREAD(mp_pending_exception) = MP_OBJ_NULL;
nlr_raise(obj);
}
return top;
Expand Down
2 changes: 1 addition & 1 deletion py/runtime.c
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ void mp_init(void) {
qstr_init();

// no pending exceptions to start with
MP_STATE_VM(mp_pending_exception) = MP_OBJ_NULL;
MP_STATE_THREAD(mp_pending_exception) = MP_OBJ_NULL;
#if MICROPY_ENABLE_SCHEDULER
MP_STATE_VM(sched_state) = MP_SCHED_IDLE;
MP_STATE_VM(sched_idx) = 0;
Expand Down
14 changes: 7 additions & 7 deletions py/scheduler.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
// This function may be called asynchronously at any time so only do the bare minimum.
void MICROPY_WRAP_MP_KEYBOARD_INTERRUPT(mp_keyboard_interrupt)(void) {
MP_STATE_VM(mp_kbd_exception).traceback_data = NULL;
MP_STATE_VM(mp_pending_exception) = MP_OBJ_FROM_PTR(&MP_STATE_VM(mp_kbd_exception));
MP_STATE_THREAD(mp_pending_exception) = MP_OBJ_FROM_PTR(&MP_STATE_VM(mp_kbd_exception));
#if MICROPY_ENABLE_SCHEDULER
if (MP_STATE_VM(sched_state) == MP_SCHED_IDLE) {
MP_STATE_VM(sched_state) = MP_SCHED_PENDING;
Expand Down Expand Up @@ -62,9 +62,9 @@ void mp_handle_pending(bool raise_exc) {
mp_uint_t atomic_state = MICROPY_BEGIN_ATOMIC_SECTION();
// Re-check state is still pending now that we're in the atomic section.
if (MP_STATE_VM(sched_state) == MP_SCHED_PENDING) {
mp_obj_t obj = MP_STATE_VM(mp_pending_exception);
mp_obj_t obj = MP_STATE_THREAD(mp_pending_exception);
if (obj != MP_OBJ_NULL) {
MP_STATE_VM(mp_pending_exception) = MP_OBJ_NULL;
MP_STATE_THREAD(mp_pending_exception) = MP_OBJ_NULL;
if (!mp_sched_num_pending()) {
MP_STATE_VM(sched_state) = MP_SCHED_IDLE;
}
Expand Down Expand Up @@ -111,7 +111,7 @@ void mp_sched_unlock(void) {
assert(MP_STATE_VM(sched_state) < 0);
if (++MP_STATE_VM(sched_state) == 0) {
// vm became unlocked
if (MP_STATE_VM(mp_pending_exception) != MP_OBJ_NULL || mp_sched_num_pending()) {
if (MP_STATE_THREAD(mp_pending_exception) != MP_OBJ_NULL || mp_sched_num_pending()) {
MP_STATE_VM(sched_state) = MP_SCHED_PENDING;
} else {
MP_STATE_VM(sched_state) = MP_SCHED_IDLE;
Expand Down Expand Up @@ -143,9 +143,9 @@ bool MICROPY_WRAP_MP_SCHED_SCHEDULE(mp_sched_schedule)(mp_obj_t function, mp_obj

// A variant of this is inlined in the VM at the pending exception check
void mp_handle_pending(bool raise_exc) {
if (MP_STATE_VM(mp_pending_exception) != MP_OBJ_NULL) {
mp_obj_t obj = MP_STATE_VM(mp_pending_exception);
MP_STATE_VM(mp_pending_exception) = MP_OBJ_NULL;
if (MP_STATE_THREAD(mp_pending_exception) != MP_OBJ_NULL) {
mp_obj_t obj = MP_STATE_THREAD(mp_pending_exception);
MP_STATE_THREAD(mp_pending_exception) = MP_OBJ_NULL;
if (raise_exc) {
nlr_raise(obj);
}
Expand Down
10 changes: 5 additions & 5 deletions py/vm.c
Original file line number Diff line number Diff line change
Expand Up @@ -1370,9 +1370,9 @@ unwind_jump:;
// Re-check state is still pending now that we're in the atomic section.
if (MP_STATE_VM(sched_state) == MP_SCHED_PENDING) {
MARK_EXC_IP_SELECTIVE();
mp_obj_t obj = MP_STATE_VM(mp_pending_exception);
mp_obj_t obj = MP_STATE_THREAD(mp_pending_exception);
if (obj != MP_OBJ_NULL) {
MP_STATE_VM(mp_pending_exception) = MP_OBJ_NULL;
MP_STATE_THREAD(mp_pending_exception) = MP_OBJ_NULL;
if (!mp_sched_num_pending()) {
MP_STATE_VM(sched_state) = MP_SCHED_IDLE;
}
Expand All @@ -1386,10 +1386,10 @@ unwind_jump:;
}
#else
// This is an inlined variant of mp_handle_pending
if (MP_STATE_VM(mp_pending_exception) != MP_OBJ_NULL) {
if (MP_STATE_THREAD(mp_pending_exception) != MP_OBJ_NULL) {
MARK_EXC_IP_SELECTIVE();
mp_obj_t obj = MP_STATE_VM(mp_pending_exception);
MP_STATE_VM(mp_pending_exception) = MP_OBJ_NULL;
mp_obj_t obj = MP_STATE_THREAD(mp_pending_exception);
MP_STATE_THREAD(mp_pending_exception) = MP_OBJ_NULL;
RAISE(obj);
}
#endif
Expand Down

0 comments on commit 4d22401

Please sign in to comment.