home *** CD-ROM | disk | FTP | other *** search
- /*
- CPPTask - A Multitasking Kernel For C++
-
- Version 1.0 08-12-91
-
- Ported by Rich Smith from:
-
- Public Domain Software written by
- Thomas Wagner
- Patschkauer Weg 31
- D-1000 Berlin 33
- West Germany
-
- TSKMAIN.CPP - Main routines for task handling.
-
- Subroutines:
- timer_main
- int9
- tasker_class::tasker_class
- tasker_class::~tasker_class
- tasker_class::preempt_on
- tasker_class::preempt_off
- tasker_class::tsk_ena_preempt
- tasker_class::tsk_dis_preempt
- tasker_class::schedule
- tasker_class::c_schedule
- asm_remove_tasker
-
- */
-
- #include <stdio.h>
-
- #include "task.hpp"
- #include "tsklocal.hpp"
-
- #define STACKSIZE 512
-
- /*
- The task queues:
- All tasks using a timeout, either through "t_delay" or an event wait,
- are enqueued into the "tsk_timer" queue, using the "timerq" link.
- All tasks eligible for running are enqueued in "tsk_eligible".
- The tcb-address of the current running task is stored in "tsk_current".
- */
-
- tlinkptr tsk_timer = NULL;
- timer null_timer_node(0, NULL, TKIND_TASK, 0);
- tcbptr tsk_eligible;
- tcbptr tsk_current;
-
- /*
- System flags:
- tsk_preempt is zero if preemption is allowed.
- Bit 0 is set if preemption has been disabled globally.
- Bit 1 is set for temporary disabling preemption.
- Temporary preemption is automatically removed by the
- scheduler.
-
- tsk_pretick is nonzero if a schedule request from an interrupt handler
- was rejected due to tsk_preempt nonzero. This allows
- an immediate scheduling whenever tsk_preempt is set to 0.
-
- tsk_var_prior Can be set nonzero to enable variable priority.
- Variable priority will increase the priority of
- eligible tasks on each scheduler call while they
- are waiting to be executed, so that low priority
- tasks will slowly get to the head of the eligible
- queue, getting a chance to be run. With variable
- priority off, lower priority tasks will never be
- executed while higher priority tasks are eligible.
-
- */
-
- byte tsk_preempt;
- byte tsk_pretick;
- byte tsk_var_prior;
-
- /* --------------------------------------------------------------------- */
-
- /*
- The tcb's of the standard tasks.
-
- timer_tcb is the tcb for the timer task.
- This task waits for the tsk_timer_counter, which is
- increased on every timer tick. It processes the entries
- in the timeout queue.
-
- int9_tcb is the tcb for the int9 chain task.
- This task waits for the tsk_int9_counter, which is
- increased on every system timer tick. It then chains to
- the previous timer interrupt entry.
-
- main_tcb is the "main" task which called "install_tasker". This
- task has no separate stack, rather the stack on entry
- to the scheduler is used.
-
- */
-
- counter tsk_timer_counter;
- local char timer_stack [STACKSIZE];
- local void far timer_main (void);
- local task timer_tcb((funcptr) timer_main, (byteptr) timer_stack,
- STACKSIZE, PRI_TIMER, NULL);
-
- local task main_tcb(NULL, NULL, STACKSIZE, PRI_TIMER, NULL);
-
- #if (IBM)
- counter tsk_int9_counter;
- local void far int9 (void);
- local char int9_stack [STACKSIZE];
- local task int9_tcb((funcptr) int9, (byteptr) int9_stack,
- STACKSIZE, PRI_INT9, NULL);
- #endif
-
- resource alloc_resource;
-
- #if (DOS)
- resource lower_dos;
- resource upper_dos;
- flag critical;
- #endif
-
- word keyboardbuffer[80];
- wpipe key_avail((farptr) keyboardbuffer, sizeof(keyboardbuffer));
-
- tasker_class tasker(0, 0);
-
- #if (CLOCK_MSEC)
- double tick_factor;
- #endif
-
- word ticks_per_sec;
-
-
- /*
- Un-Install-Function pointers for the optional serial and printer
- drivers. If ports are installed, the driver inserts the address
- of a remove-function here, to be called on removal of the main
- tasker.
- */
-
- funcptr v24_remove_func = NULL;
- funcptr prt_remove_func = NULL;
-
-
- /* --------------------------------------------------------------------- */
-
- #pragma check_stack(off)
-
- /*
- The timer_main task handles all timeouts.
- It maintains a single timer queue, which contains elements of the
- "tlink" structure. No other task is allowed to manipulate this queue,
- except for the insertion of new elements at the queue head. This allows
- stepping through the queue with interrupts enabled.
- CAUTION: This assumes that the operation of loading a far pointer
- is indivisible!
- */
-
- local void far timer_main (void)
- {
- tlinkptr curr;
- tlinkptr last;
- byte state;
- CRITICAL;
-
- while (1)
- {
- tsk_timer_counter.wait_counter_set (0L);
-
- last = (tlinkptr) &tsk_timer;
-
- while ((curr = last->next) != NULL)
- {
- /* Enter critical section for access to state and timeout
- variables. The timer action is also critical.
- */
- C_ENTER;
- if ((state = curr->tstate) >= TSTAT_COUNTDOWN)
- if (!--curr->timeout)
- {
- if (state == TSTAT_COUNTDOWN)
- state = (byte) TSTAT_REMOVE;
- else
- curr->timeout = curr->reload;
-
- curr->tsk_timer_action();
- }
- if (state == (byte) TSTAT_REMOVE)
- {
- last->next = curr->next;
- curr->tstate = TSTAT_IDLE;
-
- if (curr->tkind & TKIND_TEMP)
- delete curr;
-
- curr = last;
- }
- C_LEAVE;
- last = curr;
- }
- }
- }
-
- /*
- int9 is the timer interrupt chain task.
- */
-
- #if (IBM)
-
- local void far int9 (void)
- {
- while (1)
- {
- tsk_int9_counter.wait_counter_set (0L);
- tsk_chain_timer ();
- }
- }
-
- #endif
-
- /* --------------------------------------------------------------------- */
-
-
- /*
- tasker_class
- Installs the Ctask system. The internal tasks are created,
- the queues are initialised, and the interrupt handler installation
- routines are called. Task preemption is initially off.
-
- Handling of the speedup parameter is system dependent.
- */
-
- tasker_class::tasker_class (byte varpri, int speedup)
- {
- word divisor, sys_ticks;
-
- tsk_current = &main_tcb;
- tsk_eligible = NULL;
- tsk_timer = &null_timer_node;
- tsk_preempt = 1;
- tsk_pretick = 0;
- tsk_var_prior = varpri;
-
- timer_tcb.start_task ();
-
- #if (IBM)
- int9_tcb.start_task ();
-
- if (speedup <= 0 || speedup > 8)
- {
- divisor = 0;
- sys_ticks = 1;
- }
- else
- {
- divisor = 0x8000 >> (speedup - 1);
- sys_ticks = 1 << speedup;
- }
-
- ticks_per_sec = 18 * sys_ticks; /* rough number only */
-
- #if (CLOCK_MSEC)
- tick_factor = (65536.0 / (double)sys_ticks) / 1193.18;
- #endif
-
- tsk_install_timer (divisor, sys_ticks);
- tsk_install_kbd ();
- #endif
-
- #if (AT_BIOS)
- // tsk_install_bios ();
- #endif
-
- #if (DOS)
- tsk_install_dos ();
- #endif
- }
-
-
- /*
- ~tasker_class
- Calls the interrupt handler un-install routines.
- */
-
- tasker_class::~tasker_class (void)
- {
- tsk_preempt = 0;
-
- #if (AT_BIOS)
- // tsk_remove_bios ();
- #endif
- #if (IBM)
-
- if (v24_remove_func != NULL)
- v24_remove_func ();
- if (prt_remove_func != NULL)
- prt_remove_func ();
-
- /* Allow all stored clock ticks to be processed */
- int9_tcb.set_priority (0xffff);
- while (tsk_int9_counter.check_counter ())
- schedule();
-
- tsk_remove_timer ();
- tsk_remove_kbd ();
- #endif
-
- #if (DOS)
- tsk_remove_dos ();
- #endif
- }
-
-
- /*
- preempt_off
- Turns off task preemption (will stay off until explicitly enabled).
- */
-
- void far tasker_class::preempt_off (void)
- {
- tsk_preempt = 1;
- }
-
-
- /*
- preempt_on
- Resets permanent and temporary task preemption flag. If
- preemption is pending, the scheduler is called.
- */
-
- void far tasker_class::preempt_on (void)
- {
- tsk_preempt = 0;
- tsk_cli ();
- if (tsk_pretick)
- schedule ();
- tsk_sti ();
- }
-
-
- /*
- tsk_ena_preempt
- Resets temporary task preemption flag. If preemption is pending,
- the scheduler is called.
- */
-
- void far tasker_class::tsk_ena_preempt (void)
- {
- tsk_cli ();
- if (!(tsk_preempt &= ~2))
- if (tsk_pretick)
- schedule ();
- tsk_sti ();
- }
-
-
- /*
- tsk_dis_preempt
- Sets temporary task preemption flag.
- */
-
- void far tasker_class::tsk_dis_preempt (void)
- {
- tsk_preempt |= 2;
- }
-
-
- void far tasker_class::schedule(void)
- {
- asm_schedule();
- }
-
-
-
- void far tasker_class::c_schedule(void)
- {
- asm_c_schedule();
- }
-
-
- void far asm_remove_tasker(void)
- {
- tasker.tasker_class::~tasker_class();
- }
-
-
-