The ARM multitasker follows the model introduced with the v6.1 compilers. A few extensions are also provided.
The code in MultiARM.fth only works with the ARM32 register set usage. If you need interworking with one of the Cortex register set usages, please contact MPE or modify the code yourself.
0 equ test-multi? \ true to compile test code
If previously undefined, TEST-MULTI? is set to zero
and test code is not compiled.
|
This structure is allocated at the start of the USER area. Consequently the TCB of the current task is given by UP.
struct /TCB \ -- size
The structure used by the code that matches the
description above.
init-u0 constant main \ -- addr ; tcb of main task
Returns the base address of the main task's USER area.
0 value multi? \ -- flag
Returns true if the tasker is enabled.
: single \ --
Disable scheduler.
: multi \ --
Enable scheduler.
CODE pause \ -- ; the scheduler itself
The software scheduler itself.
code status \ -- task-status
Returns the current task's status cell, but with the run
bit masked out.
CODE restart \ task -- ; mark task TCB as running
Sets the RUN bit in the task's status cell.
CODE halt \ task -- ; reset running bit in TCB
Clears the RUN bit in the task's status cell.
: stop \ -- ; halt oneself
HALTs the current task, and executes PAUSE.
Event handling is only compiled if the equate EVENT-HANDLER? is set non-zero in the control file.
: set-event \ task --
Set the event trigger in task TCB.
: event? \ task -- flag
Returns true if true if task has received an event
trigger which has not been cleared yet.
: clr-event-run \ --
Reset the current task's EVENT_RUN flag.
: to-event \ xt task -- ; define action of a task
Sets XT as the event handler for the task.
Message handling is only compiled if the equate MESSAGE-HANDLER? is set non-zero in the control file.
: msg? \ task -- flag
Returns true if task has received a message.
: send-message \ addr task --
Send a message to a task.
: get-message \ -- addr task
Wait for any message and return the message and the task it
came from.
: wait-event/msg \ --
Wait for a message or an event trigger.
code init-task \ xt task -- ; Initialise a task stack
Initialise a task's stack before running it and
set it to execute the word whose XT is given.
: add-task \ task -- ; insert into list
Add the task to the list of tasks after the current task.
: sub-task \ task -- ; remove task from chain
Remove the task from the task list.
: initiate \ xt task -- ; start task from scratch
Start the given task executing the word whose XT is given, e.g.
['] <name> <task> INITIATE
: sleeper \ xt task --
Start task from scratch, but leave it HALTed. Use in
the form:
['] <action> <taskname> SLEEPER
to put a task on the active task list, but as if HALTed. SLEEPER allows you to make a task ready for waking up later, perhaps by another task. This avoids having to put STOP as the first word in a task. Note that SLEEPER does not call PAUSE. See also INITIATE.
: terminate \ task --
Stop a task, and remove it from the list.
: init-multi \ -- ; initialisation with multi-tasking
Initialise the multitasker and start it. If tasking is
selected by setting the equate TASKING? in the control
file, KERNEL62.FTH will automatically run this word.
Make sure that your initialisation code includes
INIT-MULTI or your code will crash.
: his \ task uservar -- addr
Given a task id and a USER variable, returns the
address of that variable in the given task. This word is
used to set up USER variables in other tasks.
The semaphore code is only compiled if the equate SEMAPHORES? is set non-zero in the control file.
A SEMAPHORE is an extended variable used for signalling between tasks, and for resource allocation. It contains two cells, a counter and an arbiter. The counter field is used as a count of the number of times the resource may be used, and the arbiter field contains the TCB of the task that currently owns it. This field can be used for priority arbitration and deadlock detection/arbitration. The count field allows the semaphore to be used as acounted semaphore or as an exclusive access semaphore.
For example a character buffer may be used where the semaphore counter contains the number of available characters.
An exclusive access semaphore is used to share resources. The semaphore is initialised to one, usually by SIGNAL. The first task to REQUEST it gains access, and all other tasks must wait until the accessing task SIGNALs that it has finished with the resource.
: semaphore \ -- ; -- addr [child]
Creates a semaphore which returns its address at runtime.
The count field is initialised to zero for use as counted
semaphore. Use in the form:
Semaphore <name>
If you want this to be an exclusive access semaphore, follow this with:
1 <name> !
: request \ sem -- ; get access to resource, wait if count = 0
REQUEST waits until the counter field of a semaphore
is non-zero, and then decrements the counter field by one.
: signal \ addr --
SIGNAL increments the counter field of a semaphore, indicating
either that another item has been allocated to the resource, or
that it is available for use again, 0 indicating in use by a task.
TASK <name> builds a named task user area. The action of a task is assigned and the task started by the word INITIATE
['] <action> <task> INITIATE
START: is used inside a colon definition. The code before START: is the task's initialisation, performed by the current task. The code after START: up to the closing ; is the action of the task. For example:
|
All tasks must run in an endless loop, except for initialisation code. When RUN-FOO is executed, the code after START: is set up as the action of task FOO and started. RUN-FOO then exits.
If you want to perform additional actions after starting the task, you should use INITIATE to start the task.
variable task-chain \ -- addr
Anchors list of all tasks created by TASK and friends.
: task \ -- ; -- task ; TASK <name> builds a task
Note that the cross-interpreter's version of TASK has
been modified from v6.2 onwards to leave the current
section as CDATA.
: task \ -- ; -- task ; TASK <name> builds a task
Creates a new task and data area, returning the address
of the user area at run time. The task is also linked into
the task chain anchored by TASK-CHAIN.
: start: \ task -- ; exits from caller
Used inside a colon definition. The code following
START: up to the ending semi-colon forms the action
of the task. The word containing START: finishes at
START:.
: .taskBody \ addr --
Display the name of a task, given the address of the link.
: .taskBody \ addr --
Display the name of a task, given the address of the link.
: .task \ task --
Display task's name if it has one, otherwise display its
address.
: .tasks \ task -- ; display all task names
Display all the tasks anchored by TASK-CHAIN.
: .running \ --
Display all the running tasks.