###################################################### ## ## Threads: ## ## A basic implementation of a cooperative multitasking ## system for Mako. Each task has an independent data ## and return stack and may call 'yield' to transfer ## control to the next task in round-robin order. ## When all tasks 'finish', the program will halt. ## ## John Earnest ## ###################################################### :data root-task 0 0 root-task :data curr-task root-task : .task-dp ; : .task-rp 1 + ; : .task-next 2 + ; : yield ( -- ) DP @ curr-task @ .task-dp ! RP @ curr-task @ .task-rp ! : [yield] curr-task @ .task-next @ curr-task ! curr-task @ .task-dp @ DP ! curr-task @ .task-rp @ RP ! ; : task ( entrypoint* task-record* -- ) curr-task @ .task-next @ over .task-next ! dup curr-task @ .task-next ! .task-rp swap over @ ! dup @ 1 + swap ! ; : last-task? ( -- flag ) curr-task @ dup .task-next @ = ; : finish ( -- ) last-task? if halt then curr-task @ dup .task-next @ loop 2dup .task-next @ xor -if break then .task-next @ again swap .task-next @ swap .task-next ! [yield] ; ###################################################### ## ## Buffered circular queues which use the ## yielding system to block for input/output. ## ###################################################### : .buff-tail ; : .buff-head 1 + ; : .buff-size 2 + ; : .buff-addr 3 + ; : >buffer ( value buff* -- ) >r loop i .buff-tail @ i .buff-head @ 1 + i .buff-size @ mod xor if break then yield again i .buff-head @ i .buff-addr @ + ! i .buff-head @ 1 + i .buff-size @ mod r> .buff-head ! ; : buffer> ( buff* -- ) loop dup .buff-tail @ over .buff-head @ xor if break then yield again >r i .buff-tail @ i .buff-addr @ + @ i .buff-tail @ 1 + i .buff-size @ mod r> .buff-tail ! ; ###################################################### ## ## Tests and examples: ## ###################################################### :include # producer :array prod-d 20 0 :array prod-r 20 0 :data prod prod-d prod-r 0 # consumer :array cons-d 20 0 :array cons-r 20 0 :data cons cons-d cons-r 0 # queue :const queue-size 5 :array queue-buff queue-size 0 :data queue 0 0 queue-size queue-buff : produce 29 for i queue >buffer next "done producing" typeln finish ; : consume 29 for queue buffer> . next "done consuming" typeln finish ; : main ' produce prod task ' consume cons task loop yield "interleaved..." typeln last-task? until "child processes complete." typeln finish ;