Fixed some compiler errors. git-svn-id: https://svn.microneil.com/svn/SNF4CGP/trunk@16 59e8e3e7-56fa-483b-b4b4-fa6ab0af3dfcmaster
@@ -0,0 +1,49 @@ | |||
// 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 |
@@ -4,7 +4,7 @@ | |||
#include "ExecutiveProcess.hpp" | |||
#include "../SNF4CGP/CodeDweller/faults.hpp" | |||
#include "../CodeDweller/faults.hpp" | |||
#include <iostream> | |||
@@ -22,27 +22,27 @@ RuntimeCheck CheckOutputProccessorWasConstructed("ExecutiveProcess::initializeOu | |||
RuntimeCheck CheckOutputProcessorWasStarted("ExecutiveProcess::initializeOutput() Check(Output->isRunning())"); | |||
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() { | |||
Jobs = new JobPool(ConfigInfo | |||
Jobs.init(ConfigInfo, Output); | |||
} | |||
void ExecutiveProcess::initializeWorkerPool() { | |||
Workers.init(); | |||
} | |||
void ExecutiveProcess::shutdownWorkerPool() { | |||
Workers.stop(); | |||
} | |||
void ExecutiveProcess::shutdownJobPool() { | |||
Jobs.stop(); | |||
} | |||
void ExecutiveProcess::shutdownOutput() { | |||
Output.stop(); | |||
} | |||
void ExecutiveProcess::dispatchCommand(Command& C) { // Job + Worker + Command; go! | |||
@@ -52,12 +52,12 @@ void ExecutiveProcess::dispatchCommand(Command& C) { | |||
W.doJob(J); | |||
} | |||
ExecutiveProcess::ExecutiveProcess(string& Version, string& Config) : // Simple construction. | |||
ExecutiveProcess::ExecutiveProcess(const string& Version, const string& Config) : // Simple construction. | |||
VersionInfo(Version), | |||
ConfigInfo(Config), | |||
QuitJobNumber(0) {} | |||
~ExecutiveProcess::ExecutiveProcess() { // Deal with uncerimoneous shutdowns. | |||
ExecutiveProcess::~ExecutiveProcess() { // Deal with uncerimoneous shutdowns. | |||
} | |||
void ExecutiveProcess::doStartup() { // Startup happens in this sequence. | |||
@@ -68,14 +68,13 @@ void ExecutiveProcess::doStartup() { | |||
void ExecutiveProcess::doProcessing() { // Command processing happens here. | |||
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) | |||
dispatchCommand(C); // and dispatch a job with it. | |||
// Then process all incoming commands: | |||
InputProcessor& I = *Input; // Convenient handle for input processor. | |||
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. | |||
} | |||
} |
@@ -13,6 +13,7 @@ | |||
#include "WorkerPool.hpp" | |||
#include "InputProcessor.hpp" | |||
#include "OutputProcessor.hpp" | |||
#include "Command.hpp" | |||
#include <string> | |||
@@ -37,11 +38,11 @@ class ExecutiveProcess { | |||
void shutdownJobPool(); | |||
void shutdownOutput(); | |||
void dispatchCommand(Command C); // Job + Worker + Command; go! | |||
void dispatchCommand(Command& C); // Job + Worker + Command; go! | |||
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. | |||
void doStartup(); // The main thread calls these in sequence. |
@@ -1,3 +1,17 @@ | |||
// SNF4CGP/InputProcessor.cpp | |||
// Copyright (C) 2009 ARM Research Labs, LLC. | |||
// 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 | |||
} |
@@ -8,22 +8,10 @@ | |||
#ifndef IncludedInputProcessor | |||
#define IncludedInputProcessor | |||
#include <string> | |||
#include "Command.hpp" | |||
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. | |||
public: |
@@ -22,17 +22,19 @@ | |||
#ifndef 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 <vector> | |||
using namespace std; | |||
class ScannerPool; | |||
class OutputProcessor; | |||
class Job { // SNF4CGP Job instance. | |||
private: | |||
ScannerPool& Scanners; // Knows where to get scanners. | |||
@@ -60,7 +62,7 @@ class Job { | |||
public: | |||
Job(ScannerPool& S, OutputProcessor O); // Construct with important links. | |||
~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. | |||
string& Responses(); // Read the job's report. | |||
void clear(); // Cleanup for the next command. | |||
@@ -82,10 +84,10 @@ class JobPool { | |||
public: | |||
JobPool(); // Basic construction. | |||
~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. | |||
void drop(Job& J); // Drop a used job object. | |||
stop(); // Shutdown and clean up. | |||
void stop(); // Shutdown and clean up. | |||
}; | |||
#endif |
@@ -3,8 +3,9 @@ | |||
// See www.armresearch.com for more information. | |||
#include "OutputProcessor.hpp" | |||
#include "JobPool.hpp" | |||
#include "../SNF4CGP/CodeDweller/faults.hpp" | |||
#include "../CodeDweller/faults.hpp" | |||
using namespace std; | |||
@@ -14,7 +15,7 @@ const ThreadState OutputProcessor::PostingResponses("Posting"); | |||
OutputProcessor::OutputProcessor() : // Constructor sets up the basics. | |||
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. | |||
} | |||
@@ -49,7 +50,7 @@ void OutputProcessor::handleJob(Job& J) { | |||
CurrentThreadState(PostingResponses); | |||
cout << J.Responses(); | |||
J.clear(); | |||
RecycledJobs.drop(J); | |||
RecycledJobs().drop(J); | |||
} | |||
void OutputProcessor::myTask() { // This is how we do it. |
@@ -11,15 +11,16 @@ | |||
#ifndef IncludedOutputProcessor | |||
#define IncludedOutputProcessor | |||
#include "JobPool.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. | |||
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. | |||
bool isTimeToStop; // Flag for when we need to stop. |
@@ -9,8 +9,7 @@ | |||
#ifndef IncludedScannerPool | |||
#define IncludedScannerPool | |||
#include "../SNF4CGP/SNFMulti/SNFMulti.hpp" | |||
#include "../SNF4CGP/CodeDweller/threading.hpp" | |||
#include "../CodeDweller/threading.hpp" | |||
#include <string> | |||
@@ -18,6 +17,9 @@ using namespace std; | |||
// 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 | |||
private: | |||
snf_RulebaseHandler& Rulebase_; // Rulebase the scanner uses. | |||
@@ -40,8 +42,8 @@ class ScannerPool { | |||
public: | |||
ScannerPool(); // Constructed with Rulebase config. | |||
~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. | |||
void drop(Scanner& S); // Returns a Scanner to the pool. | |||
}; |
@@ -3,8 +3,9 @@ | |||
// See www.armresearch.com for more information. | |||
#include "WorkerPool.hpp" | |||
#include "JobPool.hpp" | |||
#include "../SNF4CGP/CodeDweller/faults.hpp" | |||
#include "../CodeDweller/faults.hpp" | |||
using namespace std; | |||
@@ -20,7 +21,7 @@ Worker::Worker(WorkerPool& W) : | |||
myJob_(0) { | |||
} | |||
virtual Worker::~Worker() { // Cleanup on the way down. | |||
Worker::~Worker() { // Cleanup on the way down. | |||
try { stop(); } | |||
catch(...) {} | |||
} | |||
@@ -31,7 +32,7 @@ bool Worker::isJob() { | |||
RuntimeCheck CheckForValidJobPointer("Worker::myJob() Check(0 != myJob_)"); | |||
Job& myJob() { // Safe access to myJob. | |||
Job& Worker::myJob() { // Safe access to myJob. | |||
CheckForValidJobPointer(0 != myJob_); | |||
return(*myJob_); | |||
} | |||
@@ -48,7 +49,7 @@ void Worker::doJob(Job& J) { | |||
LogicCheck CheckForNoJobsAtStop("Worker::stop() Check(false == isJob())"); | |||
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. | |||
CheckForNoJobsAtStop(false == isJob()); | |||
TimeToStop = true; // It is time to stop. | |||
@@ -81,38 +82,19 @@ void Worker::myTask() { | |||
//// 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), | |||
Started(false) { | |||
} | |||
WorkerPool::~WorkerPool() { | |||
WorkerPool::~WorkerPool() { // Cleanup on the way out. | |||
try { stop(); } | |||
catch(...) {} | |||
} | |||
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. | |||
} | |||
@@ -120,13 +102,15 @@ Worker* WorkerPool::makeWorker() { | |||
Worker* NewWorker = 0; | |||
NewWorker = new Worker(*this); // Allocate the worker. | |||
++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. | |||
ScopeMutex Busy(AllocationMutex); | |||
CheckGrabOnlyWhenStarted(Started); | |||
Worker* GrabbedWorker = 0; | |||
if(0 < RecycledWorkers.size()) GrabbedWorker = RecycledWorkers.take(); // Prefer to use recycled workers. | |||
else GrabbedWorker = makeWorker(); // Make new ones if needed. | |||
@@ -134,8 +118,25 @@ Worker& WorkerPool::grab() { | |||
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. | |||
} |
@@ -15,10 +15,9 @@ | |||
#ifndef 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 Worker : private Thread { // This is a worker thread. | |||
@@ -27,7 +26,7 @@ class Worker : private Thread { | |||
ProductionGateway StoppingPoint; // Thread stops here and waits. | |||
Mutex Busy; // Busy state protection. | |||
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). | |||
Job* myJob_; // The job to do (or 0 to stop). | |||
bool isJob(); // Job pointer check. | |||
@@ -42,7 +41,6 @@ class Worker : private Thread { | |||
const static ThreadType Type; | |||
const static ThreadState Waiting; | |||
const static ThreadState Working; | |||
}; | |||
class WorkerPool { // Worker pools look like this... | |||
@@ -53,6 +51,7 @@ class WorkerPool { | |||
bool Started; // True if we're ready to go. | |||
Worker* makeWorker(); // Make and count workers. | |||
void killWorkerFromPool(); // Kill a worker from the pool. | |||
public: | |||
WorkerPool(); // Set startup defaults. |