Zephyr port: async event loop implementation starves CPU
When using asyncio in MicroPython, the event loop implementation (asyncio.run) ends up polling Python objects in a queue. The polling code does this (extmod/modselect.c:poll_poll_internal):
...
mp_uint_t start_tick = mp_hal_ticks_ms();
mp_uint_t n_ready;
for (;;) {
// poll the objects
n_ready = poll_map_poll(&self->poll_map, NULL);
if (n_ready > 0 || (timeout != (mp_uint_t)-1 && mp_hal_ticks_ms() - start_tick >= timeout)) {
break;
}
MICROPY_EVENT_POLL_HOOK
}
...
The for(;;) loop above is a busy wait loop. In the Zephyr port, it consumes a lot of CPU time and it starves other threads. Even when MICROPY_EVENT_POOL_HOOK is set to k_yield (and thus the loop gives control back to the OS scheduler after each iteration) the code will still take most of the CPU time. Setting MICROPY_EVENT_POOL_HOOK to something like k_msleep(100) (which waits 100ms before running another iteration of the loop) fixes the starving issue, but it delays the Python thread for no good reason.
I have a possible solution for this, but please let me know first if there is interest to move this forward, since lately I got the impression that the Zephyr port isn't exactly a "fist class citizen" in the world of MicroPython ports.
zephyr: Convert port to use new event waiting functions.
Summary
This PR converts the zephyr port to use the new event waiting mechanism, with the MICROPY_INTERNAL_WFE macro.
As part of this, the mp_hal_wait_sem() function is updated so it can exit early when an event occurs. That allows it to be used by MICROPY_INTERNAL_WFE to implement efficient waiting, so calls like mp_event_wait_indefinite() will actually suspend the thread until an event wakes it.
Testing
Tested on frdm_k64f, running the full test suite. There were no regressions. Note that the new event logic in machine_uart.c is tested by tests/extmod/machine_uart_tx.py (by using a custom target_wiring.py file).
Trade-offs and Alternatives
When threading is enabled mp_hal_wait_sem() does not work correctly due to global state. But that's the topic of a separate PR #17866.