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
ueventwhich is similar in spirit toselectandselectorsbut optimised for the needs of an async scheduler. It's completely independent touasynciobut used by it to wait for IO events.The use of
ueventgoes like this:It looks very similar to
select.pollbut has some important differences which make it better suited to handling events:The important thin with
ueventis 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.chas 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.Pinobject, 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 theAsyncPinwrapper 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
selectmodule asueventand makes it event/callback based (on bare-metal) rather than busy-loop polling. And then builds on this to add events tomachine.Pinobjects so they can be registered withueventand hence integrated withuasyncio.