home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD1.mdf / magazine / drdobbs / 1989 / 02 / ilg&brow.asc < prev    next >
Text File  |  1989-01-04  |  19KB  |  498 lines

  1. _A Timed Event Network Scheduler in Forth_
  2. by Gregory Ilg and R.J. Brown
  3.  
  4. [NOTE: FORTH SCREENS ACCOMPANY THESE LISTINGS]
  5.  
  6. [LISTING ONE]
  7.  
  8. \   Hypothetical Network To Handle Omelette Selection On
  9. \   Brodie's Egg-Master
  10.  
  11.  
  12.         CONSULT TENS            \ Timed Event Network Scheduler
  13.  
  14. 184 EQU ticks/10secs            \ system clock time constant
  15.  
  16. : MS ( miliseconds -- ticks )   \ time units conversion
  17.     184 10000 */ ;
  18.  
  19. : sec ( seconds -- ticks )
  20.     184 10 */ ;
  21.  
  22. : min ( minutes -- ticks )
  23.     60 * sec ;
  24.  
  25.  
  26. (  Define stubs for un-implemented words...  )
  27.  
  28.   STUB[ Break-Egg           seasoning-valve     open
  29.         close               mixer               on
  30.         off                 griddle             pour-valve
  31.         wait-for-coins      Cook-Fried          Cook-Poached
  32.         Cook-Hard-Boiled    Cook-Benedict   ]
  33.  
  34.  
  35. (   Define buttons as an enumeration set...  )
  36.  
  37.   1 ENUM[   Fried-button
  38.             Poached-button
  39.             Hard-Boiled-button
  40.             Benedict-button
  41.             Omelette-button     ]
  42.  
  43. : read-a-button Omelette-button ;   \ always choose "omelette"
  44.  
  45. : None ;  IMMEDIATE  ( noise word to improve readability )
  46.  
  47.  
  48.  
  49. NETWORK Mix-Omelette                \ subnetwork also used
  50.                                     \ in fancier omelettes
  51.  
  52.     NODE Start-Mix-Omelette         \ dummy for single entry
  53.         Predecessors    NIL
  54.         Entry-Action    None
  55.         Delay           0 sec
  56.         Exit-Action     None
  57.     END-NODE
  58.  
  59.  
  60. \ Wrap up subnetwork Break-Egg.  Break-Egg not detailed here
  61.  
  62.     NODE Crack-Egg
  63.         Predecessors    Start-Mix-Omelette
  64.         Entry-Action    Break-Egg
  65.         Delay           0 sec
  66.         Exit-Action     None
  67.     END-NODE
  68.  
  69.  
  70. \ concurrent with Crack-Egg
  71.  
  72.     NODE Add-Seasoning
  73.         Predecessors    Start-Mix-Omelette
  74.         Entry-Action    seasoning-valve open
  75.         Delay           100 MS
  76.         Exit-Action     seasoning-valve close
  77.     END-NODE
  78.  
  79.  
  80.     NODE Blend
  81.         Predecessors    Crack-Egg
  82.                         Add-Seasoning
  83.         Entry-Action    mixer on
  84.         Delay           3 sec
  85.         Exit-Action     mixer off
  86.     END-NODE
  87.  
  88.  
  89. END-NETWORK  ( Mix-Omelette )
  90.  
  91.  
  92.  
  93.  
  94. NETWORK Cook-Omelette               \ net head to process...
  95.                                     \ ...Omelette-button
  96.  
  97.     NODE Start-Cook-Omelette        \ dummy for single entry
  98.         Predecessors    NIL
  99.         Entry-Action    None
  100.         Delay           0 sec
  101.         Exit-Action     None
  102.     END-NODE
  103.  
  104.  
  105.     NODE Preheat-Griddle
  106.         Predecessors    Start-Cook-Omelette
  107.         Entry-Action    griddle on
  108.         Delay           30 sec
  109.         Exit-Action     None
  110.     END-NODE
  111.  
  112.  
  113. \ subnetwork...
  114.  
  115.     NODE Mix-Omelette'
  116.         Predecessors    Start-Cook-Omelette
  117.         Entry-Action    Mix-Omelette
  118.         Delay           0 sec
  119.         Exit-Action     None
  120.     END-NODE
  121.  
  122.  
  123.     NODE Pour-Mixture
  124.         Predecessors    Preheat-Griddle
  125.                         Mix-Omelette'
  126.         Entry-Action    pour-valve open
  127.         Delay           2 min
  128.         Exit-Action     pour-valve close
  129.                         griddle off
  130.     END-NODE
  131.  
  132.  
  133. END-NETWORK  ( Cook-Omelette )
  134.  
  135.  
  136.  
  137. \ This word is hooked to the power-up vector on the
  138. \ Egg-Master vending machine.
  139.  
  140.  
  141. : EGG_MASTER ( -- )
  142.     BEGIN  wait-for-coins  read-a-button  CASE
  143.         Fried-button        OF Cook-Fried       ENDOF
  144.         Poached-button      OF Cook-Poached     ENDOF
  145.         Hard-Boiled-button  OF Cook-Hard-Boiled ENDOF
  146.         Benedict-button     OF Cook-Benedict    ENDOF
  147.         Omelette-button     OF Cook-Omelette    ENDOF
  148.     ENDCASE AGAIN ;
  149.  
  150.  
  151. [LISTING TWO]
  152.  
  153. \                  TIMED EVENT NETWORK SCHEDULER
  154. \           Copyright (c) 1988 Elijah Laboratories Inc.
  155.  
  156.  
  157. ( This package makes use of a number of programs that are
  158. not detailed here.  The word CONSULT is used to load these
  159. packages.  The packages are included in the companion DDJ
  160. source disk. )
  161.  
  162.  
  163.     CONSULT     STRUC           \ structure definitions
  164.     CONSULT     PRIQUE          \ priority queue manager
  165.     CONSULT     MACROS          \ for the evaluator
  166.     CONSULT     BALLS           \ for backtracking control
  167.     CONSULT     XSHEETS         \ transient storage words
  168.  
  169.  
  170.   CREATE TQ NIL ,               \ the timer queue
  171.  
  172.   : nothing ; *MITT* SETQ nothing \ no default THROW handler
  173.   6 INFLATE BALL tens.ball      \ trap door for exit
  174.             BALL te.ball        \ ditto
  175.  
  176.  
  177. (  A timed event network is a linked data structure composed of
  178. the following timed event nodes. )
  179.  
  180. sizeof pq struc TEnode              \ a timed event node
  181. 1w              TEnode  word-1      \ execute before delay
  182. 1w              TEnode  delay       \ # ticks to delay
  183. 1w              TEnode  path-length \ path length from start
  184. 1w              TEnode  word-2      \ execute after delay
  185. 1w              TEnode  ^Succ's     \ ptr to successor list
  186. 0               TEnode  Pred's      \ start of predecessor list
  187.  
  188.  
  189. (  These words start and stop the timer cell, and fetch its
  190. value, and add its value to the top-of-stack, thereby
  191. converting a time interval into an absolute time value.  )
  192.  
  193.   VARIABLE now                                \ the timer cell
  194.  
  195. : start-now ( -- ) -2 now ! now TICKER DROP ; \ start the timer
  196.  
  197. : stop-now ( -- ) now -TICKER ;               \ stop the timer
  198.  
  199. : now@ ( -- #tics )  now @ NEGATE ;           \ fetch the timer
  200.  
  201. : now+ ( delay -- time ) now@ + ;             \ add timer value
  202.  
  203.  
  204. (  This word defines the processing that occurs when a node is
  205. activated.  This consists of performing the entry action
  206. routine and enqueueing for the required delay time.  )
  207.  
  208. : entry-action ( node -- )              \ start up a node
  209.     >R                                  \ save node pointer
  210.     R@ NIL = IF T tens.ball THROW THEN  \ if none, we're done!
  211.     R@ BODY> >NAME CR .NAME             \ display its name
  212.     R@ word-1 PERFORM                   \ do pre-delay stuff
  213.     R@ delay @ now+ R@ key !            \ figure dispatch time
  214.     TQ R> pq-enque ;                    \ put on timer queue
  215.  
  216.  
  217. (  This word waits until the head of the timer queue is past
  218. its dispatch time, and then dequeues the head element from the
  219. timer queue for subsequent processing. )
  220.  
  221. : wait-till ( -- node )             \ take next node off queue
  222.     TQ @ 0= ABORT" Empty timer queue "
  223.     BEGIN TQ @ key @ now@ < UNTIL   \ wait until its time
  224.     TQ pq-deque                     \ then remove it
  225. ." DQ " ;
  226.  
  227.  
  228. (  The following structures are used in the word "notify".  The
  229. first is passed as a parameter block, and the second is SPREAD
  230. as a SHEET.  )
  231.  
  232. 0 struc n.parm              \ passed parameters...
  233. 1w      n.parm  n.pred      \ ptr to predecessor
  234. 1w      n.parm  n.succ      \ ptr to its successor
  235.  
  236. 0 struc n.temp              \ temporaries...
  237. 1w      n.temp  n.trig      \ trigger indicator
  238.  
  239.  
  240. (  This word searches the predecessor list of a node for a
  241. match with the cfa of a completing predecessor.  When the match
  242. is found, the low order bit of the predecessor address is set
  243. as a flag to indicate that that predecessor has completed.  If
  244. all such flags are set, "n.trig" is set to trigger the node.  )
  245.  
  246. : set-done-flag ( _n.temp -- _n.temp )     \ set pred's done fg
  247.     AT #[ parm n.parm n.succ ]+ SH@ Pred's \ pt to succ's preds
  248.     BEGIN DUP @ ?DUP WHILE                 \ for all preds
  249.         AT #[ parm n.parm n.pred ]+ SH@ =  \ we got a match?
  250.         IF DUP 1 |! THEN                   \ yes, set done flag
  251.         DUP @ AT n.trig SH@ AND            \ figure new trigger
  252.         AT n.trig SH! w+ REPEAT DROP ;     \ save it & continue
  253.  
  254.  
  255. (  This word clears all the done flags that were set to trigger
  256. the activation of a node.  This word is performed just prior to
  257. activating the node, thus preparing it for re-triggering at a
  258. later time.  )
  259.  
  260. : clear-done-flags                  \ clear succ's done flags
  261.     AT #[ parm n.parm n.succ ]+     \ point to successor
  262.     SH@ Pred's                      \ point to his predecessors
  263.     BEGIN DUP @ ?DUP WHILE          \ for all predecessors
  264.         [ 1 NOT ]# AND OVER !       \ clear its done flag
  265.     w+ REPEAT ;                     \ loop to end of list
  266.  
  267.  
  268. (  The "notify" word tells a successor to a node that one of
  269. its predecessors has completed.  If all of its predecessors
  270. have completed, then that successor node is started.  )
  271.  
  272. : notify ( pred succ -- )       \ notify a successor
  273.     sizeof n.temp SPREAD        \ make room for temps
  274.     1 AT n.trig SH!             \ cock the trigger
  275.     set-done-flag               \ set pred's done flag
  276.     AT n.trig SH@ IF            \ has succ been triggered?
  277.         clear-done-flags        \ yes, clear his done flags
  278.         CRUSH NIP entry-action  \ & start him up!
  279.     ELSE CRUSH 2DROP THEN ;     \ no, just return...
  280.  
  281.  
  282. (  This word is executed after a node has been removed from the
  283. timer queue after waiting its required delay time.  It causes
  284. the exit action routine for that node to be performed, and then
  285. notifies all the successors of that node that it  has completed
  286. execution.  )
  287.  
  288. : exit-action ( node -- )           \ complete a node
  289.     DUP word-2 PERFORM              \ do after delay stuff
  290.     DUP ^Succ's DUP @ NIL =         \ point to successor chain
  291.     IF T tens.ball THROW THEN       \ if none, we're done!
  292.     BEGIN @ ?DUP WHILE              \ for all his successors
  293.         2DUP w+ @ notify            \ notify them he's done
  294.     REPEAT DROP ;                   \ then clean up & exit
  295.  
  296.  
  297. (  This is the "Timed Event Network Scheduler", the entry point
  298. for the DOES> word of a timed event network.  Running such a
  299. network is done by executing the name of the network, which
  300. calls TENS with the address of the network list head.  )
  301.  
  302. : TENS ( net -- )                       \ run a timed event net
  303.     tens.ball CATCH IF                  \ exit via trap door?
  304.                  DROP EXIT THEN         \ yes, stop timer, exit
  305.     start-now @ entry-action BEGIN      \ no, start first node
  306.         wait-till exit-action AGAIN ;   \ wait, then finish it
  307.  
  308.  
  309. (  This word links a node into the successor lists of all of
  310. its predecessors.  After this has been done recursively for
  311. all the successors of that node, ad infinitum, then the entire
  312. event network will be linked both forwards and backwards.  )
  313.  
  314. F: link-to-pred                 \ declare forward reference
  315.  
  316. : link-to-pred's ( node -- )    \ fix up forward lnks in network
  317.     DUP Pred's >R               \ point to it predecessor list
  318.     BEGIN R@ @ ?DUP WHILE       \ for all its predecessors...
  319.         OVER SWAP link-to-pred  \ link this node to its pred
  320.         R> w+ >R REPEAT         \ point to next pred ptr
  321.     DROP R> DROP ;              \ tidy up stacks
  322.  
  323. R: link-to-pred ( node pred -- )    \ ping pongs with word above
  324.     DUP >R                          \ remember predecessor ptr
  325.     ^Succ's                         \ point to successor ptr
  326.     BEGIN DUP @ ?DUP WHILE          \ for all successors...
  327.         NIP DUP w+ @ 2 PICK =       \ duplicate?
  328.         IF R> 3DROP EXIT THEN       \ yes, skip this node
  329.     REPEAT                          \ until end of list
  330.     HERE SWAP !                     \ append new CONS cell
  331.     NIL ,                           \ CDR is NIL
  332.     ,                               \ CAR is successor node
  333.     R> link-to-pred's ;             \ fix his predecessors too!
  334.  
  335.  
  336. (  This word kicks off the action to reverse link the event
  337. network by passing the address of the first node to the
  338. recursive network traversal algorithm.  It takes the address
  339. of the network list head as its parameter.  )
  340.  
  341. : fix-Succ's ( head -- )        \ generate successor lists
  342.     w+ @                        \ point to last node
  343.     link-to-pred's ;            \ link it to its predecessors
  344.  
  345.  
  346. ( This word recursively traverses the network accumulating the
  347. maximum path length to each node.  This length from the first
  348. to last nodes is the critical path length, or network delay. )
  349.  
  350. : set-path-len ( ^node old-path-length -- )
  351.     SWAP >R                         \ save this node's pointer
  352.     R@ delay @ +                    \ add this delay to old len
  353.     R@ path-length @                \ get current len
  354.     MAX DUP                         \ new len is max of the two
  355.     R@ path-length !                \ save new len
  356.     R> Pred's >R                    \ point to pred ptrs list
  357.     BEGIN R> DUP w+ >R @ ?DUP WHILE \ for all predecessors...
  358.         OVER RECURSE REPEAT         \ set their path length too
  359.     DROP R> DROP ;                  \ clean up and exit
  360.  
  361.  
  362. (  This word calls the recursive network traversal routine to
  363. compute the length of the critical path through the network.
  364. The result is stored in the network's list head.  )
  365.  
  366. : set-path-lengths ( nethead -- )
  367.     DUP w+ @                \ point to last node
  368.     0                       \ initial path length is zero
  369.     set-path-len            \ recursively set path lengths
  370.     DUP @ path-length @     \ get computed critical path length
  371.     SWAP 2 w*+ ! ;          \ save it in network head
  372.  
  373.  
  374. (  This word displays the name of a network and its critical
  375. path length in milliseconds, It is used as a tuning aid.  )
  376.  
  377. : .pathlen ( nethead -- )       \ display critical path length
  378.         CR                      \ start on a new line
  379.         ." Critical path of "   \ indentify it
  380.         DUP BODY> >NAME .NAME   \ show network name
  381.         ."  is "                \ more verbiage
  382.         2 w*+ @                 \ fetch length in ticks
  383.         10 184 */               \ convert to seconds
  384.         .                       \ display the number
  385.         ." seconds long. "      \ more verbiage
  386.         CR ;                    \ and a new line
  387.  
  388.  
  389. (  This word displays the critical path on the screen at
  390. compilation time to facilitate tuning.  )
  391.  
  392. : .critpath ( nethead -- )
  393.     ." Critical path is: " w+ @     \ point to last node
  394.     BEGIN ?DUP WHILE                \ for each node on critpath
  395.         CR 4 SPACES                 \ indent to look pretty
  396.         DUP BODY> >NAME .NAME       \ display its name
  397.         Pred's >R 0 0 BEGIN         \ for each predecessor
  398.             R> DUP w+ >R @          \ get a predecessor pointer
  399.             ?DUP WHILE              \ as long as they exist
  400.             DUP path-length @       \ get its path length
  401.             2 PICK OVER MAX         \ take maximum of old & new
  402.             OVER = IF 2SWAP THEN    \ update max & ptr
  403.             2DROP REPEAT R> 2DROP   \ discard excess baggage
  404.         REPEAT CR ;                 \ loop till done
  405.  
  406.  
  407. (  The Top-of-Stack is used by END-NETWORK to generate the
  408. successor lists for all of the nodes in the network. For this
  409. reason, the last node instantiated *MUST* be the unique
  410. terminal node for the network. Likewise, the first node
  411. instantiated *MUST* be the unique initial node for the
  412. network. )
  413.  
  414. : END-NETWORK ( head first last -- )
  415.         ROT >R SWAP             \ save head, put first on top
  416.         R@ !                    \ save first in head
  417.         R@ w+ !                 \ save last in head
  418.         R@ fix-Succ's           \ generate successor lists
  419.         R@ set-path-lengths     \ compute critical path length
  420.         R@ .pathlen             \ display critical path length
  421.         R> .critpath ;          \ display critical path
  422.  
  423.  
  424. (  The following word is used to begin the definition of a
  425. timed event network.  The network is terminated by the word
  426. END-NETWORK.  )
  427.  
  428. : NETWORK ( -- )            \ begin a timed event network
  429.         CREATE HERE         \ give it a name and remember where
  430.         NIL , NIL ,         \ initialize first & last pointers
  431.         NIL   NIL           \ initialize 2 pointers on stack
  432.         0 ,                 \ initialize critical path length
  433.         DOES> TENS ;        \ runs the scheduler when called
  434.  
  435.  
  436. ( This is the format for declaring a node in a TENS network.
  437.  
  438.         NODE <node-name>
  439.             Predecessor     pred1 ... predn
  440.             Entry-Action    word1 ... wordn
  441.             Delay           n  \ tics
  442.             Exit-Action     word1 ... wordn
  443.         END-NODE
  444. )
  445.  
  446.  
  447.   NIL EQU ^NODE                     \ pointer to current node
  448.  
  449. : NODE ( -- )                       \ define network step node
  450.         CREATE                      \ make a dictionary header
  451.         HERE EQU ^NODE              \ remember where it is
  452.         sizeof TEnode ALLOT         \ make room for it
  453.         0 ^NODE path-length !       \ initialize path length
  454.         NIL ^NODE ^Succ's !         \ terminate successor chain
  455.         DROP ?IF ^NODE              \ set 1st
  456.         ELSE ^NODE DUP THEN ;       \ & last pointers
  457.  
  458.  
  459. : Predecessors                      \ start predecessor list
  460.         DUP                         \ insert cushion
  461.         te.ball CATCH NIL =         \ to end predecessor list
  462.         IF BEGIN DEPTH >R EVAL      \ mark stack & eval token
  463.                 DEPTH R>            \ did eval return a value
  464.                 - 1 = IF ,          \ yes, store it as a pred
  465.                       ELSE          \ no, more than one value?
  466.     T ABORT" Illegal Predecessor "  \ yes, abort with a msg!
  467.                       THEN          \ no value, treat as comment
  468.             AGAIN THEN              \ build predecessor list
  469.         DROP                        \ remove cushion
  470.         CP @ ^NODE word-1 !         \ make entry action header
  471.         HERE PFA, nest JMP,         \ stuff cfa and pfa into it
  472.         ] ;                         \ compile entry action
  473.  
  474.  
  475. : Entry-Action NIL , T te.ball THROW ; \ end predecessor list
  476.  
  477.  
  478. : Delay                             \ specify delay time
  479.     COMPILE EXIT                    \ last word in entry action
  480.     [COMPILE] [                     \ set interpret state
  481.     ; IMMEDIATE                     \ must run while compiling
  482.  
  483.  
  484. : Exit-Action                       \ specify exit action
  485.         ^NODE delay !               \ save delay time
  486.         CP @ ^NODE word-2 !         \ make exit action header
  487.         HERE PFA, nest JMP,         \ stuff cfa & pfa into it
  488.         ] ;                         \ force compile state
  489.  
  490.  
  491. : END-NODE                      \ terminate node definition
  492.         COMPILE EXIT            \ last word in exit action
  493.         [COMPILE] [             \ set interpret mode
  494.         ; IMMEDIATE             \ must run while compiling
  495.  
  496.  
  497.  
  498.