home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Power-Programmierung
/
CD1.mdf
/
magazine
/
drdobbs
/
1987
/
12
/
holub
/
kernel.h
< prev
next >
Wrap
Text File
|
1987-12-21
|
15KB
|
178 lines
#ifndef NULL
#include <stdio.h>
#endif
#include <tools/pq.h>
/* Error codes */
#define TE_NOERR 0 /* No error */
#define TE_TOOMANY -1 /* Maximum number of tasks (32) already exists */
#define TE_NOMEM -2 /* Insufficient memory available */
#define TE_BADARG -3 /* Illegal Argument */
#define TE_TIMEOUT -4 /* Timeout */
#define TE_QFULL -5 /* Queue is full */
#define TE_NOTASKS -6 /* No tasks to send message */
#define TE_INTERNAL -7 /* Internal error */
#define TE_DEADLOCK -8 /* Delete would have caused a deadlock. */
#define TE_STACK -9 /* Stack overflow */
#define TE_KILL -10 /* Ctrl-Break encountered */
#define TS_NORMAL 0 /* Must be 0 */
#define TS_WAIT 1
#define TS_TIMEOUT 2
#define T_MAXTASK 32 /* Max. number of tasks that can be active */
#define TQ_SIG 0xa5a5 /* Signature used for queues to test validity */
/* PRIORITY(a,b) evaluates to a neagive number if task a is lower priority
* than task b, to 0 if they're equal, to a positive number
* if task a is higher priority than task b. If priorities
* are the same, the timestamps are compared and the routine
* with the smaller (older) time stamp is assumed to be the
* higher priority.
*/
#define T_PRIORITY(a,b) ( ((a)->priority != (b)->priority) \
? (a)->priority - (b)->priority \
: (b)->timestamp - (a)->timestamp )
/*----------------------------------------------------------------------
* Task Control Block. Do not change the register-save area
* (ax, bx, cx ... ) without also changing the code in swap.asm.
* Don't change anything without changing the offset to the stack
* base in chkstk.asm.
*
* I'm assuming the small model here. That is, I'm assuming that
* the only segment register that can change is the extra segment
* and that the stack and data segments always have the same value.
*
* Be sure to block() if you're going to modifiy the CS, DS, or SS
* registers.
*
* A context swap is done by pushing the registers in the following
* order:
* flags,cs,ip,ax,bx,cx,dx,si,di,bp,ds,es
*
* Then, the current stack pointer is saved in the TCB. Context is
* restored by popping es,ds,bp,di,si,dx,cx,bx, and ax, and then
* restoring the flags, cs, and ip with an iret instruction.
*/
typedef struct tcb
{
void **sp; /* Must be first and must be 16 bits */
unsigned ss; /* Must be second & must be 16 bits */
unsigned priority; /* priority 0=lowest, 65,535=highest */
unsigned long timestamp; /* Clock tick when task was preempted. */
unsigned wait; /* Counting semaphore used by tasks that
* are waiting at a queue. Set to initial
* timeout value and decremented on each
* clock tick. Task is put back into
* the active list if semaphore gets to
* 0. If wait < 0, task will not time out.
*/
struct tcb *next; /* Pointer to next task waiting at queue. */
int status; /* TS_NORMAL Not suspended by wait.
* TS_WAIT Suspended by wait
*/
void *msg; /* Dequeued message if task was waiting
* for a message. NULL if task timed out.
*/
/* The following are handy for debugging */
/* but aren't used for anything else */
char *tag; /* Identifying string of some sort */
void **initial_sp; /* Initial stack pointer */
void *stack[1]; /* First cell of stack. Must be last
* thing in the structure. Must be declared
* as pointer-sized for t_create().
*/
}
TCB;
typedef struct t_queue
{
int signature; /* Signature */
struct t_queue *next; /* Next queue in chain. */
TCB *task_h; /* Head (start) of task list. */
TCB *task_t; /* Tail (end) of task list. */
int q_size; /* Maximum number of elements */
int numele; /* # of elements currently in queue */
void **headp; /* Head pointer */
void **tailp; /* Tail pointer */
void *queue[1]; /* First cell of actual queue.
* Must be at the bottom of the
* structure.
*/
}
T_QUEUE;
/*----------------------------------------------------------------------
* Global variables. Actually declared in globals.c. I'm assuming
* the default initialization to 0 here. These may be used by
* your programs (T_clock and T_numtasks are useful) but should
* never be modified by them. It's safest to block while
* accessing them.
*/
#ifdef ALLOC
# define CLASS
# define I(x) x
#else
# define CLASS extern
# define I(x)
#endif
CLASS PQ *T_tasks I(=0); /* Priority queue of tasks that are waiting */
/* for service. See /src/tools/pq.c for priority */
/* queue routines and definition of PQ. */
CLASS TCB *T_active I(=0); /* Pointer to currently active task. NULL if
* multitasking is off or if no tasks are active
* (this latter is a deadlock).
*/
CLASS unsigned long T_clock I(=0);
/* Incremented on each system clock tick. If you
* assume the default 18.2 ticks/second,
* the clock will roll over after about
* 65552 hours (about 7.47 years):
*
* ((0xffffffff/18.2) /60) /60 == 65552
* 65552 / 24 /365.35 == 7.47798
*
* Of course, this number will scale with faster
* tick rates but the resolution should be ok for
* all reasonable tick rates.
*/
CLASS T_QUEUE *T_queues I(=0); /* Pointer to head of linked list of queues. */
CLASS int T_numtasks I(=0); /* Total # of tasks that have been created. */
/*----------------------------------------------------------------------
* Function prototypes. You should never call any of the _t_xxxx
* functions directly.
*/
extern T_QUEUE *t_makequeue (int size );
extern int t_send (T_QUEUE *q, void *msg );
extern void *t_wait (T_QUEUE *q, int timeout );
extern int t_yield (void );
extern int t_perror (char *str, int errcode );
extern int t_start (int factor );
extern TCB *t_create (int (*subr)(), char* tag, unsigned pri,
int stk_size,...);
extern int t_chg_priority (TCB *tp, int new_priority );
extern int t_delete (TCB *task );
extern int t_print (TCB *task );
extern void t_stop (int exit_code );
extern int t_second (void );
extern void _t_swap (TCB *old, TCB *new );
extern void _t_install (TCB *new );
extern void _t_shazam (void );