Chapter 7

P21Forth Multitasker


P21Forth 1.02

P21Forth provides a traditional Forth cooperative multitasker. The idea behind the multitasker is that while programs are waiting for something to happen they can let other code run by executing multiple tasks.

The most important word is the word PAUSE. PAUSE is the word that switches control from one task the next task in the task list. Each task will have control until it executes the word PAUSE and control is passed on to the next task in the list. PAUSE will execute in just a couple of microseconds to switch tasks. If there is only one task in the list the word PAUSE will just return to the word after PAUSE in the same task.

The command:

        ` P?RX `?KEY !
will set the execution vector for ?KEY to the word P?RX. P?RX contains both a PAUSE and a ?RX. This way the system will switch tasks each time it checks the keyboard.

There are several steps needed to used the multitasker. First the multitasker should be installed into the word that reads the keyboard as in the above example. Then you must allot the memory for use by the task. The word to do this is HAT, as in I put on a different hat when I do a different job. The word HAT takes three parameters from the stack. These specify the number of memory cells to be allocated for use by any user variables beyond the five default user variables, the number of memory cells to be used for the data stack by this task, and the the number of memory cells to be used by the return stack for this task. The word HAT also takes a name from the input stream.

The command:

        0 64 64 HAT MYTASK
would create a new word called MYTASK and allot enough memory for this word to contain the default 5 user variables for each task, and 64 cells of memory for the data stack and 64 cells for the return stack for the task MYTASK.

The command:

        MYTASK BUILD
will initialize the data structure of the word MYTASK, and link it into the task list.

If you define a word called TASKDEMO as:

 : TASKDEMO ( -- ) \ define a new word called TASKDEMO
  0 V1 !           \ set variable V1 to 0
  MYTASK ACTIVATE  \ start a background task in MYTASK at the next word
  BEGIN            \ TASK(   begin a loop
     PAUSE 1 V1 +! \ switch tasks each time and increment variable V1
  AGAIN ;          \ )TASK   repeat the loop
A background task is now ready to run. If you now type TASKDEMO this task will begin to run in the background. This will be obvious if you test the value in the variable V1 by typing the command:
        V1 ?
Each time you test V1 it will have a different value. This is because it is being incremented tens of thousands of times per second by the background task TASKDEMO.

The command:

        MYTASK SLEEP
will suspend the execute of the task. The command:
        MYTASK AWAKE
will restart the task if it is sleeping.

The word TASKS can be used to examine the current list of tasks and see the status and name of each task.

Each task will have its own stacks, and its own user variables. The variable UP (User Pointer) points to the area used for user variables and stacks by a task. In P21Forth UP will contain a pointer to the location of the bottom of the return stack for a task. The return stack will build up in memory from this location. The five default user variables and any extra user variables for each task will be directly below this location, and the data stack for this task will be just below that. WINDOW is not automatically assigned a space for each task declared. Only space for five default user variables is set up. If a task wants to reserve a protected space for a WINDOW user variable to manipulate its own graphics windows a space can be reserved in the user variable parameter in the word HAT.

<-data stack area-><-user variables-><-return stack area->
There are six default user variables for each task.
WINDOW   \ pointer to a table of graphic window parameters
STATUS   \ contains either the executable vector wake or pass
FOLLOWER \ contains the address of the next task's STATUS
TOS      \ contains the top stack location for a task when not running
TID      \ contains a pointer to the task name
TF       \ contains a THROW FRAME for error handling in this task
Tasks can read each others user variable by using the `S word. In the above example one can get the address of the TID user variable for the MYTASK task with the command:
        MYTASK TID `S
Multitasker Glossary
TASKS ( -- )        \ show the names and status of the tasks in the task list
SUP ( -- tid )      \ start up area
HAT ( n n n -< name>- ) \ create a new task
ACTIVATE ( --  )    \ start a task with the code following ACTIVATE
BUILD ( tid -- )    \ initialize and link in a new task
AWAKE ( tid -- )    \ awaken a task
SLEEP ( tid -- )    \ put a task to sleep
STOP ( -- )         \ sleep the current task
'S ( tid a -- a )   \ access a different task'S user variables
PAUSE ( -- )        \ switch tasks
WAKE ( -- a )       \ address of wake
wake ( -- )         \ used in STATUS for tasks that are awake
PASS ( -- a )       \ address of pass
pass ( -- )         \ used in STATUS for tasks that are asleep
TF ( -- a )         \ THROW FRAME for error handling
TID ( -- a )        \ Task ID for this task
TOS ( -- a )        \ Top of Stack storage
FOLLOWER ( -- a )   \ address of next tasks STATUS word
STATUS ( -- a )     \ contains wake or pass
WINDOW ( -- a )     \ contains a pointer to a table of graphics window parameters
UP ( -- a )         \ pointer to the user are of this task
USER ( n -< name >- )    \ creates new user variables
GET ( semaphore -- )     \ get shared resource
RELEASE ( semaphore -- ) \ release shared resource
Multitasking Demo

A multitasking demo is included in P21Forth 1.02. It is loaded with the command:
9 B THRU DECIMAL TASKDEMO MULTI-SERIAL (or MULTI-PARALLEL)
If you are using serial input it is best to turn the multitasker on at the end of the phrase because the multitasker may interfere with correctly reading the start bit of serial input at higher baud rates.

The demo source can be viewed with 9 LIST, A LIST, B LIST. The demo sets up 8 tasks, the P21Forth interpretter is the first task, there are 6 sleeping tasks T2 thru T7 and the task T8 increments a double word counter V by 8 every time it runs. T8 also displays the counter in the upper left hand corner of the screen on every 1024 task changes. It will demonstate about 200k task switches per second. The phrase T8 SLEEP will halt the T8 task and the phrase T8 AWAKE will start it back up.


End of Chapter 7

Return to Table of Contents

Previous Chapter

Next Chapter