@@ -140,7 +140,7 @@ class Store:
140140 random.shuffle(self .pending)
141141 for thread in self .pending:
142142 if thread.ready():
143- thread.resume()
143+ thread.resume(Cancelled. FALSE )
144144 return
145145```
146146The ` Store.tick ` method does not have an analogue in Core WebAssembly and
@@ -617,14 +617,14 @@ ability to switch stacks. In any case, the use of `threading.Thread` is
617617encapsulated by the ` Thread ` class so that the rest of the Canonical ABI can
618618simply use ` suspend ` , ` resume ` , etc.
619619
620- When a ` Thread ` is suspended and then resumed, it receives a ` SuspendResult `
620+ When a ` Thread ` is suspended and then resumed, it receives a ` Cancelled `
621621value indicating whether the caller has cooperatively requested that the thread
622622cancel itself which is communicated to Core WebAssembly with the following
623623integer values:
624624``` python
625- class SuspendResult (IntEnum ):
626- NOT_CANCELLED = 0
627- CANCELLED = 1
625+ class Cancelled (IntEnum ):
626+ FALSE = 0
627+ TRUE = 1
628628```
629629
630630Introducing the ` Thread ` class in chunks, a ` Thread ` has the following fields
@@ -642,7 +642,7 @@ class Thread:
642642 parent_lock: Optional[threading.Lock]
643643 ready_func: Optional[Callable[[], bool ]]
644644 cancellable: bool
645- suspend_result: Optional[SuspendResult]
645+ cancelled: Cancelled
646646 index: Optional[int ]
647647 context: list[int ]
648648
@@ -678,15 +678,13 @@ immediately blocked `acquire()`ing `fiber_lock` (which will be `release()`ed by
678678 self .parent_lock = None
679679 self .ready_func = None
680680 self .cancellable = False
681- self .suspend_result = None
681+ self .cancelled = Cancelled. FALSE
682682 self .index = None
683683 self .context = [0 ] * Thread.CONTEXT_LENGTH
684684 def fiber_func ():
685685 self .fiber_lock.acquire()
686- assert (self .running() and self .suspend_result == SuspendResult.NOT_CANCELLED )
687- self .suspend_result = None
688- thread_func(self )
689686 assert (self .running())
687+ thread_func(self )
690688 self .task.thread_stop(self )
691689 if self .index is not None :
692690 self .task.inst.threads.remove(self .index)
@@ -721,7 +719,7 @@ resumed thread will `release()` when it suspends or exits.
721719When a thread calls ` Thread.suspend ` , it indicates whether it is able to handle
722720cancellation. This information is stored in the ` cancellable ` field which is
723721used by ` Task.request_cancellation ` (defined below) to only ` resume ` with
724- ` SuspendResult.CANCELLED ` when the thread expects it.
722+ ` Cancelled.TRUE ` when the thread expects it.
725723
726724Lastly, several ` Thread ` methods below will set the ` ready_func ` and add the
727725` Thread ` to the ` Store.pending ` list so that ` Store.tick ` will call ` resume `
@@ -732,34 +730,28 @@ when the `ready_func` returns `True`. Once `Thread.resume` is called, the
732730Given the above, ` Thread.resume ` and ` Thread.suspend ` can be defined
733731complementarily using ` parent_lock ` and ` fiber_lock ` as follows:
734732``` python
735- def resume (self , suspend_result = SuspendResult. NOT_CANCELLED ):
736- assert (not self .running() and self .suspend_result is None )
733+ def resume (self , cancelled ):
734+ assert (not self .running() and ( self .cancellable or not cancelled) )
737735 if self .ready_func:
738- assert (suspend_result == SuspendResult. CANCELLED or self .ready_func())
736+ assert (cancelled or self .ready_func())
739737 self .ready_func = None
740738 self .task.inst.store.pending.remove(self )
741- assert (self .cancellable or suspend_result == SuspendResult. NOT_CANCELLED )
742- self .suspend_result = suspend_result
739+ assert (self .cancellable or not cancelled )
740+ self .cancelled = cancelled
743741 self .parent_lock = threading.Lock()
744742 self .parent_lock.acquire()
745743 self .fiber_lock.release()
746744 self .parent_lock.acquire()
747745 self .parent_lock = None
748746 assert (not self .running())
749747
750- def suspend (self , cancellable ) -> SuspendResult:
751- assert (self .task.may_block())
752- assert (self .running() and not self .cancellable and self .suspend_result is None )
748+ def suspend (self , cancellable ) -> Cancelled:
749+ assert (self .running() and self .task.may_block())
753750 self .cancellable = cancellable
754751 self .parent_lock.release()
755752 self .fiber_lock.acquire()
756- assert (self .running())
757- self .cancellable = False
758- suspend_result = self .suspend_result
759- self .suspend_result = None
760- assert (suspend_result is not None )
761- assert (cancellable or suspend_result == SuspendResult.NOT_CANCELLED )
762- return suspend_result
753+ assert (self .running() and (cancellable or not self .cancelled))
754+ return self .cancelled
763755```
764756
765757The ` Thread.resume_later ` method is called by ` canon_thread_resume_later ` below
@@ -776,11 +768,10 @@ in the near future:
776768The ` Thread.suspend_until ` method is used by a multiple internal callers below
777769to specify a custom ` ready_func ` that is polled by ` Store.tick ` :
778770``` python
779- def suspend_until (self , ready_func , cancellable = False ) -> SuspendResult:
780- assert (self .task.may_block())
781- assert (self .running())
771+ def suspend_until (self , ready_func , cancellable = False ) -> Cancelled:
772+ assert (self .running() and self .task.may_block())
782773 if ready_func() and not DETERMINISTIC_PROFILE and random.randint(0 ,1 ):
783- return SuspendResult. NOT_CANCELLED
774+ return Cancelled. FALSE
784775 self .ready_func = ready_func
785776 self .task.inst.store.pending.append(self )
786777 return self .suspend(cancellable)
@@ -801,32 +792,26 @@ of internal `thread.switch-to`s before suspending, the `async`-lowered caller
801792resumes execution immediately (as if there were no ` thread.switch-to ` and
802793[ Asyncify] was used to emulate stack switching instead).
803794``` python
804- def switch_to (self , cancellable , other : Thread) -> SuspendResult:
805- assert (self .running() and not self .cancellable and self .suspend_result is None )
806- assert (other.suspended() and other.suspend_result is None )
795+ def switch_to (self , cancellable , other : Thread) -> Cancelled:
796+ assert (self .running() and other.suspended())
807797 self .cancellable = cancellable
808- other.suspend_result = SuspendResult. NOT_CANCELLED
798+ other.cancelled = Cancelled. FALSE
809799 assert (self .parent_lock and not other.parent_lock)
810800 other.parent_lock = self .parent_lock
811801 self .parent_lock = None
812802 assert (not self .running() and other.running())
813803 other.fiber_lock.release()
814804 self .fiber_lock.acquire()
815- assert (self .running())
816- self .cancellable = False
817- suspend_result = self .suspend_result
818- self .suspend_result = None
819- assert (suspend_result is not None )
820- assert (cancellable or suspend_result == SuspendResult.NOT_CANCELLED )
821- return suspend_result
805+ assert (self .running() and (cancellable or not self .cancelled))
806+ return self .cancelled
822807```
823808
824809Lastly, the ` Thread.yield_to ` method is used by ` canon_thread_yield_to ` below
825810to switch execution to some other thread (like ` Thread.switch_to ` ), but leave
826811the current thread ` ready ` instead of ` suspended ` .
827812``` python
828- def yield_to (self , cancellable , other : Thread) -> SuspendResult :
829- assert (not self .ready_func )
813+ def yield_to (self , cancellable , other : Thread) -> Cancelled :
814+ assert (self .running() and other.suspended() )
830815 self .ready_func = lambda : True
831816 self .task.inst.store.pending.append(self )
832817 return self .switch_to(cancellable, other)
@@ -1069,9 +1054,9 @@ exports.
10691054 if has_backpressure() or self .inst.num_waiting_to_enter > 0 :
10701055 self .state = Task.State.BACKPRESSURE
10711056 self .inst.num_waiting_to_enter += 1
1072- result = thread.suspend_until(lambda : not has_backpressure(), cancellable = True )
1057+ cancelled = thread.suspend_until(lambda : not has_backpressure(), cancellable = True )
10731058 self .inst.num_waiting_to_enter -= 1
1074- if result == SuspendResult. CANCELLED :
1059+ if cancelled :
10751060 self .cancel()
10761061 return False
10771062 self .state = Task.State.UNRESOLVED
@@ -1121,15 +1106,15 @@ multiple), giving the thread the chance to handle cancellation promptly
11211106 if self .state == Task.State.BACKPRESSURE :
11221107 assert (len (self .threads) == 1 )
11231108 self .state = Task.State.CANCEL_DELIVERED
1124- self .threads[0 ].resume(SuspendResult. CANCELLED )
1109+ self .threads[0 ].resume(Cancelled. TRUE )
11251110 return
11261111 assert (self .state == Task.State.UNRESOLVED )
11271112 if not self .needs_exclusive() or not self .inst.exclusive or self .inst.exclusive is self :
11281113 random.shuffle(self .threads)
11291114 for thread in self .threads:
11301115 if thread.cancellable:
11311116 self .state = Task.State.CANCEL_DELIVERED
1132- thread.resume(SuspendResult. CANCELLED )
1117+ thread.resume(Cancelled. TRUE )
11331118 return
11341119 self .state = Task.State.PENDING_CANCEL
11351120```
@@ -1154,28 +1139,28 @@ by `Task.deliver_pending_cancel`, which is checked at all cancellation points:
11541139The following ` Task ` methods wrap corresponding ` Thread ` methods after first
11551140delivering any pending cancellations set by ` Task.request_cancellation ` :
11561141``` python
1157- def suspend (self , thread , cancellable ) -> SuspendResult :
1142+ def suspend (self , thread , cancellable ) -> Cancelled :
11581143 assert (thread in self .threads and thread.task is self )
11591144 if self .deliver_pending_cancel(cancellable):
1160- return SuspendResult. CANCELLED
1145+ return Cancelled. TRUE
11611146 return thread.suspend(cancellable)
11621147
1163- def suspend_until (self , ready_func , thread , cancellable ) -> SuspendResult :
1148+ def suspend_until (self , ready_func , thread , cancellable ) -> Cancelled :
11641149 assert (thread in self .threads and thread.task is self )
11651150 if self .deliver_pending_cancel(cancellable):
1166- return SuspendResult. CANCELLED
1151+ return Cancelled. TRUE
11671152 return thread.suspend_until(ready_func, cancellable)
11681153
1169- def switch_to (self , thread , cancellable , other_thread ) -> SuspendResult :
1154+ def switch_to (self , thread , cancellable , other_thread ) -> Cancelled :
11701155 assert (thread in self .threads and thread.task is self )
11711156 if self .deliver_pending_cancel(cancellable):
1172- return SuspendResult. CANCELLED
1157+ return Cancelled. TRUE
11731158 return thread.switch_to(cancellable, other_thread)
11741159
1175- def yield_to (self , thread , cancellable , other_thread ) -> SuspendResult :
1160+ def yield_to (self , thread , cancellable , other_thread ) -> Cancelled :
11761161 assert (thread in self .threads and thread.task is self )
11771162 if self .deliver_pending_cancel(cancellable):
1178- return SuspendResult. CANCELLED
1163+ return Cancelled. TRUE
11791164 return thread.yield_to(cancellable, other_thread)
11801165```
11811166
@@ -1192,9 +1177,9 @@ trap if another task tries to drop the waitable set being used.
11921177 def ready_and_has_event ():
11931178 return ready_func() and wset.has_pending_event()
11941179 match self .suspend_until(ready_and_has_event, thread, cancellable):
1195- case SuspendResult. CANCELLED :
1180+ case Cancelled. TRUE :
11961181 event = (EventCode.TASK_CANCELLED , 0 , 0 )
1197- case SuspendResult. NOT_CANCELLED :
1182+ case Cancelled. FALSE :
11981183 event = wset.get_pending_event()
11991184 wset.num_waiting -= 1
12001185 return event
@@ -1208,9 +1193,9 @@ another task (or not).
12081193 def yield_until (self , ready_func , thread , cancellable ) -> EventTuple:
12091194 assert (thread in self .threads and thread.task is self )
12101195 match self .suspend_until(ready_func, thread, cancellable):
1211- case SuspendResult. CANCELLED :
1196+ case Cancelled. TRUE :
12121197 return (EventCode.TASK_CANCELLED , 0 , 0 )
1213- case SuspendResult. NOT_CANCELLED :
1198+ case Cancelled. FALSE :
12141199 return (EventCode.NONE , 0 , 0 )
12151200```
12161201
@@ -3466,7 +3451,7 @@ the callee is still running concurrently in the `Thread` created here (see
34663451the [ concurrency explainer] for more on this).
34673452``` python
34683453 thread = Thread(task, thread_func)
3469- thread.resume()
3454+ thread.resume(Cancelled. FALSE )
34703455 return task
34713456```
34723457
@@ -4644,10 +4629,10 @@ def canon_thread_switch_to(cancellable, thread, i):
46444629 trap_if(not thread.task.inst.may_leave)
46454630 other_thread = thread.task.inst.threads.get(i)
46464631 trap_if(not other_thread.suspended())
4647- suspend_result = thread.task.switch_to(thread, cancellable, other_thread)
4648- return [suspend_result ]
4632+ cancelled = thread.task.switch_to(thread, cancellable, other_thread)
4633+ return [cancelled ]
46494634```
4650- If ` cancellable ` is set, then ` thread.switch-to ` will return a ` SuspendResult `
4635+ If ` cancellable ` is set, then ` thread.switch-to ` will return a ` Cancelled `
46514636value to indicate whether the supertask has already or concurrently requested
46524637cancellation. ` thread.switch-to ` (and other cancellable operations) will only
46534638indicate cancellation once and thus, if a caller is not prepared to propagate
@@ -4671,13 +4656,13 @@ calling component.
46714656def canon_thread_suspend (cancellable , thread ):
46724657 trap_if(not thread.task.inst.may_leave)
46734658 trap_if(not thread.task.may_block())
4674- suspend_result = thread.task.suspend(thread, cancellable)
4675- return [suspend_result ]
4659+ cancelled = thread.task.suspend(thread, cancellable)
4660+ return [cancelled ]
46764661```
46774662A non-` async ` -typed function export that has not yet returned a value traps if
46784663it transitively attempts to call ` thread.suspend ` .
46794664
4680- If ` cancellable ` is set, then ` thread.suspend ` will return a ` SuspendResult `
4665+ If ` cancellable ` is set, then ` thread.suspend ` will return a ` Cancelled `
46814666value to indicate whether the supertask has already or concurrently requested
46824667cancellation. ` thread.suspend ` (and other cancellable operations) will only
46834668indicate cancellation once and thus, if a caller is not prepared to propagate
@@ -4729,10 +4714,10 @@ def canon_thread_yield_to(cancellable, thread, i):
47294714 trap_if(not thread.task.inst.may_leave)
47304715 other_thread = thread.task.inst.threads.get(i)
47314716 trap_if(not other_thread.suspended())
4732- suspend_result = thread.task.yield_to(thread, cancellable, other_thread)
4733- return [suspend_result ]
4717+ cancelled = thread.task.yield_to(thread, cancellable, other_thread)
4718+ return [cancelled ]
47344719```
4735- If ` cancellable ` is set, then ` thread.yield-to ` will return a ` SuspendResult `
4720+ If ` cancellable ` is set, then ` thread.yield-to ` will return a ` Cancelled `
47364721value indicating whether the supertask has already or concurrently requested
47374722cancellation. ` thread.yield-to ` (and other cancellable operations) will only
47384723indicate cancellation once and thus, if a caller is not prepared to propagate
@@ -4758,13 +4743,13 @@ other threads in a cooperative setting.
47584743def canon_thread_yield (cancellable , thread ):
47594744 trap_if(not thread.task.inst.may_leave)
47604745 if not thread.task.may_block():
4761- return [SuspendResult. NOT_CANCELLED ]
4746+ return [Cancelled. FALSE ]
47624747 event_code,_,_ = thread.task.yield_until(lambda : True , thread, cancellable)
47634748 match event_code:
47644749 case EventCode.NONE :
4765- return [SuspendResult. NOT_CANCELLED ]
4750+ return [Cancelled. FALSE ]
47664751 case EventCode.TASK_CANCELLED :
4767- return [SuspendResult. CANCELLED ]
4752+ return [Cancelled. TRUE ]
47684753```
47694754If a non-` async ` -typed function export that has not yet returned a value
47704755transitively calls ` thread.yield ` , it returns immediately without blocking
@@ -4777,7 +4762,7 @@ Even though `yield_until` passes `lambda: True` as the condition it is waiting
47774762for, ` yield_until ` does transitively peform a ` Thread.suspend ` which allows
47784763the embedder to nondeterministically switch to executing another thread.
47794764
4780- If ` cancellable ` is set, then ` thread.yield ` will return a ` SuspendResult `
4765+ If ` cancellable ` is set, then ` thread.yield ` will return a ` Cancelled `
47814766value indicating whether the supertask has already or concurrently requested
47824767cancellation. ` thread.yield ` (and other cancellable operations) will only
47834768indicate cancellation once and thus, if a caller is not prepared to propagate
0 commit comments