Hi,
In SDK11, it was possible to call app_sched_execute()
from a function that was itself called from the scheduler:
void app_sched_execute(void)
{
void * p_event_data;
uint16_t event_data_size;
app_sched_event_handler_t event_handler;
// Get next event (if any), and execute handler
while ((app_sched_event_get(&p_event_data, &event_data_size, &event_handler) == NRF_SUCCESS))
{
event_handler(p_event_data, event_data_size);
}
}
static uint32_t app_sched_event_get(void ** pp_event_data,
uint16_t * p_event_data_size,
app_sched_event_handler_t * p_event_handler)
{
uint32_t err_code = NRF_ERROR_NOT_FOUND;
if (!APP_SCHED_QUEUE_EMPTY())
{
uint16_t event_index;
// NOTE: There is no need for a critical region here, as this function will only be called
// from app_sched_execute() from inside the main loop, so it will never interrupt
// app_sched_event_put(). Also, updating of (i.e. writing to) the start index will be
// an atomic operation.
event_index = m_queue_start_index;
m_queue_start_index = next_index(m_queue_start_index);
*pp_event_data = &m_queue_event_data[event_index * m_queue_event_size];
*p_event_data_size = m_queue_event_headers[event_index].event_data_size;
*p_event_handler = m_queue_event_headers[event_index].handler;
err_code = NRF_SUCCESS;
}
return err_code;
}
This is possible because the queue is updated in app_sched_event_get()
before the event_handler is called; thus, if the event_handler calls app_sched_execute()
again, it will either return if there are no more events on the queue, or execute the next queued event.
However, now in SDK13, the event queue is updated after calling the handler:
void app_sched_execute(void)
{
while (!is_app_sched_paused() && !APP_SCHED_QUEUE_EMPTY())
{
// Since this function is only called from the main loop, there is no
// need for a critical region here, however a special care must be taken
// regarding update of the queue start index (see the end of the loop).
uint16_t event_index = m_queue_start_index;
void * p_event_data;
uint16_t event_data_size;
app_sched_event_handler_t event_handler;
p_event_data = &m_queue_event_data[event_index * m_queue_event_size];
event_data_size = m_queue_event_headers[event_index].event_data_size;
event_handler = m_queue_event_headers[event_index].handler;
event_handler(p_event_data, event_data_size);
// Event processed, now it is safe to move the queue start index,
// so the queue entry occupied by this event can be used to store
// a next one.
m_queue_start_index = next_index(m_queue_start_index);
}
}
Thus, no scheduled function can ever call app_sched_execute()
, because it'll cause infinite recursion (since that function itself is still at the front of the queue!)
Being able to call app_sched_execute()
from places other than the main loop was useful, because for example you could block from anywhere, waiting for timer or BLE events. There may be better ways to do this in SDK13, but my app built on SDK11 relied on being able to call app_sched_execute()
from anywhere (including scheduled functions).
Is there a good reason why this was changed in SDK13 to update the queue after calling the event_handler, rather than before? I don't see any downside to updating it prior to the call, and only see upside (i.e., not worrying about infinite recursion if app_sched_execute()
is called from places other than the main loop).