home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Black Box 4
/
BlackBox.cdr
/
progc
/
cpptask.arj
/
TSKTASK.CPP
< prev
next >
Wrap
C/C++ Source or Header
|
1991-08-21
|
8KB
|
422 lines
/*
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
TSKTASK.CPP - task class member functions
Subroutines:
task::task
task::~task
task::operator new
task::start_task
task::wake_task
task::tsk_enqueue
task::tsk_unqueue
task::tsk_enqtimer
task::tsk_unqtimer
task::tsk_runable
task::set_priority
task::get_priority
task::set_state
task::get_state
task::set_user_flags
task::set_system_flags
task::get_flags
task::set_retptr
task::get_retptr
task::set_retsize
task::get_retsize
task::get_next
*/
#include "task.hpp"
#include "tsklocal.hpp"
/*
create_task
Initialises a tcb. The task is in stopped state initially.
*/
task::task (funcptr func,
byteptr stackptr,
word stksz,
word priority,
farptr arg)
{
struct task_stack far *stk;
if (func == NULL)
{
stkbot = NULL;
stack = NULL;
queue = &tsk_eligible;
state = ST_RUNNING;
flags = flags | F_CRIT;
}
else
{
stk = (struct task_stack far *)
(stackptr + stksz - sizeof (struct task_stack));
stk->r_ds = stk->r_es = tsk_dseg ();
stk->r_bp = 0;
stk->r_flags = tsk_flags ();
stk->retn = func;
stk->dummyret = killretn;
stk->arg = arg;
stkbot = stackptr;
stack = (byteptr) stk;
queue = NULL;
state = ST_STOPPED;
}
next = NULL;
prior = initprior = priority;
timerq = new timer(0, NULL, TKIND_TASK, 0);
timerq->strucp = (farptr) this;
}
/*
~task
Removes a task from the system.
CAUTION: The task control block may *not* be immediately re-used
if it was enqueued in the timer queue. Check for
task->timerq->tstate == TSTAT_IDLE before modifying
the tcb.
*/
task::~task (void)
{
byte st;
CRITICAL;
C_ENTER;
if (this != &main_tcb)
{
if ((st = state) != ST_RUNNING)
tsk_unqueue ();
queue = NULL;
tsk_kill ();
if (st == ST_RUNNING)
{
tsk_current = NULL;
tasker.schedule ();
}
C_LEAVE;
}
}
void* task::operator new(size_t size)
{
void *ptr;
ptr = tsk_alloc(size); // call protected memory allocation procedure
if (ptr)
((tcbptr) ptr)->flags = F_TEMP;
return ptr;
}
/*
tsk_kill - mark task as killed.
*/
void far task::tsk_kill (void)
{
state = ST_KILLED;
// delete timerq element only if it is IDLE, otherwise mark it for
// deletion by the timer_main function
if (timerq->tstate != TSTAT_IDLE)
{
timerq->tstate = (byte) TSTAT_REMOVE;
if (flags & F_TEMP)
timerq->tkind |= TKIND_TEMP;
}
else
delete timerq;
if (flags & F_STTEMP)
delete stack;
}
/*
start_task
Starts a stopped task. Returns -1 if the task was not stopped.
*/
int far task::start_task (void)
{
CRITICAL;
if (state == ST_STOPPED)
{
state = ST_ELIGIBLE;
C_ENTER;
tsk_enqueue (&tsk_eligible);
C_LEAVE;
return 0;
}
return -1;
}
/*
wake_task
Restarts a task waiting for an event or timeout.
Returns -1 if the task was not waiting or stopped.
*/
int far task::wake_task (void)
{
CRITICAL;
C_ENTER;
if (state >= ST_ELIGIBLE)
{
C_LEAVE;
return -1;
}
retptr = TWAKE;
tsk_wakeup ();
C_LEAVE;
return 0;
}
/*
get_priority
Returns the priority of a task.
*/
word far task::get_priority (void)
{
return prior;
}
/*
set_priority
Changes the priority of a task. If the task is enqueued in a
queue, its position in the queue is affected.
*/
void far task::set_priority (word newprior)
{
tqueptr que;
CRITICAL;
C_ENTER;
prior = initprior = newprior;
if ((state != ST_RUNNING) && ((que = queue) != NULL))
{
tsk_unqueue ();
tsk_enqueue (que);
}
C_LEAVE;
}
/*
set_user_flags
Changes the user modifiable flags of the task.
*/
void far task::set_user_flags (byte newflags)
{
CRITICAL;
C_ENTER;
flags = (flags & FL_SYSM) | (newflags & FL_USRM);
C_LEAVE;
}
/*
set_system_flags
Changes the system modifiable flags of the task.
*/
void far task::set_system_flags (byte newflags)
{
CRITICAL;
C_ENTER;
flags = (newflags & FL_SYSM) | (flags & FL_USRM);
C_LEAVE;
}
/*
tsk_enqueue inserts a task into a queue based on priority.
*/
void far task::tsk_enqueue (tqueptr que)
{
tcbptr last, curr;
last = NULL;
curr = *que;
while (curr != NULL && curr->prior >= prior)
{
last = curr;
curr = curr->next;
}
next = curr;
if (last == NULL)
*que = this;
else
last->next = this;
queue = que;
}
/*
tsk_unqueue
Removes a task from somewhere in the middle of a queue. It is only
used when stopping or prematurely waking a task, since in all other
circumstances a task is only removed from the head of a queue.
*/
void far task::tsk_unqueue (void)
{
tcbptr last, curr;
if (state == ST_RUNNING || queue == NULL)
return;
last = NULL;
curr = *queue;
while (curr != this)
{
if (curr == NULL)
return;
last = curr;
curr = curr->next;
}
if (last == NULL)
*queue = curr->next;
else
last->next = curr->next;
queue = NULL;
}
/*
tsk_enqtimer inserts a task into the timer queue.
*/
void far task::tsk_enqtimer (dword tout)
{
tlinkptr curr;
if (tout == 0)
return;
/*
Tasks are not sorted in the timer queue, so the task is inserted
at the queue head. The timer task has to step through all tasks
in the queue to cont down the timeout, so sorting would not bring
any advantages.
*/
curr = timerq;
curr->timeout = tsk_timeout(tout);
if (curr->tstate == TSTAT_IDLE)
{
curr->next = tsk_timer;
tsk_timer = curr;
}
curr->tstate = TSTAT_COUNTDOWN;
}
/*
tsk_unqtimer marks task for removal from the timer queue.
*/
void task::tsk_unqtimer(void)
{
if (timerq->tstate != TSTAT_IDLE)
timerq->tstate = (byte) TSTAT_REMOVE;
}
/*
tsk_runable
make a task eligible for running. The task is removed from the
timer queue and enqueued in the eligible queue. The old "next"
pointer of the tcb is returned. This assumes that the task
is removed from the head of a queue.
*/
tcbptr far task::tsk_runable (void)
{
tcbptr nxt;
nxt = next;
state = ST_ELIGIBLE;
tsk_unqtimer ();
tsk_enqueue (&tsk_eligible);
return nxt;
}
/*
tsk_wakeup
make a task eligible for running. The task is removed from the
timer queue and enqueued in the eligible queue.
This routine assumes that the task is removed from the middle of
a queue.
*/
void far task::tsk_wakeup (void)
{
state = ST_ELIGIBLE;
tsk_unqueue ();
tsk_unqtimer ();
tsk_enqueue (&tsk_eligible);
}
/*
tsk_wait - put current running task in wait state.
Note that the task is NOT enqueued in the respective queue
here, this is done by the scheduler based on the queue head
pointer. Only the timeout queue is affected directly.
*/
void far tsk_wait (tqueptr que, dword timeout)
{
tsk_current->state = ST_WAITING;
tsk_current->queue = que;
tsk_current->tsk_enqtimer (timeout);
tasker.schedule ();
}