Completed WAKE process. It's Alive! Starts, WAKEs, QUITs. Now it needs a brain (how to do jobs). git-svn-id: https://svn.microneil.com/svn/SNF4CGP/trunk@23 59e8e3e7-56fa-483b-b4b4-fa6ab0af3dfcmaster
initializeWorkerPool(); | initializeWorkerPool(); | ||||
} | } | ||||
void ExecutiveProcess::doProcessing() { // Command processing happens here. | |||||
void ExecutiveProcess::dispatchWakeupCommand() { | |||||
Command C; | Command C; | ||||
C.Type = Command::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: | |||||
for(;0 == QuitJobNumber;) { // Loop until we have a QUIT job. | |||||
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. | |||||
} | |||||
void ExecutiveProcess::doProcessing() { // Command processing happens here. | |||||
dispatchWakeupCommand(); // First job is to announce ourselves. | |||||
for(;;) { // Then process all jobs but QUIT. | |||||
Command C = Input.getCommand(); | |||||
if(Command::QUIT != C.Type) dispatchCommand(C); | |||||
else { | |||||
QuitJobNumber = C.Number; | |||||
return; | |||||
} | |||||
} | } | ||||
} | } | ||||
void shutdownOutput(); | void shutdownOutput(); | ||||
void dispatchCommand(Command& C); // Job + Worker + Command; go! | void dispatchCommand(Command& C); // Job + Worker + Command; go! | ||||
void dispatchWakeupCommand(); | |||||
public: | public: | ||||
// See www.armresearch.com for more information. | // See www.armresearch.com for more information. | ||||
#include "InputProcessor.hpp" | #include "InputProcessor.hpp" | ||||
#include "Command.hpp" | |||||
#include <iostream> | |||||
#include <sstream> | |||||
#include <string> | |||||
using namespace std; | using namespace std; | ||||
//// InputProcessor //////////////////////////////////////////////////////////// | //// InputProcessor //////////////////////////////////////////////////////////// | ||||
Command& parseCommandNumber(istringstream& S, Command& C) { | |||||
S >> C.Number; | |||||
S.ignore(); | |||||
return C; | |||||
} | |||||
const string INTFCommand = "INTF"; | |||||
const string QUITCommand = "QUIT"; | |||||
const string FILECommand = "FILE"; | |||||
Command& parseCommandType(istringstream& S, Command& C) { | |||||
string TypeString; | |||||
S >> TypeString; | |||||
S.ignore(); | |||||
switch(TypeString[0]) { | |||||
case 'I' : if(INTFCommand == TypeString) C.Type = Command::INTF; break; | |||||
case 'F' : if(FILECommand == TypeString) C.Type = Command::FILE; break; | |||||
case 'Q' : if(QUITCommand == TypeString) C.Type = Command::QUIT; break; | |||||
default : break; | |||||
} | |||||
return C; | |||||
} | |||||
Command& parseCommandData(istringstream& S, Command& C) { | |||||
getline(S,C.Data); | |||||
return C; | |||||
} | |||||
Command InputProcessor::getCommand() { // How to get/parse a command | 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 | |||||
string InputLine; | |||||
getline(cin, InputLine); | |||||
istringstream InputLineStream(InputLine); | |||||
Command NewCommand; | |||||
parseCommandNumber(InputLineStream, NewCommand); // First thing is always a number. | |||||
parseCommandType(InputLineStream, NewCommand); // Next is always a command name. | |||||
parseCommandData(InputLineStream, NewCommand); // The rest is data for the command. | |||||
return NewCommand; | |||||
} | } |
#include "JobPool.hpp" | #include "JobPool.hpp" | ||||
#include "Command.hpp" | #include "Command.hpp" | ||||
#include "ScannerPool.hpp" | #include "ScannerPool.hpp" | ||||
#include "OutputProcessor.hpp" | |||||
#include "../SNFMulti/SNFMulti.hpp" | #include "../SNFMulti/SNFMulti.hpp" | ||||
} | } | ||||
void Job::emitComment(string Comment) { | void Job::emitComment(string Comment) { | ||||
ostringstream O; | |||||
O << "* " << Comment << endl; | |||||
OutputBuffer.append(O.str()); | |||||
} | } | ||||
void Job::emitResponsePrevix() { | void Job::emitResponsePrevix() { | ||||
} | } | ||||
void Job::finalize() { | void Job::finalize() { | ||||
Output.outputJob(*this); | |||||
} | } | ||||
void Job::doWakeUp() { | void Job::doWakeUp() { | ||||
emitComment("SNF4CGP Waking Up"); | |||||
emitComment(CurrentCommand.Data); | |||||
} | } | ||||
void Job::doINTF() { | void Job::doINTF() { |
Workers(W), | Workers(W), | ||||
TimeToStop(false), | TimeToStop(false), | ||||
myJob_(0) { | myJob_(0) { | ||||
run(); | |||||
} | } | ||||
Worker::~Worker() { // Cleanup on the way down. | Worker::~Worker() { // Cleanup on the way down. | ||||
LogicCheck CheckForNoJobsAtStop("Worker::stop() Check(false == isJob())"); | LogicCheck CheckForNoJobsAtStop("Worker::stop() Check(false == isJob())"); | ||||
void Worker::stop() { // Stop the worker thread. | |||||
ScopeMutex CallTheBall(Busy); // Don't stop while busy or vv. | |||||
if(false == TimeToStop) { // Do this only once. | |||||
bool Worker::trySetTimeToStop() { // Statefully set time to stop. | |||||
bool SuccessFlag = false; | |||||
ScopeMutex CallTheBall(Busy); // Don't stop while busy. | |||||
if(false == TimeToStop) { // Do this only if not done yet. | |||||
CheckForNoJobsAtStop(false == isJob()); | CheckForNoJobsAtStop(false == isJob()); | ||||
TimeToStop = true; // It is time to stop. | |||||
StoppingPoint.produce(); // Get busy stopping. | |||||
join(); // Wait for the end. | |||||
TimeToStop = true; | |||||
SuccessFlag = true; | |||||
} | } | ||||
return SuccessFlag; | |||||
} | |||||
void Worker::stop() { // Stop the worker thread. | |||||
if(trySetTimeToStop()) { // First try - set time to stop. | |||||
StoppingPoint.produce(); // Release the hounds. | |||||
join(); // Wait for the end. | |||||
} // Later tries do nothing. | |||||
} | } | ||||
bool Worker::doWork() { // Get the job done. | bool Worker::doWork() { // Get the job done. |
WorkerPool& Workers; // Every worker knows where it lives. | WorkerPool& Workers; // Every worker knows where it lives. | ||||
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; // True if stop() has been called. | |||||
bool trySetTimeToStop(); // Statefully set TimeToSTop. | |||||
bool 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). |
catch(...) { // Display unusual exceptions. | catch(...) { // Display unusual exceptions. | ||||
cout << "* SNF4CGP Unusual Excetption!" << endl; | cout << "* SNF4CGP Unusual Excetption!" << endl; | ||||
} | } | ||||
cout << SNF4CGP_VERSION_INFO << endl; | |||||
cout << ConfigurationPath << endl; | |||||
} | } | ||||
int main(int argc, char* argv[]) { // Main entry point. | int main(int argc, char* argv[]) { // Main entry point. |