@@ -358,22 +358,6 @@ def write(self, vs):
358358 assert (all (v == () for v in vs ))
359359 self .progress += len (vs )
360360
361- #### Context-Local Storage
362-
363- class ContextLocalStorage :
364- LENGTH = 1
365- array : list [int ]
366-
367- def __init__ (self ):
368- self .array = [0 ] * ContextLocalStorage .LENGTH
369-
370- def set (self , i , v ):
371- assert (types_match_values (['i32' ], [v ]))
372- self .array [i ] = v
373-
374- def get (self , i ):
375- return self .array [i ]
376-
377361#### Waitable State
378362
379363class EventCode (IntEnum ):
@@ -475,7 +459,6 @@ class State(Enum):
475459 supertask : Optional [Task ]
476460 on_resolve : Callable [[Optional [list [any ]]], None ]
477461 num_borrows : int
478- context : ContextLocalStorage
479462
480463 def __init__ (self , opts , inst , ft , supertask , on_resolve ):
481464 self .state = Task .State .INITIAL
@@ -485,7 +468,6 @@ def __init__(self, opts, inst, ft, supertask, on_resolve):
485468 self .supertask = supertask
486469 self .on_resolve = on_resolve
487470 self .num_borrows = 0
488- self .context = ContextLocalStorage ()
489471
490472 async def enter (self , thread ):
491473 self .trap_if_on_the_stack (self .inst )
@@ -529,6 +511,7 @@ async def wait_sync(self, thread, awaitable) -> None:
529511 if awaitable .done () and not DETERMINISTIC_PROFILE and random .randint (0 ,1 ):
530512 return
531513 assert (self .inst .interruptible .is_set ())
514+ # TODO: only clear interruptible if thread == task.main_thread
532515 self .inst .interruptible .clear ()
533516 if await thread .suspend (awaitable ) == Cancelled .TRUE :
534517 assert (self .state == Task .State .INITIAL )
@@ -887,13 +870,19 @@ def drop(self):
887870
888871class Thread :
889872 task : Task
873+ index : int
874+ context : list [int ]
890875 awaitable : Optional [Awaitable ]
891876 on_resume : Optional [asyncio .Future ]
892877 on_suspend_or_exit : Optional [asyncio .Future ]
893878 returned : bool
894879
880+ CONTEXT_LENGTH = 1
881+
895882 def __init__ (self , task , coro ):
896883 self .task = task
884+ self .index = task .inst .table .add (self )
885+ self .context = [0 ] * Thread .CONTEXT_LENGTH
897886 self .awaitable = None
898887 self .on_resume = asyncio .Future ()
899888 self .on_suspend_or_exit = None
@@ -903,6 +892,7 @@ async def async_impl():
903892 self .on_resume = None
904893 await coro
905894 self .on_suspend_or_exit .set_result (None )
895+ self .task .inst .table .remove (self .index )
906896 self .returned = True
907897 asyncio .create_task (async_impl ())
908898
@@ -930,6 +920,30 @@ async def suspend(self, awaitable) -> Cancelled:
930920 self .on_resume = None
931921 return cancelled
932922
923+ async def switch (self , other : Thread ) -> Cancelled :
924+ assert (not self .awaitable and not other .awaitable )
925+ assert (self .on_suspend_or_exit and not other .on_suspend_or_exit )
926+ other .on_suspend_or_exit = self .on_suspend_or_exit
927+ self .on_suspend_or_exit = None
928+ other .on_resume .set_result (Cancelled .FALSE )
929+ assert (not self .on_resume )
930+ self .on_resume = asyncio .Future ()
931+ cancelled = await self .on_resume
932+ self .on_resume = None
933+ return cancelled
934+
935+ def yield_ (self , other : Thread ):
936+ # deterministically switch to other, but leave this thread unblocked
937+ TODO
938+
939+ def unblock (self , other : Thread ):
940+ # unblock other, but deterministically keep running here
941+ TODO
942+
943+ def wait (self ) -> Cancelled :
944+ # perform just the first half of switch
945+ TODO
946+
933947#### Store State / Embedding API
934948
935949class Store :
@@ -2108,19 +2122,76 @@ async def canon_resource_rep(rt, thread, i):
21082122 trap_if (h .rt is not rt )
21092123 return [h .rep ]
21102124
2125+ ### 🧵 `canon thread.index`
2126+
2127+ async def canon_thread_index (shared , thread ):
2128+ assert (not shared )
2129+ return [thread .index ]
2130+
2131+ ### 🧵 `canon thread.new_indirect`
2132+
2133+ async def canon_thread_new_indirect (shared , ft , ftbl , thread , i , c ):
2134+ assert (not shared )
2135+ inst = thread .task .inst
2136+ trap_if (not inst .may_leave )
2137+ f = ftbl .get (i )
2138+ trap_if (f is None )
2139+ trap_if (f .type != ft )
2140+ thread = Thread (thread .task , f (c ))
2141+ return [thread .index ]
2142+
2143+ ### 🧵 `canon thread.switch`
2144+
2145+ async def canon_thread_switch (shared , thread , i ):
2146+ assert (not shared )
2147+ trap_if (not thread .task .inst .may_leave )
2148+ other = thread .task .inst .table .get (i )
2149+ trap_if (not isinstance (other , Thread ))
2150+ cancelled = await thread .switch (other )
2151+ return [ 1 if cancelled else 0 ]
2152+
2153+ ### 🧵 `canon thread.yield`
2154+
2155+ async def canon_thread_yield (shared , thread , i ):
2156+ assert (not shared )
2157+ trap_if (not thread .task .inst .may_leave )
2158+ other = thread .task .inst .table .get (i )
2159+ trap_if (not isinstance (other , Thread ))
2160+ other .yield_ (other )
2161+ return []
2162+
2163+ ### 🧵 `canon thread.unblock`
2164+
2165+ async def canon_thread_unblock (shared , thread , i ):
2166+ trap_if (not thread .task .inst .may_leave )
2167+ other = thread .task .inst .table .get (i )
2168+ trap_if (not isinstance (other , Thread ))
2169+ thread .unblock ()
2170+ return []
2171+
2172+ ### 🧵 `canon thread.wait`
2173+
2174+ async def canon_thread_wait (shared , thread , i ):
2175+ assert (not shared )
2176+ trap_if (not thread .task .inst .may_leave )
2177+ other = thread .task .inst .table .get (i )
2178+ trap_if (not isinstance (other , Thread ))
2179+ cancelled = await thread .suspend ()
2180+ return [ 1 if cancelled else 0 ]
2181+
21112182### 🔀 `canon context.get`
21122183
21132184async def canon_context_get (t , i , thread ):
21142185 assert (t == 'i32' )
2115- assert (i < ContextLocalStorage . LENGTH )
2116- return [thread .task . context . get ( i ) ]
2186+ assert (i < Thread . CONTEXT_LENGTH )
2187+ return [thread .context [ i ] ]
21172188
21182189### 🔀 `canon context.set`
21192190
21202191async def canon_context_set (t , i , thread , v ):
21212192 assert (t == 'i32' )
2122- assert (i < ContextLocalStorage . LENGTH )
2123- thread .task . context . set ( i , v )
2193+ assert (i < Thread . CONTEXT_LENGTH )
2194+ thread .context [ i ] = v
21242195 return []
21252196
21262197### 🔀 `canon backpressure.set`
0 commit comments