Skip to content

py: Implement mp_sched_vm_abort() to force a return to the very top level (v2) #10971

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

Merged
merged 2 commits into from
Mar 21, 2023
Merged
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
9 changes: 9 additions & 0 deletions py/mpconfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -909,6 +909,11 @@ typedef double mp_float_t;
#define MICROPY_INTERNAL_PRINTF_PRINTER (&mp_plat_print)
#endif

// Whether to support mp_sched_vm_abort to asynchronously abort to the top level.
#ifndef MICROPY_ENABLE_VM_ABORT
#define MICROPY_ENABLE_VM_ABORT (0)
#endif

// Support for internal scheduler
#ifndef MICROPY_ENABLE_SCHEDULER
#define MICROPY_ENABLE_SCHEDULER (MICROPY_CONFIG_ROM_LEVEL_AT_LEAST_EXTRA_FEATURES)
Expand Down Expand Up @@ -1740,6 +1745,10 @@ typedef double mp_float_t;
#define MICROPY_WRAP_MP_SCHED_SCHEDULE(f) f
#endif

#ifndef MICROPY_WRAP_MP_SCHED_VM_ABORT
#define MICROPY_WRAP_MP_SCHED_VM_ABORT(f) f
#endif

/*****************************************************************************/
/* Miscellaneous settings */

Expand Down
7 changes: 7 additions & 0 deletions py/mpstate.h
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,11 @@ typedef struct _mp_state_vm_t {
uint8_t sched_idx;
#endif

#if MICROPY_ENABLE_VM_ABORT
bool vm_abort;
nlr_buf_t *nlr_abort;
#endif

#if MICROPY_PY_THREAD_GIL
// This is a global mutex used to make the VM/runtime thread-safe.
mp_thread_mutex_t gil_mutex;
Expand Down Expand Up @@ -297,8 +302,10 @@ extern mp_state_ctx_t mp_state_ctx;
#if MICROPY_PY_THREAD
extern mp_state_thread_t *mp_thread_get_state(void);
#define MP_STATE_THREAD(x) (mp_thread_get_state()->x)
#define mp_thread_is_main_thread() (mp_thread_get_state() == &mp_state_ctx.thread)
#else
#define MP_STATE_THREAD(x) MP_STATE_MAIN_THREAD(x)
#define mp_thread_is_main_thread() (true)
#endif

#endif // MICROPY_INCLUDED_PY_MPSTATE_H
7 changes: 7 additions & 0 deletions py/nlr.c
Original file line number Diff line number Diff line change
Expand Up @@ -49,3 +49,10 @@ void nlr_pop(void) {
nlr_buf_t **top = &MP_STATE_THREAD(nlr_top);
*top = (*top)->prev;
}

#if MICROPY_ENABLE_VM_ABORT
NORETURN void nlr_jump_abort(void) {
MP_STATE_THREAD(nlr_top) = MP_STATE_VM(nlr_abort);
nlr_jump(NULL);
}
#endif
17 changes: 15 additions & 2 deletions py/nlr.h
Original file line number Diff line number Diff line change
Expand Up @@ -101,9 +101,16 @@

typedef struct _nlr_buf_t nlr_buf_t;
struct _nlr_buf_t {
// the entries here must all be machine word size
// The entries in this struct must all be machine word size.

// Pointer to the previous nlr_buf_t in the chain.
// Or NULL if it's the top-level one.
nlr_buf_t *prev;
void *ret_val; // always a concrete object (an exception instance)

// The exception that is being raised:
// - NULL means the jump is because of a VM abort (only if MICROPY_ENABLE_VM_ABORT enabled)
// - otherwise it's always a concrete object (an exception instance)
void *ret_val;

#if MICROPY_NLR_SETJMP
jmp_buf jmpbuf;
Expand Down Expand Up @@ -149,6 +156,12 @@ unsigned int nlr_push_tail(nlr_buf_t *top);
void nlr_pop(void);
NORETURN void nlr_jump(void *val);

#if MICROPY_ENABLE_VM_ABORT
#define nlr_set_abort(buf) MP_STATE_VM(nlr_abort) = buf
#define nlr_get_abort() MP_STATE_VM(nlr_abort)
NORETURN void nlr_jump_abort(void);
#endif

// This must be implemented by a port. It's called by nlr_jump
// if no nlr buf has been pushed. It must not return, but rather
// should bail out with a fatal error.
Expand Down
3 changes: 3 additions & 0 deletions py/runtime.h
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,9 @@ void mp_deinit(void);

void mp_sched_exception(mp_obj_t exc);
void mp_sched_keyboard_interrupt(void);
#if MICROPY_ENABLE_VM_ABORT
void mp_sched_vm_abort(void);
#endif
void mp_handle_pending(bool raise_exc);

#if MICROPY_ENABLE_SCHEDULER
Expand Down
19 changes: 19 additions & 0 deletions py/scheduler.c
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,12 @@ void MICROPY_WRAP_MP_SCHED_KEYBOARD_INTERRUPT(mp_sched_keyboard_interrupt)(void)
}
#endif

#if MICROPY_ENABLE_VM_ABORT
void MICROPY_WRAP_MP_SCHED_VM_ABORT(mp_sched_vm_abort)(void) {
MP_STATE_VM(vm_abort) = true;
}
#endif

#if MICROPY_ENABLE_SCHEDULER

#define IDX_MASK(i) ((i) & (MICROPY_SCHEDULER_DEPTH - 1))
Expand Down Expand Up @@ -203,6 +209,17 @@ MP_REGISTER_ROOT_POINTER(mp_sched_item_t sched_queue[MICROPY_SCHEDULER_DEPTH]);
// Called periodically from the VM or from "waiting" code (e.g. sleep) to
// process background tasks and pending exceptions (e.g. KeyboardInterrupt).
void mp_handle_pending(bool raise_exc) {
// Handle pending VM abort.
#if MICROPY_ENABLE_VM_ABORT
if (MP_STATE_VM(vm_abort) && mp_thread_is_main_thread()) {
MP_STATE_VM(vm_abort) = false;
if (raise_exc && nlr_get_abort() != NULL) {
nlr_jump_abort();
}
}
#endif

// Handle any pending exception.
if (MP_STATE_THREAD(mp_pending_exception) != MP_OBJ_NULL) {
mp_uint_t atomic_state = MICROPY_BEGIN_ATOMIC_SECTION();
mp_obj_t obj = MP_STATE_THREAD(mp_pending_exception);
Expand All @@ -215,6 +232,8 @@ void mp_handle_pending(bool raise_exc) {
}
MICROPY_END_ATOMIC_SECTION(atomic_state);
}

// Handle any pending callbacks.
#if MICROPY_ENABLE_SCHEDULER
if (MP_STATE_VM(sched_state) == MP_SCHED_PENDING) {
mp_sched_run_pending();
Expand Down
4 changes: 4 additions & 0 deletions py/vm.c
Original file line number Diff line number Diff line change
Expand Up @@ -1333,6 +1333,10 @@ unwind_jump:;
// No scheduler: Just check pending exception.
MP_STATE_THREAD(mp_pending_exception) != MP_OBJ_NULL
#endif
#if MICROPY_ENABLE_VM_ABORT
// Check if the VM should abort execution.
|| MP_STATE_VM(vm_abort)
#endif
) {
MARK_EXC_IP_SELECTIVE();
mp_handle_pending(true);
Expand Down
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy