Browse Source

Refactored a bit to solve circular references in module includes.

Fixed some compiler errors.


git-svn-id: https://svn.microneil.com/svn/SNF4CGP/trunk@16 59e8e3e7-56fa-483b-b4b4-fa6ab0af3dfc
master
madscientist 15 years ago
parent
commit
90075fc40c

+ 49
- 0
SNF4CGP/Command.hpp View File

// 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

+ 12
- 13
SNF4CGP/ExecutiveProcess.cpp View File

#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.
} }
} }

+ 3
- 2
SNF4CGP/ExecutiveProcess.hpp View File

#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.

+ 14
- 0
SNF4CGP/InputProcessor.cpp View File

// 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
}

+ 1
- 13
SNF4CGP/InputProcessor.hpp View File

#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:

+ 9
- 7
SNF4CGP/JobPool.hpp View File

#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

+ 4
- 3
SNF4CGP/OutputProcessor.cpp View File

// 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.

+ 5
- 4
SNF4CGP/OutputProcessor.hpp View File

#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.

+ 6
- 4
SNF4CGP/ScannerPool.hpp View File

#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.
}; };

+ 32
- 31
SNF4CGP/WorkerPool.cpp View File

// 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.
} }

+ 4
- 5
SNF4CGP/WorkerPool.hpp View File

#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.

Loading…
Cancel
Save