📄 rtexec.c
字号:
#include "includes.h"
/****************************************************************************
* Disable all compiler optimizations (except register variables) for this
* module. Common-subexpression optimizations place hidden local variables on
* procedure stacks. Most of the procedures in this module need to know their
* exact invocation sequences in order to manipulate the machine context.
****************************************************************************/
#pragma option -Od -Z- -r
/* Real-time executive functions are collected together in this module. */
extern void TBeep(void); /* Beeper management task */
extern void TDisplay(void); /* Display update task */
extern void TProcSbf(void); /* Process subframes task */
extern void TRTCM(void); /* Differential corrections task */
/****************************************************************************
* Task definitions. The context that exists when the program begins
* executing becomes the lowest priority task, which must have the task
* name "MAIN". Since the list is in priority order, MAIN is always at
* the end of the list.
****************************************************************************/
tcbstruc TCB[] =
{
{"TBeep",2000,TBeep,NULL}, /* Beep task (mostly a case study). */
{"TDisplay",10000,TDisplay,NULL}, /* Display update task. */
{"TRTCM",4000,TRTCM,NULL}, /* Differential corrections task. */
{"TProcSbf",4000,TProcSbf,NULL}, /* Process subframes task. */
{"MAIN",0,NULL,NULL} /* MAIN must be at the end. */
};
/* Information about Current Task. */
int CurrentTask; /* TCB index of CurrentTask. */
unsigned CurrentStack; /* CurrentTask's private stack segment. */
/* Index of the TCB at the head of the suspended list. This list is
ordered by the scheduled activation times. A link of -1 indicates
the end of the suspended list. */
int SuspTask;
/* Index of the MAIN task (it's always the last entry in the TCB array). */
int MainTask;
unsigned savedSS,savedSP,taskSS,taskSP,taskCS,taskIP;
unsigned InitSegTemp,InitOffTemp;
unsigned far *InDOSPtr;
/****************************************************************************
* Function: void InitialiseTasks(void)
*
* Allocate stacks for each task from the far heap. Initialize all the tasks
* preassigned in the data structure TCB. (The exact initialization procedure
* is be compiler-dependent. The initialisation used here is appropriate for
* Borland C/C++.) Place all the tasks on the suspended list except MAIN,
* which will be left executing and identified as CurrentTask, the current
* active task.
*
* Input: None.
*
* Output: None.
*
* Return Value: None.
****************************************************************************/
void InitialiseTasks(void)
{
int i;
_AH = 0x34; /* Save a pointer to the InDOS flag. */
geninterrupt(0x21);
InDOSPtr = (unsigned int *)MK_FP(_ES,_BX);
PROTECT++;
/* Allocate stacks for all the tasks (except MAIN, which already has
a stack and is currently running). */
i=0;
while(stricmp(TCB[i].TNAME,"MAIN"))
{
if(TCB[i].TSTKSIZE < 2000)
{
printf("\nERROR: %s task stack size is too small. "
"Increase it.\r\n",TCB[i].TNAME);
QuitGpsBuilder();
}
TCB[i].TSTACK = farmalloc(TCB[i].TSTKSIZE+32);
if(TCB[i].TSTACK==NULL)
{
printf("\nERROR: Insufficient conventional memory.\r\n");
QuitGpsBuilder();
}
TCB[i].STRTSS = FP_SEG(TCB[i].TSTACK)+FP_OFF(TCB[i].TSTACK)/16+1;
TCB[i].MinSP = TCB[i].STRTSP = TCB[i].TSTKSIZE;
/* Clone the floating point emulator/coprocessor interface data
structures which exist in the low addresses of the task's stack
segment. The number of bytes that needs to be cloned grows with
each BC revision, so we are doing 1024 to be conservative. */
_fmemcpy(MK_FP(TCB[i].STRTSS,0),MK_FP(MStkSS,0),1024);
i++;
}
MainTask = i; /* Save the index of the MAIN task. */
/* Show MAIN as the current task (it's active, too). */
TCB[MainTask].STRTSS = MStkSS; /* Saved at invocation of main(). */
TCB[MainTask].STRTSP = TCB[MainTask].MinSP = MStkSP;
TCB[MainTask].Active = 1;
CurrentTask = MainTask;
CurrentStack = TCB[MainTask].STRTSS;
/* Place all the other tasks on the suspended list with zero suspend
intervals, and mark them inactive. */
SuspTask = 0;
for(i=0;i<MainTask;i++)
{
TCB[i].Active = 0;
TCB[i].SuspTics = 0;
if((i+1)==MainTask)
TCB[i].NxtSusp=-1;
else
TCB[i].NxtSusp = i+1;
}
if(_8087)
{
/* Wait for any pending coprocessor operation to complete before
disabling interrupts. Then save the coprocessor state, and wait
for the save to complete before proceeding. */
InitSegTemp = FP_SEG(TCB[MainTask].SAV8087);
InitOffTemp = FP_OFF(TCB[MainTask].SAV8087);
asm{
mov es,InitSegTemp
mov bx,InitOffTemp
fwait
cli
fsave es:[bx]
fwait
sti
}
}
/* Initialize the task contexts. Important note: do not reference
local variables while the stack pointer is being redirected. */
for(i=0;i<MainTask;i++)
{
InitSegTemp = FP_SEG(TCB[i].SAV8087); /* FP context save pointer. */
InitOffTemp = FP_OFF(TCB[i].SAV8087);
taskSS = TCB[i].STRTSS;
taskSP = TCB[i].STRTSP;
taskCS = FP_SEG(TCB[i].TSTART);
taskIP = FP_OFF(TCB[i].TSTART);
/* No local variable references or procedure calls should be made
until further notice (see below). */
savedSS = _SS;
savedSP = _SP;
_CX = taskCS;
_DX = taskIP;
_SS = taskSS;
_SP = taskSP;
/* NOTE: Borland C versions 3.1 and earlier saved only a 16-bit
context when entering routines declared as "interrupt". Borland
C/C++ version 4.0 saves a 32-bit context (when compiling in 32-bit
mode). Thus, the construction of a task's initial context must
be handled differently under the two compiler revisions. */
#if (CompilerVersion > 31) && (INSTRMODE==32)
/* Construct an initial version 4.0 32-bit context. Push the
following onto the empty stack:
Flags
CS part of task starting address
IP part of task starting address
Initial values for: eax,ebx,ecx,edx,es (zeroes)
Initial value for ds (set to DGROUP, same as for MAIN)
Initial values for: esi,edi,bp (0)
The task's stack looks like the invocation of an interrupt
procedure with no local variables. */
asm{
pushf /* Task's initial flag settings. */
pop ax /* Task must start with interrupts enabled. */
or ax,200h
push ax
push cx
push dx
push 0 /* Initial (32-bit) eax value. */
push 0
push 0 /* Initial (32-bit) ebx value. */
push 0
push 0 /* Initial (32-bit) ecx value. */
push 0
push 0 /* Initial (32-bit) edx value. */
push 0
push 0 /* Initial (16-bit) es value. */
push ds /* Initial (16-bit) ds value. */
push 0 /* Initial (32-bit) esi value. */
push 0
push 0 /* Initial (32-bit) edi value. */
push 0
push 0 /* Initial (16-bit) bp value. */
}
#endif
#if (CompilerVersion > 31) && (INSTRMODE==16)
/* Construct an initial version 4.0 16-bit context. Push the
following onto the empty stack:
Flags
CS part of task starting address
IP part of task starting address
Initial values for: ax,bx,cx,dx,es (zeroes)
Initial value for ds (set to DGROUP, same as for MAIN)
Initial values for: si,di,bp (0)
The task's stack looks like the invocation of an interrupt
procedure with no local variables. */
asm{
pushf /* Task's initial flag settings. */
pop ax /* Task must start with interrupts enabled. */
or ax,200h
push ax
push cx
push dx
push 0 /* Initial (16-bit) ax value. */
push 0 /* Initial (16-bit) bx value. */
push 0 /* Initial (16-bit) cx value. */
push 0 /* Initial (16-bit) dx value. */
push 0 /* Initial (16-bit) es value. */
push ds /* Initial (16-bit) ds value. */
push 0 /* Initial (16-bit) si value. */
push 0 /* Initial (16-bit) di value. */
push 0 /* Initial (16-bit) bp value. */
}
#endif
#if (CompilerVersion == 31)
/* Construct an initial version 3.1 context. Push the following
onto the empty stack:
Flags
CS part of task starting address
IP part of task starting address
Initial values for: ax,bx,cx,dx,es (zeroes)
Initial value for ds (set to DGROUP, same as for MAIN)
Initial values for: si,di,bp (0)
The task's stack looks like the invocation of an interrupt
procedure with no local variables. */
asm{
pushf /* Task's initial flag settings. */
pop ax /* Task must start with interrupts enabled. */
or ax,200h
push ax
push cx
push dx
push 0 /* Initial (16-bit) ax value. */
push 0 /* Initial (16-bit) bx value. */
push 0 /* Initial (16-bit) cx value. */
push 0 /* Initial (16-bit) dx value. */
push 0 /* Initial (16-bit) es value. */
push ds /* Initial (16-bit) ds value. */
push 0 /* Initial (16-bit) si value. */
push 0 /* Initial (16-bit) di value. */
push 0 /* Initial (16-bit) bp value. */
}
#endif
#if (CompilerVersion==31) && (INSTRMODE==32)
/* If we're in compiler version 3.1 and generating 32-bit
instructions, add some logic to save and restore the 32-bit
registers. */
asm{
db 0x66 /* OPSIZ: */
db 0x60 /* PUSHA */
}
#endif
asm{
cli
fninit /* Initialize H/W coprocessor or S/W emulator */
fwait
sti
}
taskSS = _SS;
taskSP = _SP;
if(_8087)
{
/* Wait for any pending coprocessor operation to complete before
disabling interrupts. Then save the coprocessor state, and
wait for the save to complete before proceeding. */
asm{
mov es,InitSegTemp
mov bx,InitOffTemp
fwait
cli
fsave es:[bx]
fwait
sti
}
} /* Of for() tasks. */
_SS = savedSS;
_SP = savedSP;
/* Now it is OK to reference local variables and make procedure
calls. */
TCB[i].SAVSS = taskSS;
TCB[i].SAVSP = taskSP;
}
if(_8087)
{
/* Restore MAIN's hardware coprocessor state. */
InitSegTemp = FP_SEG(TCB[MainTask].SAV8087);
InitOffTemp = FP_OFF(TCB[MainTask].SAV8087);
asm{
mov es,InitSegTemp
mov bx,InitOffTemp
cli
frstor es:[bx]
fwait
sti
}
}
PROTECT--;
}
int Cur,Prev,Next;
unsigned TaskBeingSuspended;
unsigned NewStackSeg,NewStackPtr;
unsigned TotalSuspTics;
unsigned SuspTics;
unsigned SuspSegTemp,SuspOffTemp;
/****************************************************************************
* Function: void interrupt far ExecSuspendFunction(void)
*
* No action is taken if CurrentTask is MAIN or still has additional
* activation counts (which may result from activations which occur while the
* task is in progress). Otherwise, the context of CurrentTask is saved,
* partly on its stack and partly in its TCB entry. The task being suspended
* (the former CurrentTask) is added to the suspended list according to its
* suspension interval. The highest priority active task is identified. Its
* context is restored and it is resumed. The newly suspended task will resume
* execution when either 1) Its suspend interval expires, or 2) Another task
* explicitly activates it.
*
* This routine cannot declare any local variables or take any stack
* arguments. Its argument, the number of TICS to suspend the calling task,
* is passed in the _AX register. The task whose TCB index is in CurrentTask
* must in fact be the current task.
*
* Input: None.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -