| 
									
										
										
										
											2008-02-18 06:07:40 -05:00
										 |  |  | ! Copyright (C) 2004, 2008 Slava Pestov. | 
					
						
							|  |  |  | ! Copyright (C) 2005 Mackenzie Straight. | 
					
						
							|  |  |  | ! See http://factorcode.org/license.txt for BSD license. | 
					
						
							| 
									
										
										
										
											2008-02-18 08:30:16 -05:00
										 |  |  | IN: threads | 
					
						
							| 
									
										
										
										
											2008-02-18 06:07:40 -05:00
										 |  |  | USING: arrays hashtables heaps kernel kernel.private math | 
					
						
							|  |  |  | namespaces sequences vectors continuations continuations.private | 
					
						
							| 
									
										
										
										
											2008-02-19 15:38:02 -05:00
										 |  |  | dlists assocs system combinators debugger prettyprint io init | 
					
						
							|  |  |  | boxes ;
 | 
					
						
							| 
									
										
										
										
											2008-02-18 06:07:40 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  | SYMBOL: initial-thread | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | TUPLE: thread | 
					
						
							| 
									
										
										
										
											2008-02-21 00:13:31 -05:00
										 |  |  | name quot error-handler exit-handler | 
					
						
							|  |  |  | id | 
					
						
							| 
									
										
										
										
											2008-02-19 15:38:02 -05:00
										 |  |  | continuation state | 
					
						
							| 
									
										
										
										
											2008-02-21 20:12:37 -05:00
										 |  |  | mailbox variables sleep-entry ;
 | 
					
						
							| 
									
										
										
										
											2008-02-18 06:07:40 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  | : self ( -- thread ) 40 getenv ; inline
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ! Thread-local storage | 
					
						
							| 
									
										
										
										
											2008-02-18 17:20:18 -05:00
										 |  |  | : tnamespace ( -- assoc )
 | 
					
						
							|  |  |  |     self dup thread-variables | 
					
						
							|  |  |  |     [ ] [ H{ } clone dup rot set-thread-variables ] ?if ;
 | 
					
						
							| 
									
										
										
										
											2008-02-18 06:07:40 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-02-18 17:20:18 -05:00
										 |  |  | : tget ( key -- value )
 | 
					
						
							|  |  |  |     self thread-variables at ;
 | 
					
						
							| 
									
										
										
										
											2008-02-18 06:07:40 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-02-18 17:20:18 -05:00
										 |  |  | : tset ( value key -- )
 | 
					
						
							|  |  |  |     tnamespace set-at ;
 | 
					
						
							| 
									
										
										
										
											2008-02-18 06:07:40 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-02-18 17:20:18 -05:00
										 |  |  | : tchange ( key quot -- )
 | 
					
						
							|  |  |  |     tnamespace change-at ; inline
 | 
					
						
							| 
									
										
										
										
											2008-02-18 06:07:40 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-02-18 17:20:18 -05:00
										 |  |  | : threads 41 getenv ;
 | 
					
						
							| 
									
										
										
										
											2008-02-18 06:07:40 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  | threads global [ H{ } assoc-like ] change-at
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-02-18 17:20:18 -05:00
										 |  |  | : thread ( id -- thread ) threads at ;
 | 
					
						
							| 
									
										
										
										
											2008-02-18 06:07:40 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-02-21 00:13:31 -05:00
										 |  |  | : thread-registered? ( thread -- ? )
 | 
					
						
							|  |  |  |     thread-id threads key? ;
 | 
					
						
							| 
									
										
										
										
											2008-02-18 06:07:40 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  | : check-unregistered | 
					
						
							|  |  |  |     dup thread-registered? | 
					
						
							| 
									
										
										
										
											2008-02-21 00:13:31 -05:00
										 |  |  |     [ "Thread already stopped" throw ] when ;
 | 
					
						
							| 
									
										
										
										
											2008-02-18 06:07:40 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  | : check-registered | 
					
						
							|  |  |  |     dup thread-registered? | 
					
						
							| 
									
										
										
										
											2008-02-21 00:13:31 -05:00
										 |  |  |     [ "Thread is not running" throw ] unless ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | <PRIVATE
 | 
					
						
							| 
									
										
										
										
											2008-02-18 06:07:40 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  | : register-thread ( thread -- )
 | 
					
						
							| 
									
										
										
										
											2008-02-21 00:13:31 -05:00
										 |  |  |     check-unregistered dup thread-id threads set-at ;
 | 
					
						
							| 
									
										
										
										
											2008-02-18 06:07:40 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  | : unregister-thread ( thread -- )
 | 
					
						
							| 
									
										
										
										
											2008-02-21 00:13:31 -05:00
										 |  |  |     check-registered thread-id threads delete-at ;
 | 
					
						
							| 
									
										
										
										
											2008-02-18 06:07:40 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  | : set-self ( thread -- ) 40 setenv ; inline
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-02-18 08:30:16 -05:00
										 |  |  | PRIVATE>
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-02-18 06:07:40 -05:00
										 |  |  | : <thread> ( quot name error-handler -- thread )
 | 
					
						
							| 
									
										
										
										
											2008-02-21 00:13:31 -05:00
										 |  |  |     \ thread counter <box> [ ] { | 
					
						
							| 
									
										
										
										
											2008-02-18 06:07:40 -05:00
										 |  |  |         set-thread-quot | 
					
						
							|  |  |  |         set-thread-name | 
					
						
							|  |  |  |         set-thread-error-handler | 
					
						
							|  |  |  |         set-thread-id | 
					
						
							| 
									
										
										
										
											2008-02-19 15:38:02 -05:00
										 |  |  |         set-thread-continuation | 
					
						
							| 
									
										
										
										
											2008-02-21 00:13:31 -05:00
										 |  |  |         set-thread-exit-handler | 
					
						
							| 
									
										
										
										
											2008-02-18 06:07:40 -05:00
										 |  |  |     } \ thread construct ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-02-18 17:20:18 -05:00
										 |  |  | : run-queue 42 getenv ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | : sleep-queue 43 getenv ;
 | 
					
						
							| 
									
										
										
										
											2008-02-18 06:07:40 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  | : resume ( thread -- )
 | 
					
						
							| 
									
										
										
										
											2008-02-25 07:31:18 -05:00
										 |  |  |     f over set-thread-state | 
					
						
							| 
									
										
										
										
											2008-02-18 17:20:18 -05:00
										 |  |  |     check-registered run-queue push-front ;
 | 
					
						
							| 
									
										
										
										
											2008-02-18 06:07:40 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-02-21 02:25:08 -05:00
										 |  |  | : resume-now ( thread -- )
 | 
					
						
							| 
									
										
										
										
											2008-02-25 07:31:18 -05:00
										 |  |  |     f over set-thread-state | 
					
						
							| 
									
										
										
										
											2008-02-21 02:25:08 -05:00
										 |  |  |     check-registered run-queue push-back ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-02-18 06:07:40 -05:00
										 |  |  | : resume-with ( obj thread -- )
 | 
					
						
							| 
									
										
										
										
											2008-02-25 07:31:18 -05:00
										 |  |  |     f over set-thread-state | 
					
						
							| 
									
										
										
										
											2008-02-18 17:20:18 -05:00
										 |  |  |     check-registered 2array run-queue push-front ;
 | 
					
						
							| 
									
										
										
										
											2008-02-18 06:07:40 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-02-25 17:48:11 -05:00
										 |  |  | : sleep-time ( -- ms/f )
 | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         { [ run-queue dlist-empty? not ] [ 0 ] } | 
					
						
							|  |  |  |         { [ sleep-queue heap-empty? ] [ f ] } | 
					
						
							|  |  |  |         { [ t ] [ sleep-queue heap-peek nip millis [-] ] } | 
					
						
							|  |  |  |     } cond ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-02-18 06:07:40 -05:00
										 |  |  | <PRIVATE
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | : schedule-sleep ( thread ms -- )
 | 
					
						
							| 
									
										
										
										
											2008-02-21 20:12:37 -05:00
										 |  |  |     >r check-registered dup r> sleep-queue heap-push* | 
					
						
							|  |  |  |     swap set-thread-sleep-entry ;
 | 
					
						
							| 
									
										
										
										
											2008-02-18 06:07:40 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-02-21 20:12:37 -05:00
										 |  |  | : expire-sleep? ( heap -- ? )
 | 
					
						
							| 
									
										
										
										
											2008-02-18 06:07:40 -05:00
										 |  |  |     dup heap-empty? | 
					
						
							|  |  |  |     [ drop f ] [ heap-peek nip millis <= ] if ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-02-21 20:12:37 -05:00
										 |  |  | : expire-sleep ( thread -- )
 | 
					
						
							|  |  |  |     f over set-thread-sleep-entry resume ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | : expire-sleep-loop ( -- )
 | 
					
						
							| 
									
										
										
										
											2008-02-18 17:20:18 -05:00
										 |  |  |     sleep-queue | 
					
						
							| 
									
										
										
										
											2008-02-21 20:12:37 -05:00
										 |  |  |     [ dup expire-sleep? ] | 
					
						
							|  |  |  |     [ dup heap-pop drop expire-sleep ] | 
					
						
							|  |  |  |     [ ] while
 | 
					
						
							| 
									
										
										
										
											2008-02-18 06:07:40 -05:00
										 |  |  |     drop ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-02-25 17:48:11 -05:00
										 |  |  | : next ( -- * )
 | 
					
						
							| 
									
										
										
										
											2008-02-21 20:12:37 -05:00
										 |  |  |     expire-sleep-loop | 
					
						
							| 
									
										
										
										
											2008-02-25 17:48:11 -05:00
										 |  |  |     run-queue dup dlist-empty? [ | 
					
						
							|  |  |  |         ! We should never be in a state where the only threads | 
					
						
							|  |  |  |         ! are sleeping; the I/O wait thread is always runnable. | 
					
						
							|  |  |  |         ! However, if it dies, we handle this case | 
					
						
							|  |  |  |         ! semi-gracefully. | 
					
						
							|  |  |  |         !
 | 
					
						
							|  |  |  |         ! And if sleep-time outputs f, there are no sleeping | 
					
						
							|  |  |  |         ! threads either... so WTF. | 
					
						
							|  |  |  |         drop sleep-time [ die 0 ] unless* (sleep) next | 
					
						
							|  |  |  |     ] [ | 
					
						
							|  |  |  |         pop-back | 
					
						
							|  |  |  |         dup array? [ first2 ] [ f swap ] if dup set-self | 
					
						
							|  |  |  |         f over set-thread-state | 
					
						
							|  |  |  |         thread-continuation box> | 
					
						
							|  |  |  |         continue-with
 | 
					
						
							|  |  |  |     ] if ;
 | 
					
						
							| 
									
										
										
										
											2008-02-18 06:07:40 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  | PRIVATE>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | : stop ( -- )
 | 
					
						
							| 
									
										
										
										
											2008-02-21 00:13:31 -05:00
										 |  |  |     self dup thread-exit-handler call
 | 
					
						
							|  |  |  |     unregister-thread next ;
 | 
					
						
							| 
									
										
										
										
											2008-02-18 06:07:40 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-02-19 15:38:02 -05:00
										 |  |  | : suspend ( quot state -- obj )
 | 
					
						
							| 
									
										
										
										
											2008-02-18 06:07:40 -05:00
										 |  |  |     [ | 
					
						
							| 
									
										
										
										
											2008-02-19 15:38:02 -05:00
										 |  |  |         self thread-continuation >box | 
					
						
							|  |  |  |         self set-thread-state | 
					
						
							|  |  |  |         self swap call next | 
					
						
							|  |  |  |     ] callcc1 2nip ; inline
 | 
					
						
							| 
									
										
										
										
											2008-02-18 06:07:40 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-02-25 07:31:18 -05:00
										 |  |  | : yield ( -- ) [ resume ] f suspend drop ;
 | 
					
						
							| 
									
										
										
										
											2008-02-21 20:12:37 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-02-25 07:31:18 -05:00
										 |  |  | GENERIC: sleep-until ( time/f -- )
 | 
					
						
							| 
									
										
										
										
											2008-02-22 00:47:06 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-02-25 07:31:18 -05:00
										 |  |  | M: integer sleep-until | 
					
						
							|  |  |  |     [ schedule-sleep ] curry "sleep" suspend drop ;
 | 
					
						
							| 
									
										
										
										
											2008-02-22 00:47:06 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-02-25 07:31:18 -05:00
										 |  |  | M: f sleep-until | 
					
						
							|  |  |  |     drop [ drop ] "interrupt" suspend drop ;
 | 
					
						
							| 
									
										
										
										
											2008-02-22 00:47:06 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-02-25 07:31:18 -05:00
										 |  |  | GENERIC: sleep ( ms -- )
 | 
					
						
							| 
									
										
										
										
											2008-02-22 00:47:06 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-02-25 07:31:18 -05:00
										 |  |  | M: real sleep | 
					
						
							|  |  |  |     millis + >integer sleep-until ;
 | 
					
						
							| 
									
										
										
										
											2008-02-21 20:12:37 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  | : interrupt ( thread -- )
 | 
					
						
							| 
									
										
										
										
											2008-02-25 07:31:18 -05:00
										 |  |  |     dup thread-state [ | 
					
						
							| 
									
										
										
										
											2008-02-21 21:57:41 -05:00
										 |  |  |         dup thread-sleep-entry [ sleep-queue heap-delete ] when*
 | 
					
						
							|  |  |  |         f over set-thread-sleep-entry | 
					
						
							| 
									
										
										
										
											2008-02-25 07:31:18 -05:00
										 |  |  |         dup resume | 
					
						
							|  |  |  |     ] when drop ;
 | 
					
						
							| 
									
										
										
										
											2008-02-18 06:07:40 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  | : (spawn) ( thread -- )
 | 
					
						
							|  |  |  |     [ | 
					
						
							| 
									
										
										
										
											2008-02-21 20:12:37 -05:00
										 |  |  |         resume-now [ | 
					
						
							| 
									
										
										
										
											2008-02-18 06:07:40 -05:00
										 |  |  |             dup set-self | 
					
						
							|  |  |  |             dup register-thread | 
					
						
							|  |  |  |             V{ } set-catchstack | 
					
						
							|  |  |  |             { } set-retainstack | 
					
						
							|  |  |  |             >r { } set-datastack r> | 
					
						
							|  |  |  |             thread-quot [ call stop ] call-clear | 
					
						
							|  |  |  |         ] 1 (throw) | 
					
						
							| 
									
										
										
										
											2008-02-19 15:38:02 -05:00
										 |  |  |     ] "spawn" suspend 2drop ;
 | 
					
						
							| 
									
										
										
										
											2008-02-18 06:07:40 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-02-21 00:13:31 -05:00
										 |  |  | : default-thread-error-handler ( error thread -- )
 | 
					
						
							|  |  |  |     global [ | 
					
						
							|  |  |  |         "Error in thread " write
 | 
					
						
							|  |  |  |         dup thread-id pprint | 
					
						
							|  |  |  |         " (" write
 | 
					
						
							|  |  |  |         dup thread-name pprint ")" print
 | 
					
						
							|  |  |  |         "spawned to call " write
 | 
					
						
							|  |  |  |         thread-quot short. | 
					
						
							|  |  |  |         nl
 | 
					
						
							|  |  |  |         print-error flush
 | 
					
						
							|  |  |  |     ] bind ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-02-18 06:07:40 -05:00
										 |  |  | : spawn ( quot name -- thread )
 | 
					
						
							| 
									
										
										
										
											2008-02-21 00:13:31 -05:00
										 |  |  |     [ default-thread-error-handler ] <thread> [ (spawn) ] keep ;
 | 
					
						
							| 
									
										
										
										
											2008-02-18 06:07:40 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-02-18 08:30:16 -05:00
										 |  |  | : spawn-server ( quot name -- thread )
 | 
					
						
							|  |  |  |     >r [ [ ] [ ] while ] curry r> spawn ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | : in-thread ( quot -- )
 | 
					
						
							|  |  |  |     >r datastack namestack r> | 
					
						
							|  |  |  |     [ >r set-namestack set-datastack r> call ] 3curry
 | 
					
						
							|  |  |  |     "Thread" spawn drop ;
 | 
					
						
							| 
									
										
										
										
											2008-02-18 06:07:40 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  | <PRIVATE
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | : init-threads ( -- )
 | 
					
						
							| 
									
										
										
										
											2008-02-18 17:20:18 -05:00
										 |  |  |     H{ } clone 41 setenv | 
					
						
							|  |  |  |     <dlist> 42 setenv | 
					
						
							|  |  |  |     <min-heap> 43 setenv | 
					
						
							| 
									
										
										
										
											2008-02-18 06:07:40 -05:00
										 |  |  |     initial-thread global
 | 
					
						
							|  |  |  |     [ drop f "Initial" [ die ] <thread> ] cache
 | 
					
						
							| 
									
										
										
										
											2008-02-19 15:38:02 -05:00
										 |  |  |     <box> over set-thread-continuation | 
					
						
							| 
									
										
										
										
											2008-02-25 07:31:18 -05:00
										 |  |  |     f over set-thread-state | 
					
						
							| 
									
										
										
										
											2008-02-18 06:07:40 -05:00
										 |  |  |     dup register-thread | 
					
						
							|  |  |  |     set-self ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | [ self dup thread-error-handler call stop ] | 
					
						
							|  |  |  | thread-error-hook set-global
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | PRIVATE>
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-02-18 08:30:16 -05:00
										 |  |  | [ init-threads ] "threads" add-init-hook |