home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The C Users' Group Library 1994 August
/
wc-cdrom-cusersgrouplibrary-1994-08.iso
/
vol_300
/
330_03
/
tsktask.c
< prev
next >
Wrap
C/C++ Source or Header
|
1990-10-12
|
7KB
|
297 lines
/*
--- Version 2.2 90-10-12 15:47 ---
TSKTASK.C - CTask - Task creation and deletion.
CTask - a Multitasking Kernel for C
Public Domain Software written by
Thomas Wagner
Ferrari electronic Gmbh
Beusselstrasse 27
D-1000 Berlin 21
Germany
No rights reserved.
This file is new with version 2.1.
Version 2.1 separates the functions previously collected in tskmain.c into
tskmain.c - Front ends for installation/removal
tskinst.c - Install/Remove main kernel
tskgrp.c - Create/remove groups
tsktask.c - Task creation and deletion
tsktutl.c - Task utilities (get/set priority etc.)
tskutil.c - General utilities (preemption, t_delay)
*/
#include "tsk.h"
#include "tsklocal.h"
/*
tsk_use_ndp is initialized by install_tasker, and may be changed
to 0 by the user to enable or disable ndp handling for tasks
being created.
Note that setting tsk_use_ndp to 1 will have no effect if
install_tasker has determined that there is no NDP present, or
if the NDP configuration flag is FALSE.
*/
int tsk_use_ndp = 0;
#pragma check_stack(off)
/*
tsk_kill
mark task as killed.
CAUTION: Critical section assumed entered.
*/
local void Staticfunc tsk_kill (tcbptr task, int currtask)
{
/*
Note: The following test shouldn't be necessary. However,
if ever an interrupt handler should cause the current task to
be killed while the scheduler is active, this would cause
catastrophic effects (also see the notes in tskasm.asm).
Well, no interrupt handler should ever do such a nasty thing, but...
So if the in_sched flag is set, and the task is the current
task, we have to stop everything.
The test is ommitted when we're not running under DOS.
*/
#if (DOS)
if (currtask && GLOBDATA in_sched)
tsk_fatal ("Kill while in Scheduler");
#endif
task->state = ST_KILLED;
task->qhead = LNULL;
tsk_deqtimer (&task->timerq.link);
#if (TSK_NAMED)
tsk_dequeue ((queptr)&task->name.list);
#endif
#if (TSK_DYNAMIC)
if (!currtask)
{
if (task->flags & F_STTEMP)
tsk_pfree (task->stkbot); /* Bug fixed in 2.1, was 'task->stack' */
if (task->flags & F_TEMP)
tsk_pfree (task);
}
else if (task->flags & (F_STTEMP | F_TEMP))
{
task->qhead = &GLOBDATA kill_queue;
if (GLOBDATA kill_task->state == ST_STOPPED)
tsk_runable (GLOBDATA kill_task);
}
#endif
if (currtask)
schedule ();
}
/*
Killretn kills the current active task. It is used internally, but
can also be called from outside. (However, *never* call it from an
interrupt handler!)
*/
void Taskfunc killretn (void)
{
tsk_cli ();
tsk_kill (GLOBDATA current_task, 1);
}
/*
tsk_kill_queue
Removes all tasks from a queue, and marks queue invalid.
For internal use only.
CAUTION: Critical section assumed entered.
*/
void Localfunc tsk_kill_queue (queheadptr que)
{
queptr curr, next;
CHECK_QHEAD (que, "Task Kill Queue");
for (curr = que->first; !(curr->kind & Q_HEAD); )
{
next = curr->next;
tsk_kill ((tcbptr)curr, 0);
curr = next;
}
tsk_init_qhead (que, 0xff);
}
/* ---------------------------------------------------------------------- */
/*
create_task
Initialises a tcb. The task is in stopped state initially.
*/
tcbptr Globalfunc create_task (tcbptr task,
funcptr func,
byteptr stack,
word stksz,
word prior,
farptr arg
TN(byteptr name)
)
{
struct task_stack far *stk;
#if (CHECKING)
word i;
#endif
#if (TSK_DYNAMIC)
if (task == LNULL)
{
if ((task = (tcbptr) tsk_palloc (sizeof(tcb))) == LNULL)
return LNULL;
task->flags = F_TEMP;
}
else
task->flags = 0;
if (stack == LNULL)
{
if ((stack = (byteptr) tsk_palloc (stksz)) == LNULL)
{
if (task->flags & F_TEMP)
tsk_pfree (task);
return LNULL;
}
task->flags |= F_STTEMP;
}
#else
task->flags = 0;
#endif
stk = (struct task_stack far *)(stack + stksz - sizeof (struct task_stack));
stk->r_ds = task->t_es = tsk_dseg ();
stk->r_flags = tsk_flags ();
stk->retn = func;
stk->dummyret = killretn;
stk->arg = arg;
task->t_bp = 0;
task->stkbot = stack;
#if (CHECKING)
for (i = 0; i < stksz - sizeof (struct task_stack); i++)
*stack++ = (byte)i;
#endif
task->stack = (byteptr) stk;
task->cqueue.kind = TYP_TCB;
task->cqueue.next = LNULL;
task->qhead = LNULL;
task->state = ST_STOPPED;
task->cqueue.el.pri.prior = task->cqueue.el.pri.ini_prior = prior;
task->timerq.link.el.ticks = task->timerq.elem.time.reload = 0L;
task->timerq.link.kind = TYP_TIMER;
task->timerq.link.next = LNULL;
task->timerq.strucp = (farptr) task;
task->timerq.struckind = TKIND_WAKE;
task->timerq.flags = 0;
task->save_func = task->rest_func = LNULL;
#if (DOS)
task->sched_ent_func = LNULL;
#endif
task->user_ptr = LNULL;
#if (GROUPS)
task->group = task->homegroup = GLOBDATA current_task->group;
#endif
#if (DOS)
task->indos = 0;
task->t_new = 1;
task->base_psp = task->group->create_psp;
#endif
#if (TSK_NAMED)
tsk_add_name (&task->name, name, TYP_TCB, task);
#endif
#if (EMS)
if (GLOBDATA ems_savetsk != LNULL)
GLOBDATA ems_savetsk (task);
#endif
#if (NDP)
if (tsk_use_ndp && GLOBDATA ndp_present)
task->flags |= F_USES_NDP;
#endif
return task;
}
/*
kill_task
Removes a task from the system.
*/
void Globalfunc kill_task (tcbptr task)
{
CRITICAL;
CHECK_TCBPTR (task, "Kill Task");
C_ENTER;
if (task != GLOBDATA current_task)
{
if (task->state == ST_KILLED)
return;
else
tsk_dequeue (&task->cqueue);
tsk_kill (task, 0);
}
else
tsk_kill (task, 1);
C_LEAVE;
}
/*
start_task
Starts a stopped task. Returns -1 if the task was not stopped.
*/
int Globalfunc start_task (tcbptr task)
{
CRITICAL;
if (task == LNULL)
#if (GROUPS)
task = GLOBDATA current_task->group->main_ptr;
#else
task = GLOBDATA main_ptr;
#endif
CHECK_TCBPTR (task, "Start Task");
if (task->state == ST_STOPPED)
{
task->state = ST_ELIGIBLE;
C_ENTER;
tsk_runable (task);
C_LEAVE;
return 0;
}
return -1;
}