summaryrefslogtreecommitdiffstatshomepage
path: root/ports/webassembly/asyncio/core.py
diff options
context:
space:
mode:
authorDamien George <damien@micropython.org>2024-06-18 17:35:24 +1000
committerDamien George <damien@micropython.org>2024-06-18 22:23:16 +1000
commite9c898cb3312c2e2cf9e0da1d099541bf7bdf4d2 (patch)
tree0f99a3264aa04767883a85cd8d173a88c3ba06cf /ports/webassembly/asyncio/core.py
parenta053e639147d97c4a306ab272c12d9520a80e805 (diff)
downloadmicropython-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.py24
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: