📄 rtexec.c
字号:
*
* Output: None.
*
* Return Value: None.
****************************************************************************/
void interrupt far ExecSuspendFunction(void)
{
/* DO NOT declare any local variables. */
disable();
#if (CompilerVersion==31) && (INSTRMODE==32)
asm{
db 0x66 /* OPSIZ:. */
db 0x60 /* PUSHA. */
}
#endif
PROTECT++;
SuspTics = _AX;
if(CurrentTask==MainTask)
{
PROTECT--;
#if (CompilerVersion==31) && (INSTRMODE==32)
asm{
db 0x66 /* OPSIZ:. */
db 0x61 /* POPA. */
}
#endif
return; /* MAIN cannot be suspended. */
}
if(TCB[TaskBeingSuspended].Active > 1)
{
/* The task still has activation counts. Let it continue. */
TCB[TaskBeingSuspended].Active -= 1;
PROTECT--;
#if (CompilerVersion==31) && (INSTRMODE==32)
asm{
db 0x66 /* OPSIZ: */
db 0x61 /* POPA */
}
#endif
return;
}
/* Save the context of the task being suspended. */
TaskBeingSuspended = CurrentTask;
if(_8087)
{
/* Save the coprocessor state without waiting for the pending
operation to complete. Wait for the save to complete before
proceeding. */
SuspSegTemp = FP_SEG(TCB[TaskBeingSuspended].SAV8087);
SuspOffTemp = FP_OFF(TCB[TaskBeingSuspended].SAV8087);
asm{
mov es,SuspSegTemp
mov bx,SuspOffTemp
fnsave es:[bx]
fwait
}
}
TCB[TaskBeingSuspended].SAVSS = _SS;
TCB[TaskBeingSuspended].SAVSP = _SP;
/* Find where to place the task in the suspend list. */
if(SuspTask == -1)
{
/* Suspend list is empty: put task at the head of the list. */
SuspTask = TaskBeingSuspended;
TCB[TaskBeingSuspended].SuspTics = SuspTics;
TCB[TaskBeingSuspended].NxtSusp = -1;
}
else
{
/* Suspend list is nonempty: insert task in the list. */
TotalSuspTics = 0;
Cur = SuspTask;
Prev = -1;
while(TRUE)
{
if(SuspTics < (TCB[Cur].SuspTics+TotalSuspTics))
{
/* The task which is being suspended is scheduled to resume
before Cur. Insert the new entry before this task. Note
that the newly suspended task is inserted into the list
AFTER all other tasks which have suspension intervals that
expire at the same time. */
TCB[TaskBeingSuspended].NxtSusp = Cur;
TCB[Cur].SuspTics -= (SuspTics - TotalSuspTics);
if(Prev == -1)
{
SuspTask = TaskBeingSuspended;
TCB[TaskBeingSuspended].SuspTics = SuspTics;
}
else
{
TCB[Prev].NxtSusp = TaskBeingSuspended;
TCB[TaskBeingSuspended].SuspTics =
SuspTics - TotalSuspTics;
}
break;
}
TotalSuspTics += TCB[Cur].SuspTics;
Prev = Cur;
Cur = TCB[Cur].NxtSusp;
if(Cur == -1)
{
/* The task now being suspended is scheduled to resume later
than any other task in the suspend list. Insert it at the
end of the list. */
TCB[Prev].NxtSusp = TaskBeingSuspended;
TCB[TaskBeingSuspended].NxtSusp = -1;
TCB[TaskBeingSuspended].SuspTics = SuspTics - TotalSuspTics;
break;
}
}
}
/* Inactivate TaskBeingSuspended. Find the highest priority active
task and make it the new current task. */
TCB[TaskBeingSuspended].Active = 0;
for(CurrentTask=0;CurrentTask<=MainTask;CurrentTask++)
if(TCB[CurrentTask].Active)
break;
CurrentStack = TCB[CurrentTask].STRTSS;
TCB[CurrentTask].Slices++;
/* Restore the context of the new CurrentTask and resume it. */
_SS = TCB[CurrentTask].SAVSS;
_SP = TCB[CurrentTask].SAVSP;
if(_8087)
{
SuspSegTemp = FP_SEG(TCB[CurrentTask].SAV8087);
SuspOffTemp = FP_OFF(TCB[CurrentTask].SAV8087);
asm{
mov es,SuspSegTemp
mov bx,SuspOffTemp
frstor es:[bx]
fwait
}
}
PROTECT--;
#if (CompilerVersion==31) && (INSTRMODE==32)
asm{
db 0x66 /* OPSIZ: */
db 0x61 /* POPA */
}
#endif
return;
}
/****************************************************************************
* Function: void Suspend(unsigned SuspTics)
*
* This is an interface between ExecSuspendFunction and calling tasks. This is
* because calling tasks cannot pass a parameter reentrantly to an procedure
* defined as interrupt without using a register, and it's inelegant to
* require an application-level task to use in-line assembly language. Can
* only be called from a task. Suspends the calling task for a specified
* interval.
*
* Input: SuspTics - suspend interval in TICs.
*
* Output: None.
*
* Return Value: None.
****************************************************************************/
void Suspend(unsigned SuspTics)
{
_AX = SuspTics;
ExecSuspendFunction();
}
volatile TaskBeingActivated;
volatile ActSegTemp,ActOffTemp;
/****************************************************************************
* Function: void interrupt far ExecActivateFunction(void)
*
* Removes a task from the suspend list (if it is there) and marks it
* activated. If the task is higher priority that the one that activated it
* by calling this routine, a task switch takes place. This routine cannot
* declare any local variables or take any stack arguments. Its argument, the
* index of the task to be activated, is passed in the _AX register. The
* specified task is removed from the suspended list, if it was in fact
* suspended. The activation count of the task is incremented. If the calling
* task cannot be positively identified as the CurrentTask, we leave the
* situation there and return to the caller. Otherwise, the priority of the
* CurrentTask is compared with the priority of the newly activated task.
* Depending on whether the newly acttivated task is higher priority, the
* context of CurrentTask may be saved and a switch to the newly activated
* task performed.
*
* Input: None.
*
* Output: None.
*
* Return Value: None.
****************************************************************************/
void interrupt far ExecActivateFunction(void)
{
/* DO NOT declare any local variables. */
#if (CompilerVersion==31) && (INSTRMODE==32)
asm{
db 0x66 /* OPSIZ:. */
db 0x60 /* PUSHA. */
}
#endif
PROTECT++;
TaskBeingActivated = _AX;
/* Remove the task from the suspended list (if it is on that list). */
if(SuspTask != -1)
{
Cur = SuspTask;
Prev = -1;
while(TRUE)
{
if(Cur == -1) /* Task wasn't in the suspend list. */
break;
if(Cur != TaskBeingActivated) /* Other task. Keep searching. */
{
Prev = Cur;
Cur = TCB[Cur].NxtSusp;
continue;
}
/* "Cur" is the index of the task to be activated. Take it out
of the suspend list. */
Next = TCB[Cur].NxtSusp;
if(Prev == -1)
SuspTask = Next;
else
TCB[Prev].NxtSusp = Next;
if(Next != -1)
TCB[Next].SuspTics += TCB[Cur].SuspTics;
break;
}
}
disable();
TCB[TaskBeingActivated].Active += 1; /* Incr task's activation count. */
/* Don't switch tasks if:
1) We weren't called from the context of the current application
task (that is, the active stack isn't the one that was
originally assigned to the task), or
2) The caller was in a protected region of code, as indicated by
PROTECT. This is indicated if PROTECT>1, since on entry to
this routine we incremented PROTECT.
In these cases, just leave the task in the active list and it will
eventually get into execution through the normal operation of the
task switcher. */
if(_SS!=CurrentStack || PROTECT>1)
{
PROTECT--;
#if (CompilerVersion==31) && (INSTRMODE==32)
asm{
db 0x66 /* OPSIZ:. */
db 0x61 /* POPA. */
}
#endif
return;
}
/* If TaskBeingActivated has equal or lower priority than CurrentTask,
just return to the calling task. Otherwise, save CurrentTask's
context, select a new CurrentTask, and resume it. */
if(TaskBeingActivated < CurrentTask)
{
/* Save the context of CurrentTask. */
if(_8087)
{
/* Save the coprocessor state without waiting for any pending
operation to complete, then wait for the save to complete
before proceeding. */
ActSegTemp = FP_SEG(TCB[CurrentTask].SAV8087);
ActOffTemp = FP_OFF(TCB[CurrentTask].SAV8087);
asm{
mov es,ActSegTemp
mov bx,ActOffTemp
fnsave es:[bx]
fwait
}
}
TCB[CurrentTask].SAVSS = _SS;
TCB[CurrentTask].SAVSP = _SP;
/* TaskBeingActivated is the new CurrentTask. */
CurrentTask = TaskBeingActivated;
CurrentStack = TCB[CurrentTask].STRTSS;
TCB[CurrentTask].Slices++;
/* Restore the new CurrentTask's context. */
_SS = TCB[CurrentTask].SAVSS;
_SP = TCB[CurrentTask].SAVSP;
if(_8087)
{
ActSegTemp = FP_SEG(TCB[CurrentTask].SAV8087);
ActOffTemp = FP_OFF(TCB[CurrentTask].SAV8087);
asm{
mov es,ActSegTemp
mov bx,ActOffTemp
frstor es:[bx]
fwait
}
}
}
PROTECT--;
#if (CompilerVersion==31) && (INSTRMODE==32)
asm{
db 0x66 /* OPSIZ:. */
db 0x61 /* POPA. */
}
#endif
return;
}
/****************************************************************************
* Function: void Activate(char *TaskName)
*
* This is an interface between ExecActivateFunction and calling tasks. This
* is because calling tasks cannot pass a parameter reentrantly to an
* procedure defined as interrupt without using a register, and it's
* inelegant to require an application-level task to use in-line assembly
* language. Can only be called from a task. Activates the specified task,
* cancelling a suspend interval if necessary. May cause a task switch if the
* activated task is higher priority that the calling task.
*
* Input: TaskName - pointer to the task name string.
*
* Output: None.
*
* Return Value: None.
****************************************************************************/
void Activate(char *TaskName)
{
int i;
for(i=0;i<MainTask;i++)
{
if(stricmp(TCB[i].TNAME,TaskName)==0)
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -