From 5e96e89999cd3b922dbc1a6ed473b44c81db92f4 Mon Sep 17 00:00:00 2001 From: Jim Mussared Date: Fri, 12 Feb 2021 14:14:07 +1100 Subject: [PATCH] extmod/uasyncio: Add ThreadSafeFlag. This is a MicroPython-extension that allows for code running in IRQ (hard or soft) or scheduler context to sequence asyncio code. Signed-off-by: Jim Mussared --- extmod/uasyncio/__init__.py | 1 + extmod/uasyncio/event.py | 31 +++++++++++++++++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/extmod/uasyncio/__init__.py b/extmod/uasyncio/__init__.py index 08f924cf29..fa64438f6b 100644 --- a/extmod/uasyncio/__init__.py +++ b/extmod/uasyncio/__init__.py @@ -10,6 +10,7 @@ _attrs = { "wait_for_ms": "funcs", "gather": "funcs", "Event": "event", + "ThreadSafeFlag": "event", "Lock": "lock", "open_connection": "stream", "start_server": "stream", diff --git a/extmod/uasyncio/event.py b/extmod/uasyncio/event.py index 31cb00e055..c28ad1fb31 100644 --- a/extmod/uasyncio/event.py +++ b/extmod/uasyncio/event.py @@ -14,6 +14,8 @@ class Event: def set(self): # Event becomes set, schedule any tasks waiting on it + # Note: This must not be called from anything except the thread running + # the asyncio loop (i.e. neither hard or soft IRQ, or a different thread). while self.waiting.peek(): core._task_queue.push_head(self.waiting.pop_head()) self.state = True @@ -29,3 +31,32 @@ class Event: core.cur_task.data = self.waiting yield return True + + +# MicroPython-extension: This can be set from outside the asyncio event loop, +# such as other threads, IRQs or scheduler context. Implementation is a stream +# that asyncio will poll until a flag is set. +# Note: Unlike Event, this is self-clearing. +try: + import uio + + class ThreadSafeFlag(uio.IOBase): + def __init__(self): + self._flag = 0 + + def ioctl(self, req, flags): + if req == 3: # MP_STREAM_POLL + return self._flag * flags + return None + + def set(self): + self._flag = 1 + + async def wait(self): + if not self._flag: + yield core._io_queue.queue_read(self) + self._flag = 0 + + +except ImportError: + pass