@@ -1042,31 +1042,10 @@ trap if another task tries to drop the waitable set being used.
10421042 return event
10431043```
10441044
1045- The ` Task.poll_until ` method is called by ` canon_waitable_set_poll ` and from
1046- the event loop in ` canon_lift ` when ` CallbackCode.POLL ` is returned. Unlike
1047- ` wait_until ` , ` poll_until ` does not wait for the given waitable set to have a
1048- pending event, returning ` EventCode.NONE ` if there is none already. However,
1049- ` poll_until ` * does* call ` suspsend_until ` to allow the runtime to
1050- nondeterministically switch to another task (or not).
1051- ``` python
1052- def poll_until (self , ready_func , thread , wset , cancellable ) -> Optional[EventTuple]:
1053- assert (thread in self .threads and thread.task is self )
1054- wset.num_waiting += 1
1055- match self .suspend_until(ready_func, thread, cancellable):
1056- case SuspendResult.CANCELLED :
1057- event = (EventCode.TASK_CANCELLED , 0 , 0 )
1058- case SuspendResult.NOT_CANCELLED :
1059- if wset.has_pending_event():
1060- event = wset.get_pending_event()
1061- else :
1062- event = (EventCode.NONE , 0 , 0 )
1063- wset.num_waiting -= 1
1064- return event
1065- ```
1066-
10671045The ` Task.yield_until ` method is called by ` canon_thread_yield ` and from
1068- the event loop in ` canon_lift ` when ` CallbackCode.YIELD ` is returned.
1069- ` yield_until ` works like ` poll_until ` if given a fresh empty waitable set.
1046+ the event loop in ` canon_lift ` when ` CallbackCode.YIELD ` is returned and
1047+ calls ` suspend_until ` to allow the runtime to nondeterministically switch to
1048+ another task (or not).
10701049``` python
10711050 def yield_until (self , ready_func , thread , cancellable ) -> EventTuple:
10721051 assert (thread in self .threads and thread.task is self )
@@ -3277,11 +3256,8 @@ function (specified as a `funcidx` immediate in `canon lift`) until the
32773256 wset = inst.table.get(si)
32783257 trap_if(not isinstance (wset, WaitableSet))
32793258 event = task.wait_until(lambda : not inst.exclusive, thread, wset, cancellable = True )
3280- case CallbackCode.POLL :
3281- trap_if(not task.may_block())
3282- wset = inst.table.get(si)
3283- trap_if(not isinstance (wset, WaitableSet))
3284- event = task.poll_until(lambda : not inst.exclusive, thread, wset, cancellable = True )
3259+ case _:
3260+ trap()
32853261 thread.in_event_loop = False
32863262 inst.exclusive = True
32873263 event_code, p1, p2 = event
@@ -3290,11 +3266,11 @@ function (specified as a `funcidx` immediate in `canon lift`) until the
32903266 task.exit()
32913267 return
32923268```
3293- The ` Task.{wait,poll, yield}_until ` methods called by the event loop are the
3294- same methods called by the ` yield ` , ` waitable-set.wait ` and ` waitable-set.poll `
3295- built-ins. Thus, the main difference between stackful and stackless async is
3296- whether these suspending operations are performed from an empty or non-empty
3297- core wasm callstack (with the former allowing additional engine optimization).
3269+ The ` Task.{wait,yield}_until ` methods called by the event loop are the same
3270+ methods called by the ` yield ` and ` waitable-set.wait ` built-ins. Thus, the
3271+ main difference between stackful and stackless async is whether these
3272+ suspending operations are performed from an empty or non-empty core wasm
3273+ callstack (with the former allowing additional engine optimization).
32983274
32993275If a ` Task ` is not allowed to block (because it was created for a non-` async ` -
33003276typed function call and has not yet returned a value), ` YIELD ` is always a
@@ -3336,8 +3312,7 @@ class CallbackCode(IntEnum):
33363312 EXIT = 0
33373313 YIELD = 1
33383314 WAIT = 2
3339- POLL = 3
3340- MAX = 3
3315+ MAX = 2
33413316
33423317def unpack_callback_result (packed ):
33433318 code = packed & 0x f
@@ -3347,7 +3322,7 @@ def unpack_callback_result(packed):
33473322 waitable_set_index = packed >> 4
33483323 return (CallbackCode(code), waitable_set_index)
33493324```
3350- The ability to asynchronously wait, poll, yield and exit is thus available to
3325+ The ability to asynchronously wait, yield and exit is thus available to
33513326both the ` callback ` and non-` callback ` cases, making ` callback ` just an
33523327optimization to avoid allocating stacks for async languages that have avoided
33533328the need for stackful coroutines by design (e.g., ` async ` /` await ` in JS,
@@ -3878,26 +3853,22 @@ validation specifies:
38783853* ` $f ` is given type ` (func (param $si i32) (param $ptr i32) (result i32)) `
38793854* 🚟 - ` cancellable ` is allowed (otherwise it must be absent)
38803855
3881- Calling ` $f ` invokes the following function, which returns ` NONE ` ( ` 0 ` ) instead
3882- of blocking if there is no event available, and otherwise returns the event the
3883- same way as ` wait ` .
3856+ Calling ` $f ` invokes the following function, which either returns an event that
3857+ was pending on one of the waitables in the given waitable set ( the same way as
3858+ ` waitable-set.wait ` ) or, if there is none, returns ` 0 ` .
38843859``` python
38853860def canon_waitable_set_poll (cancellable , mem , thread , si , ptr ):
38863861 trap_if(not thread.task.inst.may_leave)
3887- trap_if(not thread.task.may_block())
38883862 wset = thread.task.inst.table.get(si)
38893863 trap_if(not isinstance (wset, WaitableSet))
3890- event = thread.task.poll_until(lambda : True , thread, wset, cancellable)
3864+ if thread.task.deliver_pending_cancel(cancellable):
3865+ event = (EventCode.TASK_CANCELLED , 0 , 0 )
3866+ elif not wset.has_pending_event():
3867+ event = (EventCode.NONE , 0 , 0 )
3868+ else :
3869+ event = wset.get_pending_event()
38913870 return unpack_event(mem, thread, ptr, event)
38923871```
3893- Even though ` waitable-set.poll ` doesn't block until the given waitable set has
3894- a pending event, ` poll_until ` does transitively perform a ` Thread.suspend `
3895- which allows the embedder to nondeterministically switch to executing another
3896- task (like ` thread.yield ` ). To avoid encouraging spin-waiting and to support
3897- hosts like browsers that require returning to the event loop for async I/O to
3898- resolve, a non-` async ` -typed function export that has not yet returned a value
3899- unconditionally traps if it transitively attempts to call ` poll ` .
3900-
39013872If ` cancellable ` is set, then ` waitable-set.poll ` will return whether the
39023873supertask has already or concurrently requested cancellation.
39033874` waitable-set.poll ` (and other cancellable operations) will only indicate
0 commit comments