📄 basetask.cpp
字号:
void CriticalSectionEnd (void)
{
DisableInterrupt();
CriticalCounter--; // decrement for each exit
if(CriticalCounter <= 0)
{
// Only remove critical status when leaving the last nesting
CriticalSection = 0;
CriticalCounter = 0; // Make sure counter is at 0 (ignore
// extra ENDs)
}
EnableInterrupt();
}
#ifdef ISR_SCHEDULING
// File scope global variables for interrupt service routine
// Keep track of preemption (reentry) with this flag
static int ReentryInterrupt = 0;
static int ReentryPreemptable = 0;
int ReentryLevel = 0;
// Allocate static memory to save the floating point processor
// state apon reentry. The compiler (Borland C++ 4.5) does not
// take care of this even for a void interrupt type function.
static far char FPU_Buffer[94 * 2];
// Function to be installed as interrupt service routine
void interrupt TimerISR(...)
{
// Save the state of the floating point unit to the FPU.
// Calling fsave [DI] causes all the FPU's internal
// registers to be saved to a memory location pointed to
// by DI and referenced by the segment register DS.
// Therefore, before calling fsave we must set DS to the
// data segment of the FPU "stack" space, since defining
// FPU_Buffer as a file-scope global has put it in a data
// segment which may be different from the one we're in
// when this ISR runs. DI gets the offset into that data
// segment at which the FPU state will go.
// --------------------------------------------------------
// Assembly code to save the state of the floating
// point processor.
DisableInterrupt ();
unsigned Save_DI = FP_OFF (FPU_Buffer) + (94*ReentryLevel);
unsigned Save_DS = FP_SEG (FPU_Buffer);
asm push DS // Push the data segment in which the ISR is
_DI = Save_DI; // intended by the compiler to run; then get
_DS = Save_DS; // DI and DS from the local, automatic vars.
asm fsave [DI] // in which they were saved and use them to
asm fwait // save the FPU state. Then pop DS because
asm pop DS // it's needed for dealing with other data
EnableInterrupt ();
// Read the real time clock so that we avoid an overflow and
// don't lose track of time.
GetTimeNow();
// IF the program is in a critical section - signified by a
// a call to CriticalSectionBegin() - don't allow any scheduling.
if (CriticalSection||ReentryInterrupt)
{
// Clean up and return from interrupt
DisableInterrupt ();
asm push DS
_DI = Save_DI; // Get the data segment and offset at which
_DS = Save_DS; // we saved the FPU state; use to restore
asm frstor [DI]// the FPU state. Wait until FPU is fully
asm fwait // restored before going back to background
asm pop DS
EnableInterrupt ();
TimerEOI (); // Re-enable hardware timer interrupt
return;
}
ReentryLevel ++;
ReentryInterrupt = 1;
// Re-enable hardware timer interrupt. From this point on,
// this function may reenter, possibly allowing a third thread.
TimerEOI ();
// Run Interrupt list
// Sequentially run all of the Interrupt tasks once. If
// there is some sort of problem, call StopControl and let
// the scheduling loop in the main() function (the parent thread)
// handle exiting the program cleanly.
if (TaskDispatcher(NULL, Interrupt))
StopControl("\n***Problem with Interrupt list***\n");
DisableInterrupt ();
ReentryInterrupt = 0;
EnableInterrupt ();
// If this call to the ISR was reentrant, don't allow
// preemptable list to be processed.
if(ReentryPreemptable)
{
// Clean up and return from interrupt
DisableInterrupt ();
ReentryLevel --;
asm push DS
_DI = Save_DI; // Get the data segment and offset at which
_DS = Save_DS; // we saved the FPU state; use to restore
asm frstor [DI]// the FPU state. Wait until FPU is fully
asm fwait // restored before going back to background
asm pop DS
EnableInterrupt ();
return;
}
DisableInterrupt ();
ReentryPreemptable = 1;
EnableInterrupt ();
// Run Preemptable list
// Sequentially run all of the Preemptable tasks once. If
// there is some sort of problem, call StopControl and let
// the scheduling loop in the main() function (the parent thread)
// handle exiting the program cleanly.
if (TaskDispatcher(NULL, Preemptable))
StopControl("\n***Problem with Preemptable list***\n");
// Clean up and return from interrupt
DisableInterrupt ();
ReentryPreemptable = 0;
ReentryLevel --;
asm push DS
_DI = Save_DI; // Get the data segment and offset at which
_DS = Save_DS; // we saved the FPU state; use 'em to restore
asm frstor [DI]// the FPU state. Wait until FPU is fully
asm fwait // restored before going back to background
asm pop DS
EnableInterrupt ();
return;
}
static void interrupt (*oldvec)(...);
// Set up the timer interrupt
void SetupTimerInterrupt(void)
{
// Declaration for a pointer to an interrupt service function
// in which the previous interrupt vector (probably DOS clock)
// will be stored and later reinstalled from.
// Set the desired period for the timer ISR (in sec)
SetupClock(GetTickRate());
cout << "setting interrupt tickrate to :" << GetTickRate() << " sec\n";
// Disable interrupts while setting up a new ISR
DisableInterrupt ();
// Get existing vector
oldvec = _dos_getvect(8);
// Replace it with the new timer interrupt function
_dos_setvect(8,TimerISR);
// Enable interrupts when done
EnableInterrupt ();
}
void RestoreTimerInterrupt(void)
{
DisableInterrupt ();
// Restore the timer interrupt to what it was
_dos_setvect(8,oldvec);
// Reset the default mode for the timer (DOS)
SetupClock(-1.0);
EnableInterrupt ();
}
#endif // ISR_SCHEDULING
// Functions associated with the class DataOutput
// Constructor for time-based array sizing
DataOutput::DataOutput(int nvars,double STime,double LTime,double DTime)
{
MaxOutputs = 0; // Make sure that Init... doesn't try an illegal delete!
NVars = 0;
BaseTime = 0.0; // Default value
if(InitDataOutput(nvars,STime,LTime,DTime) == -1)
{
StopControl("Can't initialize for output data\n");
}
}
// Constructor for direct array sizing
DataOutput::DataOutput(int nvars,long nrows)
{
MaxOutputs = 0; // Make sure that Init... doesn't try an illegal delete!
NVars = 0;
StartTime = 0.0; // Not used in this mode - make sure they have
LastTime = 0.0; // legal values
DeltaTime = 0.0;
NextTime = 1.e20;
BaseTime = 0.0; // Default value
if(InitDataOutput(nvars,nrows) == -1)
{
StopControl("Can't initialize for output data\n");
}
}
DataOutput::~DataOutput() // Destructor
{
// If output arrays exist, delete them
if(MaxOutputs != 0)delete [] TimeRecord;
if(NVars != 0)
{
for(int i = 0; i < NVars; i++)delete [] OutRecord[i];
delete [] OutRecord;
}
}
int DataOutput::SetUpArrays(int nvars,long nrows)
{
if((TimeRecord = new double[nrows]) == NULL)
{
return(-1);
}
for(int i = 0; i < nvars; i++)
{
if((OutRecord[i] = new double[nrows]) == NULL)
{
return(-1);
}
}
MaxOutputs = nrows;
OutCount = 0;
NVars = nvars;
return(0);
}
int DataOutput::InitDataOutput(int nvars,long nrows)
{
// Returns -1 for error, 0 for OK
// If output arrays already exist, delete them
if(MaxOutputs != 0)
delete TimeRecord;
if(NVars != 0)
{
delete OutRecord;
}
OutRecord = new double *[nvars];
if(SetUpArrays(nvars,nrows) == -1)return(-1);
return(0);
}
int DataOutput::InitDataOutput(int nvars,double STime,double LTime,double DTime)
{
StartTime = STime;
LastTime = LTime;
DeltaTime = DTime;
NextTime = StartTime;
// Compute the number of rows and then call the other InitDataOutput
long nrows = ceil((LTime - STime) / DTime);
return(InitDataOutput(nvars,nrows));
}
int DataOutput::AddData(double val, ...) // Add a data row
{
va_list ArgPtr;
va_start(ArgPtr, val);
if(OutCount >= MaxOutputs)return(-1);
double time = GetTimeNow() - BaseTime;
TimeRecord[OutCount] = time;
*(OutRecord[0] + OutCount) = val;
for(int jj=1; jj < NVars; jj++)
{
*(OutRecord[jj] + OutCount) = va_arg(ArgPtr, double);
}
if (va_arg(ArgPtr, long int) != END_OF_ARGS)
StopControl("\n\n***Incorrect Arg List for DataOutput::AddData***\n\n");
OutCount++;
NextTime += DeltaTime;
va_end(ArgPtr);
return(0);
}
int DataOutput::IsTimeForOutput(void) // Query to find out if output
{
// Returns 1 for YES, 0 for NO
double time = GetTimeNow() - BaseTime;
if(time >= NextTime)return(1);
return(0);
}
int DataOutput::WriteOutputFile(char *FileName)
{
ofstream OutputFile(FileName); // Opens for 'write'
if (!OutputFile)
{
cout << "Problem opening file " << FileName << "\n";
return(-1);
}
// Returns -1 for error, 0 for OK
for (int j=0; j < OutCount; j++)
{
OutputFile << TimeRecord[j] << " ";
for(int kk = 0; kk < NVars; kk++)
OutputFile << (*(OutRecord[kk] + j)) << " ";
OutputFile << "\n";
}
OutputFile.close(); // close the output file.
return(0);
}
// Accumulate Scan Statistics
// not used? static long nscans[NTASKSMAX]; // This must be big enough for all tasks!
void InitScanStat(BaseTask *task)
{
ntasks++;
if(ntasks > NTASKSMAX)
{
StopControl("Too many tasks (fix NTASKSMAX in basetask.cpp)\n");
}
AllTasks[task->TaskID] = task;
tskname[task->TaskID] = task->Name;
// not used? nscans[task->TaskID] = 0;
}
void WriteScanStat(char *FileName, double FinalTime)
{
long nsc,tot = 0;
ofstream OutputFile(FileName); // Opens for 'write'
if (!OutputFile)
{
cout << "Problem opening file " << FileName << "\n";
return;
}
cout << "Task # \t Task Name \t\t #Scans\n\n";
OutputFile << "Task # \t Task Name \t\t #Scans\n\n";
for(int i = 0; i < ntasks; i++)
{
nsc = (AllTasks[i])->GetNumScan();
int IDno = (AllTasks[i])->TaskID;
tot += nsc;
cout << IDno << "\t" << tskname[i] << "\t\t" <<nsc << "\n";
OutputFile << IDno << "\t" << tskname[i] << "\t\t" <<nsc << "\n";
}
cout << "\nTotal scans, all tasks: " << tot << "\n";
OutputFile << "\nTotal scans, all tasks: " << tot << "\n";
cout << "\nTotal running time: " << FinalTime << "\n";
OutputFile << "\nTotal running time: " << FinalTime << "\n";
OutputFile.close();
}
void WriteProfileStat(char *FileName)
{
ofstream OutputFile(FileName); // Opens for 'write'
if (!OutputFile)
{
cout << "<ProfileStat>Problem opening file " << FileName << "\n";
return;
}
OutputFile << "Task Profile Statistics\n";
for(int i = 0; i < ntasks; i++)
{
OutputFile << "\n"<< tskname[i] << "\n";
(AllTasks[i])->WriteProfile(OutputFile);
}
OutputFile.close();
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -