<< Previous | Index | Next >>

6. Multitasking Support

RabbitSys is an operating system in the sense that it provides system-level services with a reliable interface. RabbitSys supports two basic tasking models: cooperative multitasking and preemptive multitasking. In addition, RabbitSys provides the ability to hook in a tasker.

This chapter briefly describes the support for cooperative and preemptive multitasking. Most of the chapter is used to explain how to hook in a tasker.

6.1 Cooperative Multitasking

There are no changes to the application when using the Dynamic C costate and cofunction constructs in the RabbitSys execution environment. This holds true unless you have partially disabled the system tick function, in which case, you will have to call _sys_tick explicitly in your application.

The system tick function takes one parameter. Passing in zero partially disables the system tick, meaning that it will only hit the primary watchdog and will not run RabbitSys components. This can be useful if you want RabbitSys out of the way when your application is running correctly. Of course, RabbitSys will be available over the Internet if your application should fail. If you pass anything other than zero to _sys_tick both the primary and secondary watchdogs will be hit and the RabbitSys components will run.

You can also partially disable the system tick through the Console command.


setup tick 0

6.2 Preemptive Multitasking

There are no code changes that must be made in the application when using the Dynamic C µC/OS-II module in the RabbitSys execution environment, unless you have defined stacks that are too small for the RabbitSys TCP/IP stack. A safe stack size is 4K.

Slice statements are not compatible with the use of RabbitSys.

6.3 Hooking a Tasker to the Periodic Interrupt

In addition to providing tasking support as described above, RabbitSys provides services to enable the use of your own tasker. Using the same method employed to provide services to the real-time operating system µC/OS-II, any tasker can be run on top of RabbitSys. This section describes the system services provided to the tasker and the code changes that need to be made to the tasker to set up everything.

RabbitSys provides the ability for the tasks running under the tasker to keep track of the interrupt nesting level, as well as calling the tasker's tick function on each periodic interrupt.

The function _sys_init_userosdata() must be called from the tasker to hook itself into RabbitSys.


_sys_init_userosdata( &bios_intnesting, bios_intexit,
sys_useros_tick);

The first parameter, the address of bios_intnesting, is a global interrupt nesting counter provided in the Dynamic C libraries specifically for tracking the interrupt nesting level. It is defined in the Virtual Driver interface library for RabbitSys, sysvdriver.lib. This global counter is incremented and decremented in ISRs that must be tasking aware. How do you know if your ISR must be tasking aware? If other interrupts can occur before an ISR has completed, then the ISR must be tasking aware. Also, an ISR must also be tasking aware even if it does not reenable interrupts if it signals a task to the ready state.

The second parameter, bios_intexit, is a pointer to the function that will be called when an interrupt occurs; it is called when a task must be switched to at the end of an ISR. bios_intexit is defined in sysvdriver.lib and must be modified to satisfy the requirements of your tasker. Below is the code from bios_intexit that would run if the Dynamic C µC/OS-II module was active. We will use it as a template for explaining what needs to happen in your tasker-specific code.


#ifdef MCOS
ld IX,(OSTCBCur)                 ;
task being switched out
bool HL
ld L,H
add HL,SP
ld (IX+0),HL
call OSTaskSwHook ld A,(OSPrioHighRdy)             ; OSPrioCur = OSPrioHighRdy
ld (OSPrioCur),A

ld HL,(OSTCBHighRdy)             ;
task being switched in (preempted task)
ld (OSTCBCur),HL
ld HL,(HL+os_tcb+OSTCBStkSeg)    ; Get STACKSEG of task to resume
ld A,L
ld HL,(OSTCBHighRdy)             ;
Get stack pointer of task to resume
ld HL,(HL+0)
ex DE,HL
ld B,0
ld C,A
push BC
push DE
call _sys_stack_switch
add SP,4
#endif

Typically, code that interacts with interrupts is written in assembly for speed. The above code is preparing to call the RabbitSys function _sys_stack_switch. This system call expects a segmented address in the form XX:NYYY, where N is a logical address in the stack segment, and the associated physical address is in User space. If the logical address is not of this form an error will be generated.

The last parameter of _sys_init_userosdata is sys_useros_tick, a pointer to a user-defined tick function. RabbitSys will call this function at every occurrence of the periodic interrupt so that your tasker has a sense of time passing and can perform preemptive multitasking.


RabbitSys << Previous | Index | Next>> rabbit.com