📄 basetask.cpp
字号:
// Base class for task template.
// File: basetask.cpp
// Created 8/2/95 by Jason Jones
// Modifications:
// 8/23/95 - JJ added TList.Name and cout in
// TList.Append.
// 10/6/95, DM Auslander, added task ID numbers
// 9/11/96, DM Auslander, added task profiling
// 10/1/96, DM Auslander, added message passing
// 10/7/96, DM Auslander, added global data base
// 6/16/97, DM Auslander, added state names for audit trail
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <dos.h>
#include <stdarg.h>
#include "tasks.hpp"
#define NTASKSMAX 50 // For use in ScanStat section
// These arrays are filled in InitScanStat()
static int ntasks=0;
// These arrays use TaskID as the index
static char *tskname[NTASKSMAX]; // This isn't really needed
// but it's convenient!
BaseTask *AllTasks[NTASKSMAX];
// This array uses TaskCode as its index
BaseTask *TasksByCode[2 * NTASKSMAX]; // Extra space because TaskCode
// can be assigned arbitrarily
static task_id = -1; // Use this to get a running index of tasks
#ifndef PROCESS_INFO // Default process information for code that
// does not have process information in tasks.hpp
const int ThisProcess = 0; // Process number
const int NumberOfProcesses = 1; // Number of independent processes
#endif
void BaseTask::BaseTaskInit(char *aName,int ProcNo)
{
Name = new char[strlen(aName)+1];
strcpy(Name, aName);
task_id++; // Index the id #
TaskID = task_id;
TaskCode = TaskID; // Always the same as TaskID
NumScans = 0;
State = xState = 0;
NextState = 0;
RunEntry = 0;
InitScanStat(this);
ProcessNo = ProcNo;
if(TaskCode >= (NTASKSMAX))
{
cout << "<BaseTaskInit> Task code too big (>2*NTASKSMAX)\n";
exit(1);
}
TasksByCode[TaskCode] = this; // Pointer to this task
GlobalSize = 0; // Default is no global data
StateNames = NULL; // No state names defined yet
};
BaseTask::BaseTask(char *aName,int ProcNo) // Constructor
{
profile_on = 0; // Default is no profiling
BaseTaskInit(aName,ProcNo);
}
// The destructor is overloaded in the derived task
BaseTask::~BaseTask(void)
{
delete [] Name;
if(profile_on)
{
// Free space used by profiler
delete [] values;
delete [] occur;
}
if(GlobalSize > 0)
{
// Free space used for globals
delete [] PrivateGlobalData;
delete [] GlobalData;
}
if(StateNames != NULL)delete [] StateNames;
}
static char *DefName = "aState";
// Functions to name states
void BaseTask::CreateStateNameArray(int n)
{
StateNames = new char * [n];
nStateNames = n;
for(int i = 0; i < n; i++)StateNames[i] = DefName;
}
void BaseTask::RegisterStateName(char *pName,int i)
{
if(i >= nStateNames)
{
cout << "RegisterStateName> Index too large\n";
exit(1);
}
StateNames[i] = pName;
}
char **BaseTask::GetStateNames(void)
{
return(StateNames);
}
// The default Run() function should never actually
// be used. It should be overloaded in the actual
// task definition.
int BaseTask::Run(void)
{
StopControl("Run function not overloaded\n");
return (1);
}
long BaseTask::GetNumScan(void)
{
return(NumScans);
}
// Functions associated with task profiling
void BaseTask::ActivateProfiling(double vbegin,double vend,int num_bins,int loglin)
{
if(num_bins <= 0)
{
// No bins -> No profiling
profile_on = 0;
return;
}
else
{
nbin = num_bins;
v1 = vbegin;
vlast = vend;
nbin = num_bins;
values = new double [nbin]; // Set up the values for the
// frequency (histogram) boundaries
occur = new long [nbin]; // One extra bin for >vlast
int i;
if(loglin)
// 0 -> log; 1 -> linear intervals
{
// Linear intervals
double add_amnt = (vlast - v1) / (nbin -2);
for(values[0]= v1,i = 1;i < nbin-1; i++)
{
values[i] = values[i - 1] + add_amnt;
}
}
else
{
// Log intervals
double mult = exp(log(vlast / v1) / (nbin - 2));
// Set up the boundaries for the time histogram
for(values[0]= v1,i = 1;i < nbin-1; i++)
{
values[i] = values[i - 1] * mult;
}
}
values[nbin-1] = 1.e20; // Big number
for(i = 0; i < nbin; i++)occur[i] = 0;
profile_on = 1;
}
}
void BaseTask::StartProfile(void)
{
if(!profile_on)return;
Time0 = GetTimeNow();
return;
}
void BaseTask::EndProfile(void)
{
int j;
double delt;
if(!profile_on)return;
delt = GetTimeNow() - Time0;
for(j = 0; j < nbin; j++)
{
if(delt <= values[j])
{
occur[j]++;
break;
}
}
return;
}
void BaseTask::WriteProfile(ofstream &OutputFile)
{
int i;
if(!profile_on)
{
// Nothing to print
OutputFile << "No profile statistics for this task\n";
return;
}
for(i = 0; i < nbin - 1; i++)
{
OutputFile << "<" << values[i] << "\t\t" << occur[i] << "\n";
}
OutputFile << ">" << values[i-1] << "\t\t" << occur[i] << "\n";
}
// BaseTask functions for message passing
// Delivery modes:
// 0 Only deliver message if message box is empty
// 1 Deliver message regardless of message box state
void BaseTask::SendMsg(BaseTask *ToTask,int BoxNo,int Flag,
double Val,int mode,int ReturnReceipt)
{
int ReturnValue;
int to_process = ToTask->GetTaskProcess();
int this_task_code = this->GetTaskCode();
if(to_process == ThisProcess)
{
// Message is local -- deliver it immediately
ReturnValue = ToTask->AcceptMessage(BoxNo,Flag,Val,mode,
TaskCode,ThisProcess);
if(ReturnReceipt != -1)
{
// Send a return receipt
SendRTMessage(this,ReturnReceipt,ReturnValue); // The value
// returned by Accept is sent as the flag to the return
// mailbox, which is specified by the value of ReturnReceipt
}
}
else
{
#ifdef USE_UDP
int RetVal;
int to_task_code = ToTask->GetTaskCode();
RetVal = InsertMessage(to_process,to_task_code,BoxNo,ThisProcess,
this_task_code,Flag,Val,ReturnReceipt,mode);
if(RetVal)
{
// Error inserting message
StopControl("<SendMsg> Error inserting message\n");
return;
}
#else
StopControl("<SendMsg> MultiProcess control not defined\n");
return;
#endif
}
}
// Two versions of SendRTMessage so to-task can be specified either by
// pointer or by code
void BaseTask::SendRTMessage(BaseTask *ToTask,int BoxNo,int Flag,
double Val,int mode,int ReturnReceipt)
{
SendMsg(ToTask,BoxNo,Flag,Val,mode,ReturnReceipt);
}
void BaseTask::SendRTMessage(int ToTask,int BoxNo,int Flag,
double Val,int mode,int ReturnReceipt)
{
SendMsg(TasksByCode[ToTask],BoxNo,Flag,Val,mode,ReturnReceipt);
}
int BaseTask::GetRTMessage(int BoxNo,int *msg_flag,
double *val, int *from_task,int *from_process)
{
/* Returns:
-1 for error
0 for no message available
1 for successful retrieval
*/
if((BoxNo >= NUM_MESSAGE_BOX) || (BoxNo < 0))return(-1); // Error
CriticalSectionBegin();
if(mbox[BoxNo].MessageAvailable == 0)
{
CriticalSectionEnd();
return(0); // No message available
}
// Get information
if(msg_flag != NULL)*msg_flag = mbox[BoxNo].MessageFlag;
if(val != NULL)*val = mbox[BoxNo].MessageValue;
if(from_task != NULL)*from_task = mbox[BoxNo].FromTask;
if(from_process != NULL)*from_process = mbox[BoxNo].FromProcess;
mbox[BoxNo].MessageAvailable = 0; // Clear message box
CriticalSectionEnd();
return(1); // Success
}
int BaseTask::AcceptMessage(int BoxNo,int msg_flag,double msg_val,int mode,
int from_task,int from_process)
{
// Processes an incoming message
// Returns 1 if message successfully delivered, 0 otherwise
if((BoxNo >= NUM_MESSAGE_BOX) || (BoxNo < 0))return(0);
if((mode < 0) || (mode > 1))
{
StopControl("Unknown message mode\n");
return(0);
}
CriticalSectionBegin();
if(mode == 0)
{
// Check to see if message box is empty
if(mbox[BoxNo].MessageAvailable != 0)
{
CriticalSectionEnd();
return(0); // Can't deliver
}
}
// Copy message information
mbox[BoxNo].FromTask = from_task;
mbox[BoxNo].FromProcess = from_process;
mbox[BoxNo].MessageFlag = msg_flag;
mbox[BoxNo].MessageValue = msg_val;
mbox[BoxNo].MessageAvailable = 1;
CriticalSectionEnd();
return(1); // Successful delivery
}
void BaseTask::SendCompletionMessage(int toTask,int &respBox,int code)
{
if(respBox >= 0)
{
SendRTMessage(toTask,respBox,code,0.0,MESSAGE_OVERWRITE);
respBox = -1; // Reset so accidental messages won't be sent
}
}
#ifdef USE_UDP // Only compile for network applications
void StoreMessage(int ToProc,int ToTask,int BoxNo,int FromProc,
int FromTask,int MsgFlag,double MsgValue,int RetRecpt,int DelMode)
{
// Store an incoming message into the task's message box
int RetVal;
if(ToProc != ThisProcess)
{
StopControl("<StoreMessage> Wrong process #.\n");
return;
}
BaseTask *pTask = TasksByCode[ToTask];
RetVal = pTask->AcceptMessage(BoxNo,MsgFlag,MsgValue,DelMode,
FromTask,FromProc);
if(RetRecpt != -1)
{
// Send a return receipt
pTask->SendRTMessage(FromTask,RetRecpt,RetVal); // The value
// returned by Accept is sent as the flag to the return
// mailbox, which is specified by the value of ReturnReceipt
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -