circuitcellar.com
Magazine Support   Digital Library   Products & Services   Suppliers Directory 
 
 





 

December 1998, Issue 101

A Minimalist Multitasking Executive


by Richard Man & Christina Willrich
Start Task Function Scheduling and Timeslice Task Context Task Control Block Global Variables Memory Management API Assembly Functions Give it a Try Enhancements References, Sources & PDF

API

In this section, we present the user-callable functions. The function prototypes and user-definable macros are in the file uexec.h.

These functions are written in ANSI C, and they shouldn’t need modification to compile for other processors similar to the ’HC11 or under different compilers. As well, some of the internal C functions shouldn’t require any modification for porting purposes.

The function int UEXC_CreateTask(void (*func)(void), unsigned char stack[], unsigned stack_size, int ticks); creates a task given the function func. Each task must have its own stack, given by the argument stack.

This stack is the lowest address of the array (i.e., address of the zero’th element). Since stack usually grows from high addresses to lower addresses, the size of the stack is needed and is given by the argument stack_size.

With the stack and stack size, the stack pointer can be checked against the bounds. If you port µexec to a processor that needs stack alignment, you need to align the stack properly.

ticks is the number of ticks in this task’s timeslice. If it is zero, then the value given by the macro DEFAULT_ TICKS is used.

UEXC_CreateTask obtains a task-control block from the free list, initializes it with the supplied arguments, and links the task-control block into the circular task list. This function returns an integer task identifier. If the task function returns, then it acts as if the function UEXC_KillTask is called with the task’s ID.

void UEXC_Defer(void); gives up the rest of the timeslice and lets other tasks run. This function calls an assembly routine to construct an interrupt-stack frame so that the task can be resumed by using ReturnFromInterrupt. This process is consistent when a task is interrupted by the timer and its timeslice runs out.

void UEXC_KillTask(int tid); is a function that kills a task with the ID tid. It searches the task list to find the matching task and reclaims its storage after it unlinks it from the list.

void UEXC_HogProcessor (void); hogs the processor and gives the current task another timeslice. If this function is called repeatedly before its timeslice is up, then no other tasks (except for the interrupt driver function) are run. It simply assigns the current_ ticks field of the task-control block with the ticks field.

int UEXC_StartScheduler (void); is the code that starts the multitasking scheduler. It should be called in your main() routine after it creates some tasks.

This function never returns to the caller, and control transfers to the created tasks unless no task was created prior to this call being made. It starts the timer interrupt and then calls the internal function Schedule to transfer control to a task.

Finally, void (*UEXC_Interrupt Driver)(void); is not actually a function but a pointer to a function. If nonnull, it should contain the address of a function you wish to call at each timer interrupt.