1 ! Copyright (C) 2004, 2011 Slava Pestov.
2 ! Copyright (C) 2005 Mackenzie Straight.
3 ! See http://factorcode.org/license.txt for BSD license.
4 USING: accessors alien.private arrays assocs boxes combinators
5 continuations continuations.private deques dlists fry hashtables
6 heaps init kernel kernel.private math math.order namespaces
7 quotations sequences strings system ;
8 FROM: assocs => change-at ;
13 ! Wrap sub-primitives; we don't want them inlined into callers
14 ! since their behavior depends on what frames are on the callstack
15 : context ( -- context )
16 CONTEXT-OBJ-CONTEXT context-object ; inline
18 : set-context ( obj context -- obj' )
19 (set-context) ; inline
21 : start-context ( obj quot: ( obj -- * ) -- obj' )
22 (start-context) ; inline
24 : set-context-and-delete ( obj context -- * )
25 (set-context-and-delete) ; inline
27 : start-context-and-delete ( obj quot: ( obj -- * ) -- * )
28 (start-context-and-delete) ; inline
30 ! Context introspection
31 : namestack-for ( context -- namestack )
32 [ CONTEXT-OBJ-NAMESTACK ] dip context-object-for ;
34 : catchstack-for ( context -- catchstack )
35 [ CONTEXT-OBJ-CATCHSTACK ] dip context-object-for ;
37 : continuation-for ( context -- continuation )
44 } cleave <continuation> ;
48 SYMBOL: initial-thread
52 { quot callable initial: [ ] }
53 { exit-handler callable initial: [ ] }
59 { variables hashtable }
63 OBJ-CURRENT-THREAD special-object { thread } declare ; inline
65 : thread-continuation ( thread -- continuation )
66 context>> check-box value>> continuation-for ;
68 ! Thread-local storage
69 : tnamespace ( -- assoc )
70 self variables>> ; inline
72 : tget ( key -- value )
75 : tset ( value key -- )
78 : tchange ( ..a key quot: ( ..a value -- ..b newvalue ) -- ..b )
79 [ tnamespace ] dip change-at ; inline
81 : threads ( -- assoc )
82 OBJ-THREADS special-object { hashtable } declare ; inline
84 : thread-registered? ( thread -- ? )
89 : register-thread ( thread -- )
90 dup id>> threads set-at ;
92 : unregister-thread ( thread -- )
93 id>> threads delete-at ;
95 : set-self ( thread -- )
96 OBJ-CURRENT-THREAD set-special-object ; inline
100 : run-queue ( -- dlist )
101 OBJ-RUN-QUEUE special-object { dlist } declare ; inline
103 : sleep-queue ( -- heap )
104 OBJ-SLEEP-QUEUE special-object { min-heap } declare ; inline
106 : waiting-callbacks ( -- assoc )
107 OBJ-WAITING-CALLBACKS special-object { hashtable } declare ; inline
109 : new-thread ( quot name class -- thread )
113 \ thread counter >>id
114 H{ } clone >>variables
115 <box> >>context ; inline
117 : <thread> ( quot name -- thread )
118 \ thread new-thread ;
120 : resume ( thread -- )
121 f >>state run-queue push-front ;
123 : resume-now ( thread -- )
124 f >>state run-queue push-back ;
126 : resume-with ( obj thread -- )
127 f >>state 2array run-queue push-front ;
129 : sleep-time ( -- nanos/f )
131 { [ current-callback waiting-callbacks key? ] [ 0 ] }
132 { [ run-queue deque-empty? not ] [ 0 ] }
133 { [ sleep-queue heap-empty? ] [ f ] }
134 [ sleep-queue heap-peek nip nano-count [-] ]
137 : interrupt ( thread -- )
140 [ sleep-queue heap-delete ] when* f
141 ] change-sleep-entry dup resume
148 : schedule-sleep ( thread dt -- )
149 dupd sleep-queue heap-push* >>sleep-entry drop ;
151 : expire-sleep? ( -- ? )
152 sleep-queue dup heap-empty?
153 [ drop f ] [ heap-peek nip nano-count <= ] if ;
155 : expire-sleep ( thread -- )
156 f >>sleep-entry resume ;
158 : expire-sleep-loop ( -- )
160 [ sleep-queue heap-pop drop expire-sleep ]
171 GENERIC: (next) ( obj thread -- obj' )
175 [ context>> box> set-context ]
176 [ t >>runnable drop [start] start-context ] if ;
178 : (stop) ( obj thread -- * )
180 [ context>> box> set-context-and-delete ]
181 [ t >>runnable drop [start] start-context-and-delete ] if ;
183 : wake-up-callbacks ( -- )
184 current-callback waiting-callbacks delete-at*
185 [ resume-now ] [ drop ] if ;
187 : next ( -- obj thread )
191 dup array? [ first2 ] [ [ f ] dip ] if
198 self [ exit-handler>> call( -- ) ] [ unregister-thread ] bi
201 : suspend ( state -- obj )
203 [ context ] dip context>> >box
207 self resume f suspend drop ;
209 GENERIC: sleep-until ( n/f -- )
211 M: integer sleep-until
212 [ self ] dip schedule-sleep "sleep" suspend drop ;
215 drop "standby" suspend drop ;
217 GENERIC: sleep ( dt -- )
220 >integer nano-count + sleep-until ;
222 : (spawn) ( thread -- )
223 [ register-thread ] [ [ namestack ] dip resume-with ] bi ;
225 : spawn ( quot name -- thread )
226 <thread> [ (spawn) ] keep ;
228 : spawn-server ( quot name -- thread )
229 [ '[ _ loop ] ] dip spawn ;
231 : in-thread ( quot -- )
233 '[ _ set-datastack @ ]
234 "Thread" spawn drop ;
238 : init-thread-state ( -- )
239 H{ } clone OBJ-THREADS set-special-object
240 <dlist> OBJ-RUN-QUEUE set-special-object
241 <min-heap> OBJ-SLEEP-QUEUE set-special-object
242 H{ } clone OBJ-WAITING-CALLBACKS set-special-object ;
244 : init-initial-thread ( -- )
245 [ ] "Initial" <thread>
247 [ initial-thread set-global ]
252 : init-threads ( -- )
254 init-initial-thread ;
256 : wait-for-callback ( callback -- )
257 self swap waiting-callbacks set-at
258 "Callback return" suspend drop ;
262 [ init-threads ] "threads" add-startup-hook