shared/runtime/mpirq: Factor out mp_irq_dispatch() and use it.

Separate out a routine to call an arbitrary function with arbitrary
argument either directly as a hard-IRQ handler or scheduled as a soft-IRQ
handler, adjusting mp_irq_handler() to wrap this. This can then be used
to implement other hard/soft callbacks, such as for machine.Timer.

Signed-off-by: Chris Webb <chris@arachsys.com>
This commit is contained in:
Chris Webb
2025-08-25 13:56:49 +01:00
committed by Damien George
parent 6c9940b1f6
commit 706cc8d833
2 changed files with 18 additions and 8 deletions

View File

@@ -65,9 +65,10 @@ void mp_irq_init(mp_irq_obj_t *self, const mp_irq_methods_t *methods, mp_obj_t p
self->ishard = false; self->ishard = false;
} }
void mp_irq_handler(mp_irq_obj_t *self) { int mp_irq_dispatch(mp_obj_t handler, mp_obj_t parent, bool ishard) {
if (self->handler != mp_const_none) { int result = 0;
if (self->ishard) { if (handler != mp_const_none) {
if (ishard) {
// When executing code within a handler we must lock the scheduler to // When executing code within a handler we must lock the scheduler to
// prevent any scheduled callbacks from running, and lock the GC to // prevent any scheduled callbacks from running, and lock the GC to
// prevent any memory allocations. // prevent any memory allocations.
@@ -75,22 +76,30 @@ void mp_irq_handler(mp_irq_obj_t *self) {
gc_lock(); gc_lock();
nlr_buf_t nlr; nlr_buf_t nlr;
if (nlr_push(&nlr) == 0) { if (nlr_push(&nlr) == 0) {
mp_call_function_1(self->handler, self->parent); mp_call_function_1(handler, parent);
nlr_pop(); nlr_pop();
} else { } else {
// Uncaught exception; disable the callback so that it doesn't run again
self->methods->trigger(self->parent, 0);
self->handler = mp_const_none;
mp_printf(MICROPY_ERROR_PRINTER, "Uncaught exception in IRQ callback handler\n"); mp_printf(MICROPY_ERROR_PRINTER, "Uncaught exception in IRQ callback handler\n");
mp_obj_print_exception(MICROPY_ERROR_PRINTER, MP_OBJ_FROM_PTR(nlr.ret_val)); mp_obj_print_exception(MICROPY_ERROR_PRINTER, MP_OBJ_FROM_PTR(nlr.ret_val));
result = -1;
} }
gc_unlock(); gc_unlock();
mp_sched_unlock(); mp_sched_unlock();
} else { } else {
// Schedule call to user function // Schedule call to user function
mp_sched_schedule(self->handler, self->parent); mp_sched_schedule(handler, parent);
} }
} }
return result;
}
void mp_irq_handler(mp_irq_obj_t *self) {
if (mp_irq_dispatch(self->handler, self->parent, self->ishard) < 0) {
// Uncaught exception; disable the callback so that it doesn't run again
self->methods->trigger(self->parent, 0);
self->handler = mp_const_none;
}
} }
/******************************************************************************/ /******************************************************************************/

View File

@@ -77,6 +77,7 @@ extern const mp_obj_type_t mp_irq_type;
mp_irq_obj_t *mp_irq_new(const mp_irq_methods_t *methods, mp_obj_t parent); mp_irq_obj_t *mp_irq_new(const mp_irq_methods_t *methods, mp_obj_t parent);
void mp_irq_init(mp_irq_obj_t *self, const mp_irq_methods_t *methods, mp_obj_t parent); void mp_irq_init(mp_irq_obj_t *self, const mp_irq_methods_t *methods, mp_obj_t parent);
int mp_irq_dispatch(mp_obj_t handler, mp_obj_t parent, bool ishard);
void mp_irq_handler(mp_irq_obj_t *self); void mp_irq_handler(mp_irq_obj_t *self);
#endif // MICROPY_INCLUDED_LIB_UTILS_MPIRQ_H #endif // MICROPY_INCLUDED_LIB_UTILS_MPIRQ_H