diff options
author | Damien George <damien@micropython.org> | 2024-06-18 17:35:24 +1000 |
---|---|---|
committer | Damien George <damien@micropython.org> | 2024-06-18 22:23:16 +1000 |
commit | e9c898cb3312c2e2cf9e0da1d099541bf7bdf4d2 (patch) | |
tree | 0f99a3264aa04767883a85cd8d173a88c3ba06cf /ports/webassembly/asyncio/core.py | |
parent | a053e639147d97c4a306ab272c12d9520a80e805 (diff) | |
download | micropython-e9c898cb3312c2e2cf9e0da1d099541bf7bdf4d2.tar.gz micropython-e9c898cb3312c2e2cf9e0da1d099541bf7bdf4d2.zip |
webassembly/asyncio: Support top-level await of asyncio Task and Event.
This change allows doing a top-level await on an asyncio primitive like
Task and Event.
This feature enables a better interaction and synchronisation between
JavaScript and Python, because `api.runPythonAsync` can now be used (called
from JavaScript) to await on the completion of asyncio primitives.
Signed-off-by: Damien George <damien@micropython.org>
Diffstat (limited to 'ports/webassembly/asyncio/core.py')
-rw-r--r-- | ports/webassembly/asyncio/core.py | 24 |
1 files changed, 18 insertions, 6 deletions
diff --git a/ports/webassembly/asyncio/core.py b/ports/webassembly/asyncio/core.py index f6f9d19e5c..cc26e7b8d5 100644 --- a/ports/webassembly/asyncio/core.py +++ b/ports/webassembly/asyncio/core.py @@ -50,9 +50,6 @@ class SingletonGenerator: # Pause task execution for the given time (integer in milliseconds, uPy extension) # Use a SingletonGenerator to do it without allocating on the heap def sleep_ms(t, sgen=SingletonGenerator()): - if cur_task is None: - # Support top-level asyncio.sleep, via a JavaScript Promise. - return jsffi.async_timeout_ms(t) assert sgen.state is None sgen.state = ticks_add(ticks(), max(0, t)) return sgen @@ -69,6 +66,18 @@ def sleep(t): asyncio_timer = None +class TopLevelCoro: + @staticmethod + def set(resolve, reject): + TopLevelCoro.resolve = resolve + TopLevelCoro.reject = reject + _schedule_run_iter(0) + + @staticmethod + def send(value): + TopLevelCoro.resolve() + + class ThenableEvent: def __init__(self, thenable): self.result = None # Result of the thenable @@ -122,12 +131,12 @@ def _run_iter(): dt = max(0, ticks_diff(t.ph_key, ticks())) else: # No tasks can be woken so finished running - cur_task = None + cur_task = _top_level_task return if dt > 0: # schedule to call again later - cur_task = None + cur_task = _top_level_task _schedule_run_iter(dt) return @@ -198,11 +207,14 @@ def create_task(coro): return t +# Task used to suspend and resume top-level await. +_top_level_task = Task(TopLevelCoro, globals()) + ################################################################################ # Event loop wrapper -cur_task = None +cur_task = _top_level_task class Loop: |