Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Per-thread exceptions #7251

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion ports/esp8266/modnetwork.c
Original file line number Diff line number Diff line change
Expand Up @@ -237,7 +237,7 @@ 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_handle_pending(true);
}
Expand Down
2 changes: 1 addition & 1 deletion 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
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_MAIN_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_MAIN_THREAD(mp_pending_exception) == MP_OBJ_NULL) {
mp_sched_keyboard_interrupt();
} else {
MP_STATE_VM(mp_pending_exception) = MP_OBJ_NULL;
MP_STATE_MAIN_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_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_VM(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
3 changes: 2 additions & 1 deletion py/modthread.c
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,8 @@ STATIC void *thread_entry(void *args_in) {
// The GC starts off unlocked on this thread.
ts.gc_lock_depth = 0;

ts.mp_pending_exception = MP_OBJ_NULL;

// set locals and globals from the calling context
mp_locals_set(args->dict_locals);
mp_globals_set(args->dict_globals);
Expand All @@ -184,7 +186,6 @@ STATIC void *thread_entry(void *args_in) {
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
10 changes: 6 additions & 4 deletions py/mpstate.h
Original file line number Diff line number Diff line change
Expand Up @@ -137,9 +137,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 @@ -266,6 +263,9 @@ typedef struct _mp_state_thread_t {

nlr_buf_t *nlr_top;

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

#if MICROPY_PY_SYS_SETTRACE
mp_obj_t prof_trace_callback;
bool prof_callback_is_executing;
Expand All @@ -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/profile.c
Original file line number Diff line number Diff line change
Expand Up @@ -297,7 +297,7 @@ 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) {
if (MP_STATE_THREAD(mp_pending_exception) != MP_OBJ_NULL) {
mp_handle_pending(true);
}
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
16 changes: 9 additions & 7 deletions py/scheduler.c
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,10 @@

#include "py/runtime.h"

// Schedules an exception on the main thread (for exceptions "thrown" by async
// sources such as interrupts and UNIX signal handlers).
void MICROPY_WRAP_MP_SCHED_EXCEPTION(mp_sched_exception)(mp_obj_t exc) {
MP_STATE_VM(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 Expand Up @@ -66,9 +68,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 @@ -115,7 +117,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 @@ -148,9 +150,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 @@ -1375,9 +1375,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 @@ -1391,10 +1391,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