Fixed some compiler errors. git-svn-id: https://svn.microneil.com/svn/SNF4CGP/trunk@16 59e8e3e7-56fa-483b-b4b4-fa6ab0af3dfcmaster
// SNF4CGP/Command.hpp | |||||
// Copyright (C) 2009 ARM Research Labs, LLC | |||||
// See www.armresearch.com for more information. | |||||
// | |||||
// The Command class describes what CGP is asking us to do. | |||||
#ifndef IncludedCommand | |||||
#define IncludedCommand | |||||
#include <string> | |||||
using namespace std; | |||||
class Command { // Parsed Command Objects | |||||
public: | |||||
enum CommandType { // Commands have these types: | |||||
UNKNOWN, // We don't know this command. | |||||
QUIT, // It is time to stop the app. | |||||
WAKE, // Report the app is now awake. | |||||
INTF, // Report the interface version. | |||||
FILE // Scan this file. | |||||
}; | |||||
unsigned int Number; // Commands have a serial number | |||||
CommandType Type; // Commands have a type. | |||||
string Data; // Other command data goes here. | |||||
Command::Command() : // Ordinary constructor. | |||||
Number(0), | |||||
Type(UNKNOWN), | |||||
Data("") { | |||||
} | |||||
Command::Command(const Command& R) : // Copy constructor. | |||||
Number(R.Number), | |||||
Type(R.Type) { | |||||
Data = R.Data; | |||||
} | |||||
Command& operator=(const Command& R) { // We need an assignment operator. | |||||
Number = R.Number; | |||||
Type = R.Type; | |||||
Data = R.Data; | |||||
return (*this); | |||||
} | |||||
}; | |||||
#endif |
#include "ExecutiveProcess.hpp" | #include "ExecutiveProcess.hpp" | ||||
#include "../SNF4CGP/CodeDweller/faults.hpp" | |||||
#include "../CodeDweller/faults.hpp" | |||||
#include <iostream> | #include <iostream> | ||||
RuntimeCheck CheckOutputProcessorWasStarted("ExecutiveProcess::initializeOutput() Check(Output->isRunning())"); | RuntimeCheck CheckOutputProcessorWasStarted("ExecutiveProcess::initializeOutput() Check(Output->isRunning())"); | ||||
void ExecutiveProcess::initializeOutput() { | void ExecutiveProcess::initializeOutput() { | ||||
CheckJobPoolNotNull(0 != Jobs); | |||||
try { Output = new OutputProcessor(*Jobs); } catch(...) {} | |||||
CheckOutputProcessorWasConstructed(0 != Output); | |||||
try { Output->start() } catch(...) {} | |||||
CheckOutputProcessorWasStarted(Output->isRunning()); | |||||
Output.init(Jobs); | |||||
} | } | ||||
void ExecutiveProcess::initializeJobPool() { | void ExecutiveProcess::initializeJobPool() { | ||||
Jobs = new JobPool(ConfigInfo | |||||
Jobs.init(ConfigInfo, Output); | |||||
} | } | ||||
void ExecutiveProcess::initializeWorkerPool() { | void ExecutiveProcess::initializeWorkerPool() { | ||||
Workers.init(); | |||||
} | } | ||||
void ExecutiveProcess::shutdownWorkerPool() { | void ExecutiveProcess::shutdownWorkerPool() { | ||||
Workers.stop(); | |||||
} | } | ||||
void ExecutiveProcess::shutdownJobPool() { | void ExecutiveProcess::shutdownJobPool() { | ||||
Jobs.stop(); | |||||
} | } | ||||
void ExecutiveProcess::shutdownOutput() { | void ExecutiveProcess::shutdownOutput() { | ||||
Output.stop(); | |||||
} | } | ||||
void ExecutiveProcess::dispatchCommand(Command& C) { // Job + Worker + Command; go! | void ExecutiveProcess::dispatchCommand(Command& C) { // Job + Worker + Command; go! | ||||
W.doJob(J); | W.doJob(J); | ||||
} | } | ||||
ExecutiveProcess::ExecutiveProcess(string& Version, string& Config) : // Simple construction. | |||||
ExecutiveProcess::ExecutiveProcess(const string& Version, const string& Config) : // Simple construction. | |||||
VersionInfo(Version), | VersionInfo(Version), | ||||
ConfigInfo(Config), | ConfigInfo(Config), | ||||
QuitJobNumber(0) {} | QuitJobNumber(0) {} | ||||
~ExecutiveProcess::ExecutiveProcess() { // Deal with uncerimoneous shutdowns. | |||||
ExecutiveProcess::~ExecutiveProcess() { // Deal with uncerimoneous shutdowns. | |||||
} | } | ||||
void ExecutiveProcess::doStartup() { // Startup happens in this sequence. | void ExecutiveProcess::doStartup() { // Startup happens in this sequence. | ||||
void ExecutiveProcess::doProcessing() { // Command processing happens here. | void ExecutiveProcess::doProcessing() { // Command processing happens here. | ||||
Command C; | Command C; | ||||
C.CommandType = WAKE; // Create the WAKE command to announce | |||||
C.Type = Command::WAKE; // Create the WAKE command to announce | |||||
C.Data = VersionInfo; // that we are alive (and who we are) | C.Data = VersionInfo; // that we are alive (and who we are) | ||||
dispatchCommand(C); // and dispatch a job with it. | dispatchCommand(C); // and dispatch a job with it. | ||||
// Then process all incoming commands: | // Then process all incoming commands: | ||||
InputProcessor& I = *Input; // Convenient handle for input processor. | |||||
for(;0 == QuitJobNumber;) { // Loop until we have a QUIT job. | for(;0 == QuitJobNumber;) { // Loop until we have a QUIT job. | ||||
C = I.getCommand(); // Get a command from the input. | |||||
if(QUIT == C.CommandType) QuitJobNumber = C.Number; // QUIT command means it's time to stop. | |||||
C = Input.getCommand(); // Get a command from the input. | |||||
if(Command::QUIT == C.Type) QuitJobNumber = C.Number; // QUIT command means it's time to stop. | |||||
else dispatchCommand(C); // Dispatch a job for all other commands. | else dispatchCommand(C); // Dispatch a job for all other commands. | ||||
} | } | ||||
} | } |
#include "WorkerPool.hpp" | #include "WorkerPool.hpp" | ||||
#include "InputProcessor.hpp" | #include "InputProcessor.hpp" | ||||
#include "OutputProcessor.hpp" | #include "OutputProcessor.hpp" | ||||
#include "Command.hpp" | |||||
#include <string> | #include <string> | ||||
void shutdownJobPool(); | void shutdownJobPool(); | ||||
void shutdownOutput(); | void shutdownOutput(); | ||||
void dispatchCommand(Command C); // Job + Worker + Command; go! | |||||
void dispatchCommand(Command& C); // Job + Worker + Command; go! | |||||
public: | public: | ||||
ExecutiveProcess(string& Version, string& Config); // Simple construction. The d'tor needs | |||||
ExecutiveProcess(const string& Version, const string& Config); // Simple construction. The d'tor needs | |||||
~ExecutiveProcess(); // to deal with uncerimoneous shutdowns. | ~ExecutiveProcess(); // to deal with uncerimoneous shutdowns. | ||||
void doStartup(); // The main thread calls these in sequence. | void doStartup(); // The main thread calls these in sequence. |
// SNF4CGP/InputProcessor.cpp | // SNF4CGP/InputProcessor.cpp | ||||
// Copyright (C) 2009 ARM Research Labs, LLC. | // Copyright (C) 2009 ARM Research Labs, LLC. | ||||
// See www.armresearch.com for more information. | // See www.armresearch.com for more information. | ||||
#include "InputProcessor.hpp" | |||||
using namespace std; | |||||
//// InputProcessor //////////////////////////////////////////////////////////// | |||||
Command InputProcessor::getCommand() { // How to get/parse a command | |||||
// get a line from cin | |||||
// parse the number | |||||
// parse the type | |||||
// parse the remaining data | |||||
// return the command | |||||
} |
#ifndef IncludedInputProcessor | #ifndef IncludedInputProcessor | ||||
#define IncludedInputProcessor | #define IncludedInputProcessor | ||||
#include <string> | |||||
#include "Command.hpp" | |||||
using namespace std; | using namespace std; | ||||
struct Command { // Parsed Command Objects | |||||
unsigned int Number; // Commands have a serial number | |||||
enum CommandType { // Commands have these types: | |||||
UNKNOWN, // We don't know this command. | |||||
QUIT, // It is time to stop the app. | |||||
WAKE, // Report the app is now awake. | |||||
INTF, // Report the interface version. | |||||
FILE // Scan this file. | |||||
} Type; // Here is where we keep it. | |||||
string Data; // Other command data goes here. | |||||
}; | |||||
class InputProcessor { // Here is the InputProcessor object. | class InputProcessor { // Here is the InputProcessor object. | ||||
public: | public: |
#ifndef IncludedJobPool | #ifndef IncludedJobPool | ||||
#define IncludedJobPool | #define IncludedJobPool | ||||
#include "../SNF4CGP/SNFMulti/SNFMulti.hpp" | |||||
#include "../SNF4CGP/CodeDweller/threading.hpp" | |||||
#include "../SNFMulti/SNFMulti.hpp" | |||||
#include "../CodeDweller/threading.hpp" | |||||
#include "InputProcessor.hpp" | |||||
#include "ScannerPool.hpp" | |||||
#include "Command.hpp" | |||||
#include <string> | #include <string> | ||||
#include <vector> | #include <vector> | ||||
using namespace std; | using namespace std; | ||||
class ScannerPool; | |||||
class OutputProcessor; | |||||
class Job { // SNF4CGP Job instance. | class Job { // SNF4CGP Job instance. | ||||
private: | private: | ||||
ScannerPool& Scanners; // Knows where to get scanners. | ScannerPool& Scanners; // Knows where to get scanners. | ||||
public: | public: | ||||
Job(ScannerPool& S, OutputProcessor O); // Construct with important links. | Job(ScannerPool& S, OutputProcessor O); // Construct with important links. | ||||
~Job(); // Cleanup when destructing. | ~Job(); // Cleanup when destructing. | ||||
void setCommand(Command C); // Assign a command for this job. | |||||
void setCommand(Command& C); // Assign a command for this job. | |||||
void doIt(); // Get the job done. | void doIt(); // Get the job done. | ||||
string& Responses(); // Read the job's report. | string& Responses(); // Read the job's report. | ||||
void clear(); // Cleanup for the next command. | void clear(); // Cleanup for the next command. | ||||
public: | public: | ||||
JobPool(); // Basic construction. | JobPool(); // Basic construction. | ||||
~JobPool(); // Safe cleanup on destruction. | ~JobPool(); // Safe cleanup on destruction. | ||||
init(string Configuration, OutputProcessor& O); // Get ready to allocate jobs. | |||||
void init(string Configuration, OutputProcessor& O); // Get ready to allocate jobs. | |||||
Job& grab(); // Get a fresh job object. | Job& grab(); // Get a fresh job object. | ||||
void drop(Job& J); // Drop a used job object. | void drop(Job& J); // Drop a used job object. | ||||
stop(); // Shutdown and clean up. | |||||
void stop(); // Shutdown and clean up. | |||||
}; | }; | ||||
#endif | #endif |
// See www.armresearch.com for more information. | // See www.armresearch.com for more information. | ||||
#include "OutputProcessor.hpp" | #include "OutputProcessor.hpp" | ||||
#include "JobPool.hpp" | |||||
#include "../SNF4CGP/CodeDweller/faults.hpp" | |||||
#include "../CodeDweller/faults.hpp" | |||||
using namespace std; | using namespace std; | ||||
OutputProcessor::OutputProcessor() : // Constructor sets up the basics. | OutputProcessor::OutputProcessor() : // Constructor sets up the basics. | ||||
Thread(OutputProcessor::Type, "Output"), // Name the thread. | Thread(OutputProcessor::Type, "Output"), // Name the thread. | ||||
RecycledJobs(0), // No job pool yet. | |||||
RecycledJobs_(0), // No job pool yet. | |||||
isTimeToStop(false) { // Not time to stop. | isTimeToStop(false) { // Not time to stop. | ||||
} | } | ||||
CurrentThreadState(PostingResponses); | CurrentThreadState(PostingResponses); | ||||
cout << J.Responses(); | cout << J.Responses(); | ||||
J.clear(); | J.clear(); | ||||
RecycledJobs.drop(J); | |||||
RecycledJobs().drop(J); | |||||
} | } | ||||
void OutputProcessor::myTask() { // This is how we do it. | void OutputProcessor::myTask() { // This is how we do it. |
#ifndef IncludedOutputProcessor | #ifndef IncludedOutputProcessor | ||||
#define IncludedOutputProcessor | #define IncludedOutputProcessor | ||||
#include "JobPool.hpp" | |||||
#include "../CodeDweller/threading.hpp" | #include "../CodeDweller/threading.hpp" | ||||
class JobPool; // Yes there is a JobPool class. | |||||
class Job; // Yes there is a Job class. | |||||
class OutputProcessor : private Thread { // Process job outputs. | class OutputProcessor : private Thread { // Process job outputs. | ||||
private: | private: | ||||
JobPool* Jobs_; // Where we put our recycled jobs. | |||||
JobPool& Jobs(); // Safe access to jobs pool. | |||||
JobPool* RecycledJobs_; // Where we put our recycled jobs. | |||||
JobPool& RecycledJobs(); // Safe access to jobs pool. | |||||
ProductionQueue<Job*> CompletedJobs; // Input queue for jobs to process. | ProductionQueue<Job*> CompletedJobs; // Input queue for jobs to process. | ||||
bool isTimeToStop; // Flag for when we need to stop. | bool isTimeToStop; // Flag for when we need to stop. |
#ifndef IncludedScannerPool | #ifndef IncludedScannerPool | ||||
#define IncludedScannerPool | #define IncludedScannerPool | ||||
#include "../SNF4CGP/SNFMulti/SNFMulti.hpp" | |||||
#include "../SNF4CGP/CodeDweller/threading.hpp" | |||||
#include "../CodeDweller/threading.hpp" | |||||
#include <string> | #include <string> | ||||
// Constructing a scanner is essentially constructing an snf_EngineHandler in a wrapper. | // Constructing a scanner is essentially constructing an snf_EngineHandler in a wrapper. | ||||
class snf_RulebaseHandler; // These classes exists. | |||||
class snf_EngineHandler; | |||||
class Scanner { // SNF Scanner instance for the pool | class Scanner { // SNF Scanner instance for the pool | ||||
private: | private: | ||||
snf_RulebaseHandler& Rulebase_; // Rulebase the scanner uses. | snf_RulebaseHandler& Rulebase_; // Rulebase the scanner uses. | ||||
public: | public: | ||||
ScannerPool(); // Constructed with Rulebase config. | ScannerPool(); // Constructed with Rulebase config. | ||||
~ScannerPool(); // Cleans up when destroyed. | ~ScannerPool(); // Cleans up when destroyed. | ||||
init(string Configuration); // Get ready to provide scanners. | |||||
stop(); // Shutdown and clean up. | |||||
void init(string Configuration); // Get ready to provide scanners. | |||||
void stop(); // Shutdown and clean up. | |||||
Scanner& grab(); // Provides a Scanner from the pool. | Scanner& grab(); // Provides a Scanner from the pool. | ||||
void drop(Scanner& S); // Returns a Scanner to the pool. | void drop(Scanner& S); // Returns a Scanner to the pool. | ||||
}; | }; |
// See www.armresearch.com for more information. | // See www.armresearch.com for more information. | ||||
#include "WorkerPool.hpp" | #include "WorkerPool.hpp" | ||||
#include "JobPool.hpp" | |||||
#include "../SNF4CGP/CodeDweller/faults.hpp" | |||||
#include "../CodeDweller/faults.hpp" | |||||
using namespace std; | using namespace std; | ||||
myJob_(0) { | myJob_(0) { | ||||
} | } | ||||
virtual Worker::~Worker() { // Cleanup on the way down. | |||||
Worker::~Worker() { // Cleanup on the way down. | |||||
try { stop(); } | try { stop(); } | ||||
catch(...) {} | catch(...) {} | ||||
} | } | ||||
RuntimeCheck CheckForValidJobPointer("Worker::myJob() Check(0 != myJob_)"); | RuntimeCheck CheckForValidJobPointer("Worker::myJob() Check(0 != myJob_)"); | ||||
Job& myJob() { // Safe access to myJob. | |||||
Job& Worker::myJob() { // Safe access to myJob. | |||||
CheckForValidJobPointer(0 != myJob_); | CheckForValidJobPointer(0 != myJob_); | ||||
return(*myJob_); | return(*myJob_); | ||||
} | } | ||||
LogicCheck CheckForNoJobsAtStop("Worker::stop() Check(false == isJob())"); | LogicCheck CheckForNoJobsAtStop("Worker::stop() Check(false == isJob())"); | ||||
void Worker::stop() { // Stop the worker thread. | void Worker::stop() { // Stop the worker thread. | ||||
ScopeMutext CallTheBall(Busy); // Don't stop while busy or vv. | |||||
ScopeMutex CallTheBall(Busy); // Don't stop while busy or vv. | |||||
if(false == TimeToStop) { // Do this only once. | if(false == TimeToStop) { // Do this only once. | ||||
CheckForNoJobsAtStop(false == isJob()); | CheckForNoJobsAtStop(false == isJob()); | ||||
TimeToStop = true; // It is time to stop. | TimeToStop = true; // It is time to stop. | ||||
//// WorkerPool //////////////////////////////////////////////////////////////// | //// WorkerPool //////////////////////////////////////////////////////////////// | ||||
/* | |||||
class WorkerPool { // Worker pools look like this... | |||||
private: | |||||
Mutex AllocationMutex; // Worker pool allocation control. | |||||
ProductionQueue<Worker*> RecycledWorkers; // Where do recyceled workers go. | |||||
unsigned int AllocatedWorkers; // Count of workers to clean up. | |||||
bool Started; // True if we're ready to go. | |||||
public: | |||||
WorkerPool(); // Set startup defaults. | |||||
~WorkerPool(); // Cleanup if needed. | |||||
void init(); // Start making workers. | |||||
Worker& grab(); // Give me a worker to use. | |||||
void drop(Worker& W); // Take this worker back. | |||||
void stop(); // Destroy all workers and stop. | |||||
}; | |||||
*/ | |||||
WorkerPool::WorkerPool() : | |||||
WorkerPool::WorkerPool() : // Simple construction. | |||||
AllocatedWorkers(0), | AllocatedWorkers(0), | ||||
Started(false) { | Started(false) { | ||||
} | } | ||||
WorkerPool::~WorkerPool() { | |||||
WorkerPool::~WorkerPool() { // Cleanup on the way out. | |||||
try { stop(); } | try { stop(); } | ||||
catch(...) {} | catch(...) {} | ||||
} | } | ||||
void WorkerPool::init() { // Initialize the worker pool. | void WorkerPool::init() { // Initialize the worker pool. | ||||
Worker& FirstWorker = makeWorker(); // Make the first worker and | |||||
drop(FirstWorker); // drop it into the pool. | |||||
Worker* FirstWorker = makeWorker(); // Make the first worker and | |||||
drop(*FirstWorker); // drop it into the pool. | |||||
Started = true; // We are now initialized. | Started = true; // We are now initialized. | ||||
} | } | ||||
Worker* NewWorker = 0; | Worker* NewWorker = 0; | ||||
NewWorker = new Worker(*this); // Allocate the worker. | NewWorker = new Worker(*this); // Allocate the worker. | ||||
++AllocatedWorkers; // If successful count it. | ++AllocatedWorkers; // If successful count it. | ||||
return Worker; // Return a reference. | |||||
return NewWorker; // Return a reference. | |||||
} | } | ||||
RuntimeCheck CheckForValidGrabbedWorker("WorkerPool:grab() Check(0 != GrabbedWorker)"); | |||||
LogicCheck CheckGrabOnlyWhenStarted("WorkerPool::grab() Check(Started)"); | |||||
RuntimeCheck CheckForValidGrabbedWorker("WorkerPool::grab() Check(0 != GrabbedWorker)"); | |||||
Worker& WorkerPool::grab() { // Grab a worker from the pool. | Worker& WorkerPool::grab() { // Grab a worker from the pool. | ||||
ScopeMutex Busy(AllocationMutex); | ScopeMutex Busy(AllocationMutex); | ||||
CheckGrabOnlyWhenStarted(Started); | |||||
Worker* GrabbedWorker = 0; | Worker* GrabbedWorker = 0; | ||||
if(0 < RecycledWorkers.size()) GrabbedWorker = RecycledWorkers.take(); // Prefer to use recycled workers. | if(0 < RecycledWorkers.size()) GrabbedWorker = RecycledWorkers.take(); // Prefer to use recycled workers. | ||||
else GrabbedWorker = makeWorker(); // Make new ones if needed. | else GrabbedWorker = makeWorker(); // Make new ones if needed. | ||||
return (*GrabbedWorker); | return (*GrabbedWorker); | ||||
} | } | ||||
void WorkerPool::drop(Worker& W) { | |||||
// Note that drop() does not use the AllocationMutex. This decouples (somewhat) drop operations from allocation | |||||
// operations and improves the performance potential. Since only one thread will ever use the AllocationMutex | |||||
// it should never see contention -- it is essentially a safety device in case some later modification gets | |||||
// things wrong or some other event occurs that causes a conflict. | |||||
void WorkerPool::drop(Worker& W) { // Drop a worker into the pool. | |||||
RecycledWorkers.give(&W); | |||||
} | |||||
void WorkerPool::killWorkerFromPool() { // Destroy and count workers. | |||||
Worker* WorkerToKill = 0; | |||||
WorkerToKill = RecycledWorkers.take(); // Take a worker from the pool. | |||||
WorkerToKill->stop(); // Stop the worker thread. | |||||
delete WorkerToKill; // Destroy it. | |||||
--AllocatedWorkers; // Count each one. | |||||
} | } | ||||
void WorkerPool::stop() { | |||||
void WorkerPool::stop() { // Shutdown the pool (reclaim all) | |||||
ScopeMutex Busy(AllocationMutex); // No grabbing. | |||||
while(0 < AllocatedWorkers) killWorkerFromPool(); // Kill each worker in the pool. | |||||
Started = false; // We're not alive now. | |||||
} | } |
#ifndef IncludedWorkerPool | #ifndef IncludedWorkerPool | ||||
#define IncludedWorkerPool | #define IncludedWorkerPool | ||||
#include "../SNF4CGP/CodeDweller/threading.hpp" | |||||
#include "JobPool.hpp" | |||||
#include "../CodeDweller/threading.hpp" | |||||
class Job; | |||||
class WorkerPool; // There will be a worker pool. | class WorkerPool; // There will be a worker pool. | ||||
class Worker : private Thread { // This is a worker thread. | class Worker : private Thread { // This is a worker thread. | ||||
ProductionGateway StoppingPoint; // Thread stops here and waits. | ProductionGateway StoppingPoint; // Thread stops here and waits. | ||||
Mutex Busy; // Busy state protection. | Mutex Busy; // Busy state protection. | ||||
bool TimeToStop; // stop() has been called. | bool TimeToStop; // stop() has been called. | ||||
void doWork(); // Get a job done. | |||||
bool doWork(); // Get a job done. | |||||
void myTask(); // Task for the thread. (my loop). | void myTask(); // Task for the thread. (my loop). | ||||
Job* myJob_; // The job to do (or 0 to stop). | Job* myJob_; // The job to do (or 0 to stop). | ||||
bool isJob(); // Job pointer check. | bool isJob(); // Job pointer check. | ||||
const static ThreadType Type; | const static ThreadType Type; | ||||
const static ThreadState Waiting; | const static ThreadState Waiting; | ||||
const static ThreadState Working; | const static ThreadState Working; | ||||
}; | }; | ||||
class WorkerPool { // Worker pools look like this... | class WorkerPool { // Worker pools look like this... | ||||
bool Started; // True if we're ready to go. | bool Started; // True if we're ready to go. | ||||
Worker* makeWorker(); // Make and count workers. | Worker* makeWorker(); // Make and count workers. | ||||
void killWorkerFromPool(); // Kill a worker from the pool. | |||||
public: | public: | ||||
WorkerPool(); // Set startup defaults. | WorkerPool(); // Set startup defaults. |