; Copyright (c) 2012 Teresa Bradbury ; Execution starts here ; In this example there are 3 threads ; Thread 2 prints twice then kills itself (by returning) ; Thread 1 loops until the main thread kills it 0x0100: call threadinit load #thread1 R1 load #thread1stack R2 call threadcreate store R1 thread1id load #thread2 R1 load #thread2stack R2 call threadcreate store R1 thread2id mainloop: load #mainstr R1 call printstring call threadyield ;jump mainloop ; uncomment this for inf-loop load #mainstr R1 call printstring call threadyield load #mainstr R1 call printstring call threadyield load #mainstr R1 call printstring call threadyield load thread1id R1 call threaddestroy load #mainstr R1 call printstring call threadyield load #mainstr R1 call printstring call threadselfdestruct thread1id : block 1 thread2id : block 1 mainstr : block #"Main Thread\n" thread1 : load #thread1str R1 call printstring call threadyield jump thread1 ;return thread2 : load #thread2str R1 call printstring call threadyield ;jump thread2 load #thread2str R1 call printstring call threadyield return thread1stack : block 8 thread2stack : block 8 thread1str : block #"Thread 1\n" thread2str : block #"Thread 2\n" ; R1 : string pointer (changed) printstring : load R1 R2 jumpz R2 printstring_end store R2 0xfff0 add R1 ONE R1 jump printstring printstring_end : return ; ------------------------------------- ; --------- Concurrency Data ---------- ; ------------------------------------- maxthreads : block #3 ; For each thread, the first word is one if the thread exists ; and zero otherwise. The second word is the stack pointer. threaddata : block 6 currentthreadid : block 1 ; ------------------------------------- ; ------- Concurrency Functions ------- ; ------------------------------------- ; must be called at start of the program ; it initializes the data structures ; No parameters threadinit : load maxthreads R0 threadinit_threaddatainit : ; R0 is the thread that is being initialised. It counts down. add R0 MONE R0 ; thread id move R0 R1 ; structure offset move ZERO R2 ; no flags move ZERO R3 call threaddatastore jumpnz R0 threadinit_threaddatainit ; set thread zero to active move ZERO R1 move ZERO R2 move ONE R3 call threaddatastore store ZERO currentthreadid return ; R1 : in thread id ; R2 : in structure offset ; R1 : out data ; preserves R0 threaddataload : ; structure has size 2 load #2 R3 mult R1 R3 R3 add R3 R2 R3 load R3 #threaddata R1 return ; R1 : in thread id ; R2 : in structure offset ; R3 : in data ; preserves R0 threaddatastore : ; structure has size 2 load #2 R4 mult R1 R4 R4 add R4 R2 R4 store R3 #threaddata R4 return ; R1 : in function pointer ; R2 : in stack pointer ; R1 : out thread id (-1 for error) ; Stack needs to be big enough for thread's workings, ; plus at least 3 threadcreate : push R1 push R2 ; find a free thread id (in R0) move ZERO R0 threadcreate_findid : load maxthreads R1 sub R1 R0 R2 ; if R2 == 0 then R0 == maxthreads ; so return -1 as no available threads jumpnz R2 threadcreate_no_error move MONE R1 return threadcreate_no_error : move R0 R1 move ZERO R2 call threaddataload jumpz R1 threadcreate_foundid add ONE R0 R0 jump threadcreate_findid threadcreate_foundid : ; created thread is inactive (not current) and ; the stack contains a pointer to selfdestruct then ; the provided stack pointer so first it will ; return to the given function and if it returns ; again it will be destroyed pop R2 ; stack pointer pop R1 ; function pointer store R1 #1 R2 load #threadselfdestruct R1 store R1 #0 R2 ; Store the stack pointer move R0 R1 add R2 ONE R3 move ONE R2 call threaddatastore ; Mark the thread as existant move R0 R1 move ZERO R2 move ONE R3 call threaddatastore ; Return the created thread id move R0 R1 return ; Pass thread id in R1 threaddestroy : ; If thread id is not current, we just mark nonexistant ; If thread id *is* current, we mark nonexistant and then call ; threadyield to switch to another thread move R1 R0 ; because R0 survives the function calls ; Turn off the thread move R0 R1 move ZERO R2 move ZERO R3 call threaddatastore ; Is this the current thread? load currentthreadid R1 sub R0 R1 R2 jumpnz R2 threaddestroy_notcurrentthread call threadyield threaddestroy_notcurrentthread : return ; No parameters - destroys current thread ; this is called on returning from a thread function threadselfdestruct : load currentthreadid R1 jump threaddestroy ; No parameters threadyield : ; store the stackpointer load currentthreadid R1 move ONE R2 move SP R3 call threaddatastore ; round robin scheduling ; we will eventually choose the thread id in R0 load currentthreadid R0 threadyield_findnext : load maxthreads R1 add R0 ONE R0 sub R1 R0 R2 ; if R2 == 0 then R0 == maxthreads ; so R0 := 0 jumpnz R2 threadyield_mod move ZERO R0 threadyield_mod : move R0 R1 move ZERO R2 call threaddataload jumpnz R1 threadyield_foundnext ; if none of the threads exist, halt load currentthreadid R4 sub R4 R0 R4 jumpnz R4 threadyield_findnext halt threadyield_foundnext : store R0 currentthreadid ; load the new stack pointer load currentthreadid R1 move ONE R2 call threaddataload move R1 SP return