Looking at the stm32 can code, the general structure of an interrupt handler that does a callback seems to be
Code: Select all
int handler ( )
{
int l_nResult = e_RETURNVALUE_Success;
pyb_obj_t * self = xxx;
mp_sched_lock();
gc_lock();
nlr_buf_t nlr;
if (nlr_push(&nlr) == 0) {
mp_call_function_x( l_pSelf->callback, ... );
nlr_pop();
} else {
// Uncaught exception; disable the callback so it doesn't run again.
pyb_setbareventcallback(l_pSelf, mp_const_none);
printf("uncaught exception in handler\n");
mp_obj_print_exception(&mp_plat_print, (mp_obj_t)nlr.ret_val);
l_nResult = e_RETURNVALUE_Failure;
}
gc_unlock();
mp_sched_unlock();
return ( l_nResult );
}
[1] I need to create a string mp object from an input argument of the handler. Creating objects might raise an exception and can't be done in gc_lock state, so i have to change the order. The can code does not have this problem because the use a small int (which is only ok if representation is such that small int fits in a number and not an object, but okay).
[2] I am running under freertos so no scheduler.
The good thing is that my handler is not an interrupt handler, but just a notification coming from another task that is probably not too bothered by having to wait a bit.
So i think about going to this form:
Code: Select all
int handler( char* somestring )
{
int l_nResult = e_RETURNVALUE_Success;
pyb_obj_t * self = xxx;
MP_THREAD_GIL_ENTER();
nlr_buf_t nlr;
if (nlr_push(&nlr) == 0) {
mp_obj_t callbackstring = mp_obj_new_str( somestring, strlen(somestring), 0 )
gc_lock();
mp_call_function_x( l_pSelf->callback , l_pSelf, callbackstring, );
gc_unlock();
nlr_pop();
} else {
// Uncaught exception; disable the callback so it doesn't run again.
pyb_setbareventcallback(l_pSelf, mp_const_none);
printf("uncaught exception in handler\n");
mp_obj_print_exception(&mp_plat_print, (mp_obj_t)nlr.ret_val);
l_nResult = e_RETURNVALUE_Failure;
}
MP_THREAD_GIL_EXIT();
return ( l_nResult );
}
The mp_sched_lock might be useful to prevent the scheduler from running another 'task' if the can interrupt itself is interrupted by a timer tick i suppose (not sure if that is possible, i have not looked at the scheduler to see how it is works). But then why the extra gc_lock ? To make sure that anyone attempting to do a malloc in the callback gets trapped in the uncaught exception branch ?
In that case setting up nlr before doing a gc_lock should not be a problem.
Did i miss something ?