extmod: implement "uevent" module for event-based polling and use with uasyncio (RFC, WIP) #6110
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
This is an alternative to #6106 to allow arbitrary events to hook into uasyncio, not just streams that are readable/writable.
The idea here is to provide a new MicroPython-specific module called
uevent
which is similar in spirit toselect
andselectors
but optimised for the needs of an async scheduler. It's completely independent touasyncio
but used by it to wait for IO events.The use of
uevent
goes like this:It looks very similar to
select.poll
but has some important differences which make it better suited to handling events:The important thin with
uevent
is that on bare-metal it's implemented fully as O(1) for all operations (registering, modifying, waiting, getting next available event). It does this by providing registered objects with a callback to call when they have an event of interest.The PR here includes working code for stm32 (sockets and native pin events), unix (file descriptors only) and zephyr (native pin events).
The code is still very much WIP and proof-of-concept, but the highlights are:
extmod/modlwip.c
has very minimal changes to make it event driven, ie provide callbacks into uevent when sockets become readable/writable (so no more busy loop polling!)k_sem_take(&sem, timeout)
, with the semaphore set asynchronously by a pin interruptMICROPY_EVENT_POLL_HOOK
(which could be just a WFI and it'd still work)The code to implement an async pin object with this PR is:
Note that one can't directly await on a raw
machine.Pin
object, instead such objects are registered with the poller and the poller wakes when the raw pin object has some kind of event. It's then up to theAsyncPin
wrapper to manage that event (in the case above it just retrieves it withpin.get_event()
which returns the number of edges since the last call).The code here doesn't yet implement a way to call
Event.set()
from a soft-scheduled callback, like #6106 does, but I still think that's a useful feature to have more control over waking asyncio from an IRQ.In summary: the PR here reimplements the
select
module asuevent
and makes it event/callback based (on bare-metal) rather than busy-loop polling. And then builds on this to add events tomachine.Pin
objects so they can be registered withuevent
and hence integrated withuasyncio
.