$treeview $search $mathjax $extrastylesheet
otsdaq
v2_03_00
$projectbrief
|
$projectbrief
|
$searchbox |
00001 #include "otsdaq-core/GatewaySupervisor/Iterator.h" 00002 #include "otsdaq-core/CoreSupervisors/CoreSupervisorBase.h" 00003 #include "otsdaq-core/GatewaySupervisor/GatewaySupervisor.h" 00004 #include "otsdaq-core/Macros/CoutMacros.h" 00005 #include "otsdaq-core/MessageFacility/MessageFacility.h" 00006 #include "otsdaq-core/WebUsersUtilities/WebUsers.h" 00007 00008 #include <iostream> 00009 #include <thread> //for std::thread 00010 00011 #undef __MF_SUBJECT__ 00012 #define __MF_SUBJECT__ "Iterator" 00013 00014 using namespace ots; 00015 00016 //======================================================================================================================== 00017 Iterator::Iterator(GatewaySupervisor* supervisor) 00018 : workloopRunning_(false) 00019 , activePlanIsRunning_(false) 00020 , iteratorBusy_(false) 00021 , commandPlay_(false) 00022 , commandPause_(false) 00023 , commandHalt_(false) 00024 , activePlanName_("") 00025 , activeCommandIndex_(-1) 00026 , activeCommandStartTime_(0) 00027 , theSupervisor_(supervisor) 00028 { 00029 __MOUT__ << "Iterator constructed." << __E__; 00030 __COUT__ << "Iterator constructed." << __E__; 00031 } 00032 00033 //======================================================================================================================== 00034 Iterator::~Iterator(void) {} 00035 00036 //======================================================================================================================== 00037 void Iterator::IteratorWorkLoop(Iterator* iterator) try 00038 { 00039 __MOUT__ << "Iterator work loop starting..." << __E__; 00040 __COUT__ << "Iterator work loop starting..." << __E__; 00041 00042 // mutex init scope 00043 { 00044 // lockout the messages array for the remainder of the scope 00045 // this guarantees the reading thread can safely access the messages 00046 if(iterator->theSupervisor_->VERBOSE_MUTEX) 00047 __COUT__ << "Waiting for iterator access" << __E__; 00048 std::lock_guard<std::mutex> lock(iterator->accessMutex_); 00049 if(iterator->theSupervisor_->VERBOSE_MUTEX) 00050 __COUT__ << "Have iterator access" << __E__; 00051 00052 iterator->errorMessage_ = ""; // clear error message 00053 } 00054 00055 ConfigurationManagerRW theConfigurationManager( 00056 WebUsers::DEFAULT_ITERATOR_USERNAME); // this is a restricted username 00057 // theConfigurationManager.init(); 00058 theConfigurationManager.getAllTableInfo(true); // to prep all info 00059 00060 IteratorWorkLoopStruct theIteratorStruct(iterator, &theConfigurationManager); 00061 00062 const IterateTable* itConfig; 00063 00064 std::vector<IterateTable::Command> commands; 00065 00066 while(1) 00067 { 00068 // Process: 00069 // - always "listen" for commands 00070 // - play: if no plan running, activePlanIsRunning_ = true, 00071 // and start or continue plan based on name/commandIndex 00072 // - pause: if plan playing, pause it, activePlanIsRunning_ = false 00073 // and do not clear commandIndex or name, iteratorBusy_ = true 00074 // - halt: if plan playing or not, activePlanIsRunning_ = false 00075 // and clear commandIndex or name, iteratorBusy_ = false 00076 // - when running 00077 // - go through each command 00078 // - start the command, commandBusy = true 00079 // - check for complete, then commandBusy = false 00080 00081 // start command handling 00082 // define mutex scope 00083 { 00084 // lockout the messages array for the remainder of the scope 00085 // this guarantees the reading thread can safely access the messages 00086 if(iterator->theSupervisor_->VERBOSE_MUTEX) 00087 __COUT__ << "Waiting for iterator access" << __E__; 00088 std::lock_guard<std::mutex> lock(iterator->accessMutex_); 00089 if(iterator->theSupervisor_->VERBOSE_MUTEX) 00090 __COUT__ << "Have iterator access" << __E__; 00091 00092 if(iterator->commandPlay_) 00093 { 00094 iterator->commandPlay_ = false; // clear 00095 00096 if(!iterator->activePlanIsRunning_) 00097 { 00098 // valid PLAY command! 00099 00100 iterator->activePlanIsRunning_ = true; 00101 iterator->iteratorBusy_ = true; 00102 00103 if(theIteratorStruct.activePlan_ != iterator->activePlanName_) 00104 { 00105 __COUT__ << "New plan name encountered old=" 00106 << theIteratorStruct.activePlan_ 00107 << " vs new=" << iterator->activePlanName_ << __E__; 00108 theIteratorStruct.commandIndex_ = -1; // reset for new plan 00109 } 00110 00111 theIteratorStruct.activePlan_ = iterator->activePlanName_; 00112 iterator->lastStartedPlanName_ = iterator->activePlanName_; 00113 00114 if(theIteratorStruct.commandIndex_ == (unsigned int)-1) 00115 { 00116 __COUT__ << "Starting plan '" << theIteratorStruct.activePlan_ 00117 << ".'" << __E__; 00118 __MOUT__ << "Starting plan '" << theIteratorStruct.activePlan_ 00119 << ".'" << __E__; 00120 } 00121 else 00122 { 00123 theIteratorStruct.doResumeAction_ = true; 00124 __COUT__ << "Continuing plan '" << theIteratorStruct.activePlan_ 00125 << "' at command index " 00126 << theIteratorStruct.commandIndex_ << ". " << __E__; 00127 __MOUT__ << "Continuing plan '" << theIteratorStruct.activePlan_ 00128 << "' at command index " 00129 << theIteratorStruct.commandIndex_ << ". " << __E__; 00130 } 00131 } 00132 } 00133 else if(iterator->commandPause_ && !theIteratorStruct.doPauseAction_) 00134 { 00135 theIteratorStruct.doPauseAction_ = true; 00136 iterator->commandPause_ = false; // clear 00137 } 00138 else if(iterator->commandHalt_ && !theIteratorStruct.doHaltAction_) 00139 { 00140 theIteratorStruct.doHaltAction_ = true; 00141 iterator->commandHalt_ = false; // clear 00142 } 00143 00144 theIteratorStruct.running_ = iterator->activePlanIsRunning_; 00145 00146 if(iterator 00147 ->activeCommandIndex_ != // update active command status if changed 00148 theIteratorStruct.commandIndex_) 00149 { 00150 iterator->activeCommandIndex_ = theIteratorStruct.commandIndex_; 00151 iterator->activeCommandStartTime_ = time(0); // reset on any change 00152 00153 if(theIteratorStruct.commandIndex_ < 00154 theIteratorStruct.commandIterations_.size()) 00155 iterator->activeCommandIteration_ = 00156 theIteratorStruct 00157 .commandIterations_[theIteratorStruct.commandIndex_]; 00158 else 00159 iterator->activeCommandIteration_ = -1; 00160 00161 iterator->depthIterationStack_.clear(); 00162 for(const auto& depthIteration : theIteratorStruct.stepIndexStack_) 00163 iterator->depthIterationStack_.push_back(depthIteration); 00164 // if(theIteratorStruct.stepIndexStack_.size()) 00165 // iterator->activeLoopIteration_ = 00166 // theIteratorStruct.stepIndexStack_.back(); else 00167 // iterator->activeLoopIteration_ = -1; 00168 } 00169 00170 } // end command handling and iterator mutex 00171 00174 // do halt or pause action outside of iterator mutex 00175 00176 if(theIteratorStruct.doPauseAction_) 00177 { 00178 // valid PAUSE command! 00179 00180 // safely pause plan! 00181 // i.e. check that command is complete 00182 00183 __COUT__ << "Waiting to pause..." << __E__; 00184 while(!iterator->checkCommand(&theIteratorStruct)) 00185 __COUT__ << "Waiting to pause..." << __E__; 00186 00187 __COUT__ << "Completing pause..." << __E__; 00188 00189 theIteratorStruct.doPauseAction_ = false; // clear 00190 00191 // lockout the messages array for the remainder of the scope 00192 // this guarantees the reading thread can safely access the messages 00193 if(iterator->theSupervisor_->VERBOSE_MUTEX) 00194 __COUT__ << "Waiting for iterator access" << __E__; 00195 std::lock_guard<std::mutex> lock(iterator->accessMutex_); 00196 if(iterator->theSupervisor_->VERBOSE_MUTEX) 00197 __COUT__ << "Have iterator access" << __E__; 00198 00199 iterator->activePlanIsRunning_ = false; 00200 00201 __COUT__ << "Paused plan '" << theIteratorStruct.activePlan_ 00202 << "' at command index " << theIteratorStruct.commandIndex_ << ". " 00203 << __E__; 00204 __MOUT__ << "Paused plan '" << theIteratorStruct.activePlan_ 00205 << "' at command index " << theIteratorStruct.commandIndex_ << ". " 00206 << __E__; 00207 00208 continue; // resume workloop 00209 } 00210 else if(theIteratorStruct.doHaltAction_) 00211 { 00212 // valid HALT command! 00213 00214 // safely end plan! 00215 // i.e. check that command is complete 00216 00217 __COUT__ << "Waiting to halt..." << __E__; 00218 while(!iterator->checkCommand(&theIteratorStruct)) 00219 __COUT__ << "Waiting to halt..." << __E__; 00220 00221 __COUT__ << "Completing halt..." << __E__; 00222 00223 theIteratorStruct.doHaltAction_ = false; // clear 00224 00225 iterator->haltIterator(iterator, &theIteratorStruct); 00226 00227 // //last ditch effort to make sure FSM is halted 00228 // iterator->haltIterator( 00229 // iterator->theSupervisor_, 00230 // theIteratorStruct.fsmName_); 00231 // 00232 // //lockout the messages array for the remainder of the scope 00233 // //this guarantees the reading thread can safely access the 00234 // messages 00235 // if(iterator->theSupervisor_->VERBOSE_MUTEX) __COUT__ << "Waiting 00236 // for iterator access" << __E__; std::lock_guard<std::mutex> 00237 // lock(iterator->accessMutex_); 00238 // if(iterator->theSupervisor_->VERBOSE_MUTEX) __COUT__ << "Have 00239 // iterator access" << __E__; 00240 // 00241 // iterator->activePlanIsRunning_ = false; 00242 // iterator->iteratorBusy_ = false; 00243 // 00244 // __COUT__ << "Halted plan '" << theIteratorStruct.activePlan_ << "' 00245 // at command index " << theIteratorStruct.commandIndex_ << 00246 //". " << __E__; 00247 // __MOUT__ << "Halted plan '" << theIteratorStruct.activePlan_ << "' 00248 // at command index " << theIteratorStruct.commandIndex_ << 00249 //". " << __E__; 00250 // 00251 // theIteratorStruct.activePlan_ = ""; //clear 00252 // theIteratorStruct.commandIndex_ = -1; //clear 00253 00254 continue; // resume workloop 00255 } 00256 00259 // handle running 00260 // __COUT__ << "thinking.." << theIteratorStruct.running_ << " " << 00261 // theIteratorStruct.activePlan_ << " cmd=" << 00262 // theIteratorStruct.commandIndex_ << __E__; 00263 if(theIteratorStruct.running_ && 00264 theIteratorStruct.activePlan_ != 00265 "") // important, because after errors, still "running" until halt 00266 { 00267 if(theIteratorStruct.commandIndex_ == (unsigned int)-1) 00268 { 00269 // initialize the running plan 00270 00271 __COUT__ << "Get commands" << __E__; 00272 00273 theIteratorStruct.commandIndex_ = 0; 00274 00275 theIteratorStruct.cfgMgr_ 00276 ->init(); // completely reset to re-align with any changes 00277 itConfig = theIteratorStruct.cfgMgr_->__GET_CONFIG__(IterateTable); 00278 00279 theIteratorStruct.commands_ = itConfig->getPlanCommands( 00280 theIteratorStruct.cfgMgr_, theIteratorStruct.activePlan_); 00281 00282 // reset commandIteration counts 00283 theIteratorStruct.commandIterations_.clear(); 00284 for(auto& command : theIteratorStruct.commands_) 00285 { 00286 theIteratorStruct.commandIterations_.push_back(0); 00287 __COUT__ << "command " << command.type_ << __E__; 00288 __COUT__ << "table " 00289 << IterateTable::commandToTableMap_.at(command.type_) 00290 << __E__; 00291 __COUT__ << "param count = " << command.params_.size() << __E__; 00292 00293 for(auto& param : command.params_) 00294 { 00295 __COUT__ << "\t param " << param.first << " : " << param.second 00296 << __E__; 00297 } 00298 } 00299 00300 theIteratorStruct.originalTrackChanges_ = 00301 ConfigurationInterface::isVersionTrackingEnabled(); 00302 theIteratorStruct.originalConfigGroup_ = 00303 theIteratorStruct.cfgMgr_->getActiveGroupName(); 00304 theIteratorStruct.originalConfigKey_ = 00305 theIteratorStruct.cfgMgr_->getActiveGroupKey(); 00306 00307 __COUT__ << "originalTrackChanges " 00308 << theIteratorStruct.originalTrackChanges_ << __E__; 00309 __COUT__ << "originalConfigGroup " 00310 << theIteratorStruct.originalConfigGroup_ << __E__; 00311 __COUT__ << "originalConfigKey " << theIteratorStruct.originalConfigKey_ 00312 << __E__; 00313 00314 } // end initial section 00315 00316 if(!theIteratorStruct.commandBusy_) 00317 { 00318 if(theIteratorStruct.commandIndex_ < theIteratorStruct.commands_.size()) 00319 { 00320 // execute command 00321 theIteratorStruct.commandBusy_ = true; 00322 00323 __COUT__ << "Iterator starting command " 00324 << theIteratorStruct.commandIndex_ + 1 << ": " 00325 << theIteratorStruct 00326 .commands_[theIteratorStruct.commandIndex_] 00327 .type_ 00328 << __E__; 00329 __MOUT__ << "Iterator starting command " 00330 << theIteratorStruct.commandIndex_ + 1 << ": " 00331 << theIteratorStruct 00332 .commands_[theIteratorStruct.commandIndex_] 00333 .type_ 00334 << __E__; 00335 00336 iterator->startCommand(&theIteratorStruct); 00337 } 00338 else if(theIteratorStruct.commandIndex_ == 00339 theIteratorStruct.commands_.size()) // Done! 00340 { 00341 __COUT__ << "Finished Iteration Plan '" 00342 << theIteratorStruct.activePlan_ << __E__; 00343 __MOUT__ << "Finished Iteration Plan '" 00344 << theIteratorStruct.activePlan_ << __E__; 00345 00346 __COUT__ << "Reverting track changes." << __E__; 00347 ConfigurationInterface::setVersionTrackingEnabled( 00348 theIteratorStruct.originalTrackChanges_); 00349 00350 __COUT__ << "Activating original group..." << __E__; 00351 try 00352 { 00353 theIteratorStruct.cfgMgr_->activateTableGroup( 00354 theIteratorStruct.originalConfigGroup_, 00355 theIteratorStruct.originalConfigKey_); 00356 } 00357 catch(...) 00358 { 00359 __COUT_WARN__ << "Original group could not be activated." 00360 << __E__; 00361 } 00362 00363 // leave FSM halted 00364 __COUT__ << "Completing halt..." << __E__; 00365 00366 iterator->haltIterator(iterator, &theIteratorStruct); 00367 00368 // 00369 // //leave FSM halted 00370 // iterator->haltIterator( 00371 // iterator->theSupervisor_, 00372 // theIteratorStruct.fsmName_); 00373 // 00374 // //lockout the messages array for the remainder of 00375 // the scope 00376 // //this guarantees the reading thread can safely 00377 // access the messages 00378 // if(iterator->theSupervisor_->VERBOSE_MUTEX) 00379 //__COUT__ 00380 //<< "Waiting for iterator access" << __E__; 00381 // std::lock_guard<std::mutex> 00382 // lock(iterator->accessMutex_); 00383 // if(iterator->theSupervisor_->VERBOSE_MUTEX) 00384 //__COUT__ 00385 //<< "Have iterator access" << __E__; 00386 // 00387 // //similar to halt 00388 // iterator->activePlanIsRunning_ = false; 00389 // iterator->iteratorBusy_ = false; 00390 // 00391 // iterator->lastStartedPlanName_ = 00392 // theIteratorStruct.activePlan_; 00393 // theIteratorStruct.activePlan_ = ""; //clear 00394 // theIteratorStruct.commandIndex_ = -1; //clear 00395 } 00396 } 00397 else if(theIteratorStruct.commandBusy_) 00398 { 00399 // check for command completion 00400 if(iterator->checkCommand(&theIteratorStruct)) 00401 { 00402 theIteratorStruct.commandBusy_ = false; // command complete 00403 00404 ++theIteratorStruct.commandIndex_; 00405 00406 __COUT__ << "Ready for next command. Done with " 00407 << theIteratorStruct.commandIndex_ << " of " 00408 << theIteratorStruct.commands_.size() << __E__; 00409 __MOUT__ << "Iterator ready for next command. Done with " 00410 << theIteratorStruct.commandIndex_ << " of " 00411 << theIteratorStruct.commands_.size() << __E__; 00412 } 00413 00414 // Note: check command gets one shot to resume 00415 if(theIteratorStruct.doResumeAction_) // end resume action 00416 theIteratorStruct.doResumeAction_ = false; 00417 } 00418 00419 } // end running 00420 else 00421 sleep(1); // when inactive sleep a lot 00422 00425 00426 // __COUT__ << "end loop.." << theIteratorStruct.running_ << " " << 00427 // theIteratorStruct.activePlan_ << " cmd=" << 00428 // theIteratorStruct.commandIndex_ << __E__; 00429 } 00430 00431 iterator->workloopRunning_ = false; // if we ever exit 00432 } 00433 catch(const std::runtime_error& e) 00434 { 00435 __SS__ << "Encountered error in Iterator thread:\n" << e.what() << __E__; 00436 __COUT_ERR__ << ss.str(); 00437 00438 // lockout the messages array for the remainder of the scope 00439 // this guarantees the reading thread can safely access the messages 00440 if(iterator->theSupervisor_->VERBOSE_MUTEX) 00441 __COUT__ << "Waiting for iterator access" << __E__; 00442 std::lock_guard<std::mutex> lock(iterator->accessMutex_); 00443 if(iterator->theSupervisor_->VERBOSE_MUTEX) 00444 __COUT__ << "Have iterator access" << __E__; 00445 00446 iterator->workloopRunning_ = false; // if we ever exit 00447 iterator->errorMessage_ = ss.str(); 00448 } 00449 catch(...) 00450 { 00451 __SS__ << "Encountered unknown error in Iterator thread." << __E__; 00452 __COUT_ERR__ << ss.str(); 00453 00454 // lockout the messages array for the remainder of the scope 00455 // this guarantees the reading thread can safely access the messages 00456 if(iterator->theSupervisor_->VERBOSE_MUTEX) 00457 __COUT__ << "Waiting for iterator access" << __E__; 00458 std::lock_guard<std::mutex> lock(iterator->accessMutex_); 00459 if(iterator->theSupervisor_->VERBOSE_MUTEX) 00460 __COUT__ << "Have iterator access" << __E__; 00461 00462 iterator->workloopRunning_ = false; // if we ever exit 00463 iterator->errorMessage_ = ss.str(); 00464 } // end IteratorWorkLoop() 00465 00466 //======================================================================================================================== 00467 void Iterator::startCommand(IteratorWorkLoopStruct* iteratorStruct) try 00468 { 00469 { 00470 int i = 0; 00471 for(const auto& depthIteration : iteratorStruct->stepIndexStack_) 00472 { 00473 __COUT__ << i++ << ":" << depthIteration << __E__; 00474 } 00475 } 00476 00477 // should be mutually exclusive with GatewaySupervisor main thread state machine 00478 // accesses lockout the messages array for the remainder of the scope this 00479 // guarantees the reading thread can safely access the messages 00480 if(iteratorStruct->theIterator_->theSupervisor_->VERBOSE_MUTEX) 00481 __COUT__ << "Waiting for FSM access" << __E__; 00482 std::lock_guard<std::mutex> lock( 00483 iteratorStruct->theIterator_->theSupervisor_->stateMachineAccessMutex_); 00484 if(iteratorStruct->theIterator_->theSupervisor_->VERBOSE_MUTEX) 00485 __COUT__ << "Have FSM access" << __E__; 00486 00487 // for out of range, throw exception - should never happen 00488 if(iteratorStruct->commandIndex_ >= iteratorStruct->commands_.size()) 00489 { 00490 __SS__ << "Out of range commandIndex = " << iteratorStruct->commandIndex_ 00491 << " in size = " << iteratorStruct->commands_.size() << __E__; 00492 __SS_THROW__; 00493 } 00494 00495 // increment iteration count for command 00496 ++iteratorStruct->commandIterations_[iteratorStruct->commandIndex_]; 00497 00498 std::string type = iteratorStruct->commands_[iteratorStruct->commandIndex_].type_; 00499 if(type == IterateTable::COMMAND_BEGIN_LABEL) 00500 { 00501 return startCommandBeginLabel(iteratorStruct); 00502 } 00503 else if(type == IterateTable::COMMAND_CHOOSE_FSM) 00504 { 00505 return startCommandChooseFSM( 00506 iteratorStruct, 00507 iteratorStruct->commands_[iteratorStruct->commandIndex_] 00508 .params_[IterateTable::commandChooseFSMParams_.NameOfFSM_]); 00509 } 00510 else if(type == IterateTable::COMMAND_CONFIGURE_ACTIVE_GROUP) 00511 { 00512 return startCommandConfigureActive(iteratorStruct); 00513 } 00514 else if(type == IterateTable::COMMAND_CONFIGURE_ALIAS) 00515 { 00516 return startCommandConfigureAlias( 00517 iteratorStruct, 00518 iteratorStruct->commands_[iteratorStruct->commandIndex_] 00519 .params_[IterateTable::commandConfigureAliasParams_.SystemAlias_]); 00520 } 00521 else if(type == IterateTable::COMMAND_CONFIGURE_GROUP) 00522 { 00523 return startCommandConfigureGroup(iteratorStruct); 00524 } 00525 else if(type == IterateTable::COMMAND_EXECUTE_FE_MACRO) 00526 { 00527 return startCommandMacro(iteratorStruct, true /*isFEMacro*/); 00528 } 00529 else if(type == IterateTable::COMMAND_EXECUTE_MACRO) 00530 { 00531 return startCommandMacro(iteratorStruct, false /*isFEMacro*/); 00532 } 00533 else if(type == IterateTable::COMMAND_MODIFY_ACTIVE_GROUP) 00534 { 00535 return startCommandModifyActive(iteratorStruct); 00536 } 00537 else if(type == IterateTable::COMMAND_REPEAT_LABEL) 00538 { 00539 return startCommandRepeatLabel(iteratorStruct); 00540 } 00541 else if(type == IterateTable::COMMAND_RUN) 00542 { 00543 return startCommandRun(iteratorStruct); 00544 } 00545 else 00546 { 00547 __SS__ << "Failed attempt to start unrecognized command type = " << type << __E__; 00548 __COUT_ERR__ << ss.str(); 00549 __SS_THROW__; 00550 } 00551 } 00552 catch(...) 00553 { 00554 __COUT__ << "Error caught. Reverting track changes." << __E__; 00555 ConfigurationInterface::setVersionTrackingEnabled( 00556 iteratorStruct->originalTrackChanges_); 00557 00558 __COUT__ << "Activating original group..." << __E__; 00559 try 00560 { 00561 iteratorStruct->cfgMgr_->activateTableGroup(iteratorStruct->originalConfigGroup_, 00562 iteratorStruct->originalConfigKey_); 00563 } 00564 catch(...) 00565 { 00566 __COUT_WARN__ << "Original group could not be activated." << __E__; 00567 } 00568 throw; 00569 } // end startCommand() 00570 00571 //======================================================================================================================== 00572 // checkCommand 00573 // when busy for a while, start to sleep 00574 // use sleep() or nanosleep() 00575 bool Iterator::checkCommand(IteratorWorkLoopStruct* iteratorStruct) try 00576 { 00577 // for out of range, return done 00578 if(iteratorStruct->commandIndex_ >= iteratorStruct->commands_.size()) 00579 { 00580 __COUT__ << "Out of range commandIndex = " << iteratorStruct->commandIndex_ 00581 << " in size = " << iteratorStruct->commands_.size() << __E__; 00582 return true; 00583 } 00584 00585 std::string type = iteratorStruct->commands_[iteratorStruct->commandIndex_].type_; 00586 if(type == IterateTable::COMMAND_BEGIN_LABEL) 00587 { 00588 // do nothing 00589 return true; 00590 } 00591 else if(type == IterateTable::COMMAND_CHOOSE_FSM) 00592 { 00593 // do nothing 00594 return true; 00595 } 00596 else if(type == IterateTable::COMMAND_CONFIGURE_ALIAS || 00597 type == IterateTable::COMMAND_CONFIGURE_ACTIVE_GROUP || 00598 type == IterateTable::COMMAND_CONFIGURE_GROUP) 00599 { 00600 return checkCommandConfigure(iteratorStruct); 00601 } 00602 else if(type == IterateTable::COMMAND_EXECUTE_FE_MACRO) 00603 { 00604 return checkCommandMacro(iteratorStruct, true /*isFEMacro*/); 00605 } 00606 else if(type == IterateTable::COMMAND_EXECUTE_MACRO) 00607 { 00608 return checkCommandMacro(iteratorStruct, false /*isFEMacro*/); 00609 } 00610 else if(type == IterateTable::COMMAND_MODIFY_ACTIVE_GROUP) 00611 { 00612 // do nothing 00613 return true; 00614 } 00615 else if(type == IterateTable::COMMAND_REPEAT_LABEL) 00616 { 00617 // do nothing 00618 return true; 00619 } 00620 else if(type == IterateTable::COMMAND_RUN) 00621 { 00622 return checkCommandRun(iteratorStruct); 00623 } 00624 else 00625 { 00626 __SS__ << "Attempt to check unrecognized command type = " << type << __E__; 00627 __COUT_ERR__ << ss.str(); 00628 __SS_THROW__; 00629 } 00630 } 00631 catch(...) 00632 { 00633 __COUT__ << "Error caught. Reverting track changes." << __E__; 00634 ConfigurationInterface::setVersionTrackingEnabled( 00635 iteratorStruct->originalTrackChanges_); 00636 00637 __COUT__ << "Activating original group..." << __E__; 00638 try 00639 { 00640 iteratorStruct->cfgMgr_->activateTableGroup(iteratorStruct->originalConfigGroup_, 00641 iteratorStruct->originalConfigKey_); 00642 } 00643 catch(...) 00644 { 00645 __COUT_WARN__ << "Original group could not be activated." << __E__; 00646 } 00647 00648 throw; 00649 } // end checkCommand() 00650 00651 //======================================================================================================================== 00652 void Iterator::startCommandChooseFSM(IteratorWorkLoopStruct* iteratorStruct, 00653 const std::string& fsmName) 00654 { 00655 __COUT__ << "fsmName " << fsmName << __E__; 00656 00657 iteratorStruct->fsmName_ = fsmName; 00658 iteratorStruct->theIterator_->lastFsmName_ = fsmName; 00659 00660 // Translate fsmName 00661 // to gives us run alias (fsmRunAlias_) and next run number (fsmNextRunNumber_) 00662 00663 // CAREFUL?? Threads 00664 00666 00667 iteratorStruct->fsmRunAlias_ = "Run"; // default to "Run" 00668 00669 // get stateMachineAliasFilter if possible 00670 ConfigurationTree configLinkNode = iteratorStruct->cfgMgr_->getSupervisorTableNode( 00671 iteratorStruct->theIterator_->theSupervisor_->getContextUID(), 00672 iteratorStruct->theIterator_->theSupervisor_->getSupervisorUID()); 00673 00674 if(!configLinkNode.isDisconnected()) 00675 { 00676 try // for backwards compatibility 00677 { 00678 ConfigurationTree fsmLinkNode = 00679 configLinkNode.getNode("LinkToStateMachineTable"); 00680 if(!fsmLinkNode.isDisconnected()) 00681 iteratorStruct->fsmRunAlias_ = 00682 fsmLinkNode.getNode(fsmName + "/RunDisplayAlias") 00683 .getValue<std::string>(); 00684 else 00685 __COUT_INFO__ << "FSM Link disconnected." << __E__; 00686 } 00687 catch(std::runtime_error& e) 00688 { 00689 //__COUT_INFO__ << e.what() << __E__; 00690 __COUT_INFO__ 00691 << "No state machine Run alias. Ignoring and assuming alias of '" 00692 << iteratorStruct->fsmRunAlias_ << ".'" << __E__; 00693 } 00694 catch(...) 00695 { 00696 __COUT_ERR__ << "Unknown error. Should never happen." << __E__; 00697 00698 __COUT_INFO__ 00699 << "No state machine Run alias. Ignoring and assuming alias of '" 00700 << iteratorStruct->fsmRunAlias_ << ".'" << __E__; 00701 } 00702 } 00703 else 00704 __COUT_INFO__ << "FSM Link disconnected." << __E__; 00705 00706 __COUT__ << "fsmRunAlias_ = " << iteratorStruct->fsmRunAlias_ << __E__; 00707 00709 00710 iteratorStruct->fsmNextRunNumber_ = 00711 iteratorStruct->theIterator_->theSupervisor_->getNextRunNumber( 00712 iteratorStruct->fsmName_); 00713 00714 if(iteratorStruct->theIterator_->theSupervisor_->theStateMachine_ 00715 .getCurrentStateName() == "Running" || 00716 iteratorStruct->theIterator_->theSupervisor_->theStateMachine_ 00717 .getCurrentStateName() == "Paused") 00718 --iteratorStruct->fsmNextRunNumber_; // current run number is one back 00719 00720 __COUT__ << "fsmNextRunNumber_ = " << iteratorStruct->fsmNextRunNumber_ << __E__; 00721 } // end startCommandChooseFSM() 00722 00723 //======================================================================================================================== 00724 // return true if an action was attempted 00725 bool Iterator::haltIterator(Iterator* iterator, IteratorWorkLoopStruct* iteratorStruct) 00726 //(GatewaySupervisor* theSupervisor, const std::string& fsmName) 00727 { 00728 GatewaySupervisor* theSupervisor = iterator->theSupervisor_; 00729 const std::string& fsmName = iterator->lastFsmName_; 00730 00731 std::vector<std::string> fsmCommandParameters; 00732 std::string errorStr = ""; 00733 std::string currentState = theSupervisor->theStateMachine_.getCurrentStateName(); 00734 00735 bool haltAttempted = true; 00736 if(currentState == "Initialized" || currentState == "Halted") 00737 { 00738 __COUT__ << "Do nothing. Already halted." << __E__; 00739 haltAttempted = false; 00740 } 00741 else if(currentState == "Running") 00742 errorStr = theSupervisor->attemptStateMachineTransition( 00743 0, 00744 0, 00745 "Abort", 00746 fsmName, 00747 WebUsers::DEFAULT_ITERATOR_USERNAME /*fsmWindowName*/, 00748 WebUsers::DEFAULT_ITERATOR_USERNAME, 00749 fsmCommandParameters); 00750 else 00751 errorStr = theSupervisor->attemptStateMachineTransition( 00752 0, 00753 0, 00754 "Halt", 00755 fsmName, 00756 WebUsers::DEFAULT_ITERATOR_USERNAME /*fsmWindowName*/, 00757 WebUsers::DEFAULT_ITERATOR_USERNAME, 00758 fsmCommandParameters); 00759 00760 if(haltAttempted) 00761 { 00762 if(errorStr != "") 00763 { 00764 __SS__ << "Iterator failed to halt because of the following error: " 00765 << errorStr; 00766 __SS_THROW__; 00767 } 00768 00769 // else successfully launched 00770 __COUT__ << "FSM in transition = " 00771 << theSupervisor->theStateMachine_.isInTransition() << __E__; 00772 __COUT__ << "halting state machine launched." << __E__; 00773 } 00774 00775 // finish up halting the iterator 00776 __COUT__ << "Conducting Iterator halt." << __E__; 00777 00778 if(iteratorStruct) 00779 { 00780 __COUT__ << "Reverting track changes." << __E__; 00781 ConfigurationInterface::setVersionTrackingEnabled( 00782 iteratorStruct->originalTrackChanges_); 00783 00784 __COUT__ << "Activating original group..." << __E__; 00785 try 00786 { 00787 iteratorStruct->cfgMgr_->activateTableGroup( 00788 iteratorStruct->originalConfigGroup_, iteratorStruct->originalConfigKey_); 00789 } 00790 catch(...) 00791 { 00792 __COUT_WARN__ << "Original group could not be activated." << __E__; 00793 } 00794 } 00795 00796 // lockout the messages array for the remainder of the scope 00797 // this guarantees the reading thread can safely access the messages 00798 if(iterator->theSupervisor_->VERBOSE_MUTEX) 00799 __COUT__ << "Waiting for iterator access" << __E__; 00800 std::lock_guard<std::mutex> lock(iterator->accessMutex_); 00801 if(iterator->theSupervisor_->VERBOSE_MUTEX) 00802 __COUT__ << "Have iterator access" << __E__; 00803 00804 iterator->activePlanIsRunning_ = false; 00805 iterator->iteratorBusy_ = false; 00806 00807 // clear 00808 iterator->activePlanName_ = ""; 00809 iterator->activeCommandIndex_ = -1; 00810 00811 if(iteratorStruct) 00812 { 00813 __COUT__ << "Halted plan '" << iteratorStruct->activePlan_ 00814 << "' at command index " << iteratorStruct->commandIndex_ << ". " 00815 << __E__; 00816 __MOUT__ << "Halted plan '" << iteratorStruct->activePlan_ 00817 << "' at command index " << iteratorStruct->commandIndex_ << ". " 00818 << __E__; 00819 00820 iterator->lastStartedPlanName_ = iteratorStruct->activePlan_; 00821 iteratorStruct->activePlan_ = ""; // clear 00822 iteratorStruct->commandIndex_ = -1; // clear 00823 } 00824 00825 return haltAttempted; 00826 } // end haltIterator() 00827 00828 //======================================================================================================================== 00829 void Iterator::startCommandBeginLabel(IteratorWorkLoopStruct* iteratorStruct) 00830 { 00831 __COUT__ << "Entering label '" 00832 << iteratorStruct->commands_[iteratorStruct->commandIndex_] 00833 .params_[IterateTable::commandBeginLabelParams_.Label_] 00834 << "'..." << std::endl; 00835 00836 // add new step index to stack 00837 iteratorStruct->stepIndexStack_.push_back(0); 00838 } // end startCommandBeginLabel() 00839 00840 //======================================================================================================================== 00841 void Iterator::startCommandRepeatLabel(IteratorWorkLoopStruct* iteratorStruct) 00842 { 00843 // search for first matching label backward and set command to there 00844 00845 int numOfRepetitions; 00846 sscanf(iteratorStruct->commands_[iteratorStruct->commandIndex_] 00847 .params_[IterateTable::commandRepeatLabelParams_.NumberOfRepetitions_] 00848 .c_str(), 00849 "%d", 00850 &numOfRepetitions); 00851 __COUT__ << "numOfRepetitions remaining = " << numOfRepetitions << __E__; 00852 00853 char repStr[200]; 00854 00855 if(numOfRepetitions <= 0) 00856 { 00857 // write original number of repetitions value back 00858 sprintf(repStr, "%d", iteratorStruct->stepIndexStack_.back()); 00859 iteratorStruct->commands_[iteratorStruct->commandIndex_] 00860 .params_[IterateTable::commandRepeatLabelParams_.NumberOfRepetitions_] = 00861 repStr; // re-store as string 00862 00863 // remove step index from stack 00864 iteratorStruct->stepIndexStack_.pop_back(); 00865 00866 return; // no more repetitions 00867 } 00868 00869 --numOfRepetitions; 00870 00871 // increment step index in stack 00872 ++(iteratorStruct->stepIndexStack_.back()); 00873 00874 unsigned int i; 00875 for(i = iteratorStruct->commandIndex_; i > 0; 00876 --i) // assume 0 is always the fallback option 00877 if(iteratorStruct->commands_[i].type_ == IterateTable::COMMAND_BEGIN_LABEL && 00878 iteratorStruct->commands_[iteratorStruct->commandIndex_] 00879 .params_[IterateTable::commandRepeatLabelParams_.Label_] == 00880 iteratorStruct->commands_[i] 00881 .params_[IterateTable::commandBeginLabelParams_.Label_]) 00882 break; 00883 00884 sprintf(repStr, "%d", numOfRepetitions); 00885 iteratorStruct->commands_[iteratorStruct->commandIndex_] 00886 .params_[IterateTable::commandRepeatLabelParams_.NumberOfRepetitions_] = 00887 repStr; // re-store as string 00888 00889 iteratorStruct->commandIndex_ = i; 00890 __COUT__ << "Jumping back to commandIndex " << iteratorStruct->commandIndex_ << __E__; 00891 } // end startCommandRepeatLabel() 00892 00893 //======================================================================================================================== 00894 void Iterator::startCommandRun(IteratorWorkLoopStruct* iteratorStruct) 00895 { 00896 iteratorStruct->runIsDone_ = false; 00897 iteratorStruct->fsmCommandParameters_.clear(); 00898 00899 std::string errorStr = ""; 00900 std::string currentState = iteratorStruct->theIterator_->theSupervisor_ 00901 ->theStateMachine_.getCurrentStateName(); 00902 00903 // execute first transition (may need two) 00904 00905 if(currentState == "Configured") 00906 errorStr = 00907 iteratorStruct->theIterator_->theSupervisor_->attemptStateMachineTransition( 00908 0, 00909 0, 00910 "Start", 00911 iteratorStruct->fsmName_, 00912 WebUsers::DEFAULT_ITERATOR_USERNAME /*fsmWindowName*/, 00913 WebUsers::DEFAULT_ITERATOR_USERNAME, 00914 iteratorStruct->fsmCommandParameters_); 00915 else 00916 errorStr = "Can only Run from the Configured state. The current state is " + 00917 currentState; 00918 00919 if(errorStr != "") 00920 { 00921 __SS__ << "Iterator failed to run because of the following error: " << errorStr; 00922 __SS_THROW__; 00923 } 00924 00925 // else successfully launched 00926 __COUT__ 00927 << "FSM in transition = " 00928 << iteratorStruct->theIterator_->theSupervisor_->theStateMachine_.isInTransition() 00929 << __E__; 00930 __COUT__ << "startCommandRun success." << __E__; 00931 } // end startCommandRun() 00932 00933 //======================================================================================================================== 00934 void Iterator::startCommandConfigureActive(IteratorWorkLoopStruct* iteratorStruct) 00935 { 00936 __COUT__ << "startCommandConfigureActive " << __E__; 00937 00938 // steps: 00939 // get active config group 00940 // transition to configure with parameters describing group 00941 00942 std::string group = iteratorStruct->cfgMgr_->getActiveGroupName(); 00943 TableGroupKey key = iteratorStruct->cfgMgr_->getActiveGroupKey(); 00944 00945 __COUT__ << "group " << group << __E__; 00946 __COUT__ << "key " << key << __E__; 00947 00948 // create special alias for this group using : separators 00949 00950 std::stringstream systemAlias; 00951 systemAlias << "GROUP:" << group << ":" << key; 00952 startCommandConfigureAlias(iteratorStruct, systemAlias.str()); 00953 } // end startCommandConfigureActive() 00954 00955 //======================================================================================================================== 00956 void Iterator::startCommandConfigureGroup(IteratorWorkLoopStruct* iteratorStruct) 00957 { 00958 __COUT__ << "startCommandConfigureGroup " << __E__; 00959 00960 // steps: 00961 // transition to configure with parameters describing group 00962 00963 std::string group = 00964 iteratorStruct->commands_[iteratorStruct->commandIndex_] 00965 .params_[IterateTable::commandConfigureGroupParams_.GroupName_]; 00966 TableGroupKey key = 00967 TableGroupKey(iteratorStruct->commands_[iteratorStruct->commandIndex_] 00968 .params_[IterateTable::commandConfigureGroupParams_.GroupKey_]); 00969 00970 __COUT__ << "group " << group << __E__; 00971 __COUT__ << "key " << key << __E__; 00972 00973 // create special alias for this group using : separators 00974 00975 std::stringstream systemAlias; 00976 systemAlias << "GROUP:" << group << ":" << key; 00977 startCommandConfigureAlias(iteratorStruct, systemAlias.str()); 00978 } // end startCommandConfigureGroup() 00979 00980 //======================================================================================================================== 00981 void Iterator::startCommandConfigureAlias(IteratorWorkLoopStruct* iteratorStruct, 00982 const std::string& systemAlias) 00983 { 00984 __COUT__ << "systemAlias " << systemAlias << __E__; 00985 00986 iteratorStruct->fsmCommandParameters_.clear(); 00987 iteratorStruct->fsmCommandParameters_.push_back(systemAlias); 00988 00989 std::string errorStr = ""; 00990 std::string currentState = iteratorStruct->theIterator_->theSupervisor_ 00991 ->theStateMachine_.getCurrentStateName(); 00992 00993 // execute first transition (may need two in conjunction with checkCommandConfigure()) 00994 00995 if(currentState == "Initial") 00996 errorStr = 00997 iteratorStruct->theIterator_->theSupervisor_->attemptStateMachineTransition( 00998 0, 00999 0, 01000 "Initialize", 01001 iteratorStruct->fsmName_, 01002 WebUsers::DEFAULT_ITERATOR_USERNAME /*fsmWindowName*/, 01003 WebUsers::DEFAULT_ITERATOR_USERNAME, 01004 iteratorStruct->fsmCommandParameters_); 01005 else if(currentState == "Halted") 01006 errorStr = 01007 iteratorStruct->theIterator_->theSupervisor_->attemptStateMachineTransition( 01008 0, 01009 0, 01010 "Configure", 01011 iteratorStruct->fsmName_, 01012 WebUsers::DEFAULT_ITERATOR_USERNAME /*fsmWindowName*/, 01013 WebUsers::DEFAULT_ITERATOR_USERNAME, 01014 iteratorStruct->fsmCommandParameters_); 01015 else if(currentState == "Configured") 01016 errorStr = 01017 iteratorStruct->theIterator_->theSupervisor_->attemptStateMachineTransition( 01018 0, 01019 0, 01020 "Halt", 01021 iteratorStruct->fsmName_, 01022 WebUsers::DEFAULT_ITERATOR_USERNAME /*fsmWindowName*/, 01023 WebUsers::DEFAULT_ITERATOR_USERNAME, 01024 iteratorStruct->fsmCommandParameters_); 01025 else 01026 errorStr = 01027 "Can only Configure from the Initial or Halted state. The current state is " + 01028 currentState; 01029 01030 if(errorStr != "") 01031 { 01032 __SS__ << "Iterator failed to configure with system alias '" 01033 << (iteratorStruct->fsmCommandParameters_.size() 01034 ? iteratorStruct->fsmCommandParameters_[0] 01035 : "UNKNOWN") 01036 << "' because of the following error: " << errorStr; 01037 __SS_THROW__; 01038 } 01039 01040 // else successfully launched 01041 __COUT__ 01042 << "FSM in transition = " 01043 << iteratorStruct->theIterator_->theSupervisor_->theStateMachine_.isInTransition() 01044 << __E__; 01045 __COUT__ << "startCommandConfigureAlias success." << __E__; 01046 } // end startCommandConfigureAlias() 01047 01048 //======================================================================================================================== 01049 void Iterator::startCommandMacro(IteratorWorkLoopStruct* iteratorStruct, 01050 bool isFrontEndMacro) 01051 { 01052 // Steps: 01053 // 4 parameters CommandExecuteFEMacroParams: 01054 // //targets 01055 // const std::string FEMacroName_ = "FEMacroName"; 01056 // //macro parameters (table/groupID) 01057 01058 const std::string& macroName = 01059 iteratorStruct->commands_[iteratorStruct->commandIndex_] 01060 .params_[IterateTable::commandExecuteMacroParams_.MacroName_]; 01061 const std::string& enableSavingOutput = 01062 iteratorStruct->commands_[iteratorStruct->commandIndex_] 01063 .params_[IterateTable::commandExecuteMacroParams_.EnableSavingOutput_]; 01064 const std::string& outputFilePath = 01065 iteratorStruct->commands_[iteratorStruct->commandIndex_] 01066 .params_[IterateTable::commandExecuteMacroParams_.OutputFilePath_]; 01067 const std::string& outputFileRadix = 01068 iteratorStruct->commands_[iteratorStruct->commandIndex_] 01069 .params_[IterateTable::commandExecuteMacroParams_.OutputFileRadix_]; 01070 const std::string& inputArgs = 01071 iteratorStruct->commands_[iteratorStruct->commandIndex_] 01072 .params_[IterateTable::commandExecuteMacroParams_.MacroArgumentString_]; 01073 01074 __COUTV__(macroName); 01075 __COUTV__(enableSavingOutput); 01076 __COUTV__(outputFilePath); 01077 __COUTV__(outputFileRadix); 01078 __COUTV__(inputArgs); 01079 01080 // send request to MacroMaker a la FEVInterface::runFrontEndMacro 01081 // but need to pass iteration information, so that the call is launched by just one 01082 // send to each front end. Front-ends must immediately respond that is started 01083 // FEVInterfacesManager.. must start a thread for running the macro iterations 01084 // Then check for complete. 01085 01086 iteratorStruct->targetsDone_.clear(); // reset 01087 01088 __COUTV__(iteratorStruct->commands_[iteratorStruct->commandIndex_].targets_.size()); 01089 for(const auto& target : 01090 iteratorStruct->commands_[iteratorStruct->commandIndex_].targets_) 01091 { 01092 __COUT__ << "target " << target.table_ << ":" << target.UID_ << __E__; 01093 01094 // for each target, init to not done 01095 iteratorStruct->targetsDone_.push_back(false); 01096 01097 xoap::MessageReference message = 01098 SOAPUtilities::makeSOAPMessageReference("FECommunication"); 01099 01100 SOAPParameters parameters; 01101 std::string type = isFrontEndMacro ? "feMacroMultiDimensionalStart" 01102 : "macroMultiDimensionalStart"; 01103 parameters.addParameter("type", type); 01104 parameters.addParameter("requester", WebUsers::DEFAULT_ITERATOR_USERNAME); 01105 parameters.addParameter("targetInterfaceID", target.UID_); 01106 parameters.addParameter(isFrontEndMacro ? "feMacroName" : "macroName", macroName); 01107 parameters.addParameter("enableSavingOutput", enableSavingOutput); 01108 parameters.addParameter("outputFilePath", outputFilePath); 01109 parameters.addParameter("outputFileRadix", outputFileRadix); 01110 parameters.addParameter("inputArgs", inputArgs); 01111 SOAPUtilities::addParameters(message, parameters); 01112 01113 __COUT__ << "Sending FE communication: " << SOAPUtilities::translate(message) 01114 << __E__; 01115 01116 xoap::MessageReference replyMessage = 01117 iteratorStruct->theIterator_->theSupervisor_ 01118 ->SOAPMessenger::sendWithSOAPReply( 01119 iteratorStruct->theIterator_->theSupervisor_->allSupervisorInfo_ 01120 .getAllMacroMakerTypeSupervisorInfo() 01121 .begin() 01122 ->second.getDescriptor(), 01123 message); 01124 01125 __COUT__ << "Response received: " << SOAPUtilities::translate(replyMessage) 01126 << __E__; 01127 01128 SOAPParameters rxParameters; 01129 rxParameters.addParameter("Error"); 01130 std::string response = SOAPUtilities::receive(replyMessage, rxParameters); 01131 01132 std::string error = rxParameters.getValue("Error"); 01133 01134 if(response != type + "Done" || error != "") 01135 { 01136 // error occurred! 01137 __SS__ << "Error transmitting request to target interface '" << target.UID_ 01138 << "' from '" << WebUsers::DEFAULT_ITERATOR_USERNAME << ".' Response '" 01139 << response << "' with error: " << error << __E__; 01140 __SS_THROW__; 01141 } 01142 } // end target loop 01143 01144 } // end startCommandMacro() 01145 01146 //======================================================================================================================== 01147 bool Iterator::checkCommandMacro(IteratorWorkLoopStruct* iteratorStruct, 01148 bool isFrontEndMacro) 01149 { 01150 sleep(1); 01151 01152 // Steps: 01153 // 4 parameters CommandExecuteFEMacroParams: 01154 // //targets 01155 // const std::string FEMacroName_ = "FEMacroName"; 01156 // //macro parameters (table/groupID) 01157 01158 const std::string& macroName = 01159 iteratorStruct->commands_[iteratorStruct->commandIndex_] 01160 .params_[IterateTable::commandExecuteMacroParams_.MacroName_]; 01161 01162 __COUTV__(macroName); 01163 01164 // send request to MacroMaker to check completion of macro 01165 // as targets are identified complete, remove targets_ from vector 01166 01167 for(unsigned int i = 0; 01168 i < iteratorStruct->commands_[iteratorStruct->commandIndex_].targets_.size(); 01169 ++i) 01170 { 01171 ots::IterateTable::CommandTarget& target = 01172 iteratorStruct->commands_[iteratorStruct->commandIndex_].targets_[i]; 01173 01174 __COUT__ << "target " << target.table_ << ":" << target.UID_ << __E__; 01175 01176 xoap::MessageReference message = 01177 SOAPUtilities::makeSOAPMessageReference("FECommunication"); 01178 01179 SOAPParameters parameters; 01180 std::string type = isFrontEndMacro ? "feMacroMultiDimensionalCheck" 01181 : "macroMultiDimensionalCheck"; 01182 parameters.addParameter("type", type); 01183 parameters.addParameter("requester", WebUsers::DEFAULT_ITERATOR_USERNAME); 01184 parameters.addParameter("targetInterfaceID", target.UID_); 01185 parameters.addParameter(isFrontEndMacro ? "feMacroName" : "macroName", macroName); 01186 SOAPUtilities::addParameters(message, parameters); 01187 01188 __COUT__ << "Sending FE communication: " << SOAPUtilities::translate(message) 01189 << __E__; 01190 01191 xoap::MessageReference replyMessage = 01192 iteratorStruct->theIterator_->theSupervisor_ 01193 ->SOAPMessenger::sendWithSOAPReply( 01194 iteratorStruct->theIterator_->theSupervisor_->allSupervisorInfo_ 01195 .getAllMacroMakerTypeSupervisorInfo() 01196 .begin() 01197 ->second.getDescriptor(), 01198 message); 01199 01200 __COUT__ << "Response received: " << SOAPUtilities::translate(replyMessage) 01201 << __E__; 01202 01203 SOAPParameters rxParameters; 01204 rxParameters.addParameter("Error"); 01205 rxParameters.addParameter("Done"); 01206 std::string response = SOAPUtilities::receive(replyMessage, rxParameters); 01207 01208 std::string error = rxParameters.getValue("Error"); 01209 bool done = rxParameters.getValue("Done") == "1"; 01210 01211 if(response != type + "Done" || error != "") 01212 { 01213 // error occurred! 01214 __SS__ << "Error transmitting request to target interface '" << target.UID_ 01215 << "' from '" << WebUsers::DEFAULT_ITERATOR_USERNAME << ".' Response '" 01216 << response << "' with error: " << error << __E__; 01217 __SS_THROW__; 01218 } 01219 01220 if(!done) // still more to do so give up checking 01221 return false; 01222 01223 // mark target done 01224 iteratorStruct->targetsDone_[i] = true; 01225 01226 // iteratorStruct->commands_[iteratorStruct->commandIndex_].targets_.erase( 01227 // targetIt--); //go back after delete 01228 01229 } // end target loop 01230 01231 // if here all targets are done 01232 return true; 01233 } // end checkCommandMacro() 01234 01235 //======================================================================================================================== 01236 void Iterator::startCommandModifyActive(IteratorWorkLoopStruct* iteratorStruct) 01237 { 01238 // Steps: 01239 // 4 parameters commandModifyActiveParams_: 01240 // const std::string DoTrackGroupChanges_ TrueFalse 01241 // //targets 01242 // const std::string RelativePathToField_ = "RelativePathToField"; 01243 // const std::string FieldStartValue_ = "FieldStartValue"; 01244 // const std::string FieldIterationStepSize_ = "FieldIterationStepSize"; 01245 // 01246 // if tracking changes, 01247 // create a new group 01248 // for every enabled FE 01249 // set field = start value + stepSize * currentStepIndex_ 01250 // activate group 01251 // else 01252 // load scratch group 01253 // for every enabled FE 01254 // set field = start value + stepSize * stepIndex 01255 // activate group 01256 01257 bool doTrackGroupChanges = false; 01258 if("True" == 01259 iteratorStruct->commands_[iteratorStruct->commandIndex_] 01260 .params_[IterateTable::commandModifyActiveParams_.DoTrackGroupChanges_]) 01261 doTrackGroupChanges = true; 01262 01263 const std::string& startValueStr = 01264 iteratorStruct->commands_[iteratorStruct->commandIndex_] 01265 .params_[IterateTable::commandModifyActiveParams_.FieldStartValue_]; 01266 const std::string& stepSizeStr = 01267 iteratorStruct->commands_[iteratorStruct->commandIndex_] 01268 .params_[IterateTable::commandModifyActiveParams_.FieldIterationStepSize_]; 01269 01270 const unsigned int stepIndex = iteratorStruct->stepIndexStack_.back(); 01271 01272 __COUT__ << "doTrackGroupChanges " << (doTrackGroupChanges ? "yes" : "no") 01273 << std::endl; 01274 __COUT__ << "stepIndex " << stepIndex << std::endl; 01275 01276 ConfigurationInterface::setVersionTrackingEnabled(doTrackGroupChanges); 01277 01278 // two approaches: double or long handling 01279 01280 if(startValueStr.size() && (startValueStr[startValueStr.size() - 1] == 'f' || 01281 startValueStr.find('.') != std::string::npos)) 01282 { 01283 // handle as double 01284 double startValue = strtod(startValueStr.c_str(), 0); 01285 double stepSize = strtod(stepSizeStr.c_str(), 0); 01286 01287 __COUT__ << "startValue " << startValue << std::endl; 01288 __COUT__ << "stepSize " << stepSize << std::endl; 01289 __COUT__ << "currentValue " << startValue + stepSize * stepIndex << std::endl; 01290 01291 helpCommandModifyActive( 01292 iteratorStruct, startValue + stepSize * stepIndex, doTrackGroupChanges); 01293 } 01294 else // handle as long 01295 { 01296 long int startValue; 01297 long int stepSize; 01298 01299 StringMacros::getNumber(startValueStr, startValue); 01300 StringMacros::getNumber(startValueStr, stepSize); 01301 01302 // long int startValue; 01303 // 01304 // if(startValueStr.size() > 2 && startValueStr[1] == 'x') //assume hex value 01305 // startValue = strtol(startValueStr.c_str(),0,16); 01306 // else if(startValueStr.size() > 1 && startValueStr[0] == 'b') //assume 01307 // binary value startValue = 01308 // strtol(startValueStr.substr(1).c_str(),0,2); 01310 // strtol(startValueStr.c_str(),0,10); 01311 // 01312 // long int stepSize; 01313 // 01314 // if(stepSizeStr.size() > 2 && stepSizeStr[1] == 'x') //assume hex value 01315 // stepSize = strtol(stepSizeStr.c_str(),0,16); 01316 // else if(stepSizeStr.size() > 1 && stepSizeStr[0] == 'b') //assume binary 01317 // value stepSize = strtol(stepSizeStr.substr(1).c_str(),0,2); //skip 01318 // first 'b' character else stepSize = 01319 // strtol(stepSizeStr.c_str(),0,10); 01320 01321 __COUT__ << "startValue " << startValue << std::endl; 01322 __COUT__ << "stepSize " << stepSize << std::endl; 01323 __COUT__ << "currentValue " << startValue + stepSize * stepIndex << std::endl; 01324 01325 helpCommandModifyActive( 01326 iteratorStruct, startValue + stepSize * stepIndex, doTrackGroupChanges); 01327 } 01328 01329 } // end startCommandModifyActive() 01330 01331 //======================================================================================================================== 01332 // checkCommandRun 01333 // return true if done 01334 // 01335 // Either will be done on (priority 1) running threads (for Frontends) ending 01336 // or (priority 2 and ignored if <= 0) duration timeout 01337 // 01338 // Note: use command structure strings to maintain duration left 01339 // Note: watch iterator->doPauseAction and iterator->doHaltAction and respond 01340 bool Iterator::checkCommandRun(IteratorWorkLoopStruct* iteratorStruct) 01341 { 01342 sleep(1); // sleep to give FSM time to transition 01343 01344 // all RunControlStateMachine access commands should be mutually exclusive with 01345 // GatewaySupervisor main thread state machine accesses should be mutually exclusive 01346 // with GatewaySupervisor main thread state machine accesses lockout the messages 01347 // array for the remainder of the scope this guarantees the reading thread can safely 01348 // access the messages 01349 if(iteratorStruct->theIterator_->theSupervisor_->VERBOSE_MUTEX) 01350 __COUT__ << "Waiting for FSM access" << __E__; 01351 std::lock_guard<std::mutex> lock( 01352 iteratorStruct->theIterator_->theSupervisor_->stateMachineAccessMutex_); 01353 if(iteratorStruct->theIterator_->theSupervisor_->VERBOSE_MUTEX) 01354 __COUT__ << "Have FSM access" << __E__; 01355 01356 if(iteratorStruct->theIterator_->theSupervisor_->theStateMachine_.isInTransition()) 01357 return false; 01358 01359 iteratorStruct->fsmCommandParameters_.clear(); 01360 01361 std::string errorStr = ""; 01362 std::string currentState = iteratorStruct->theIterator_->theSupervisor_ 01363 ->theStateMachine_.getCurrentStateName(); 01364 01366 // check for imposed actions and forced exits 01367 if(iteratorStruct->doPauseAction_) 01368 { 01369 // transition to pause state 01370 __COUT__ << "Transitioning FSM to Paused..." << __E__; 01371 01372 if(currentState == "Paused") 01373 { 01374 // done with early pause exit! 01375 __COUT__ << "Transition to Paused complete." << __E__; 01376 return true; 01377 } 01378 else if(currentState == "Running") // launch transition to pause 01379 errorStr = iteratorStruct->theIterator_->theSupervisor_ 01380 ->attemptStateMachineTransition( 01381 0, 01382 0, 01383 "Pause", 01384 iteratorStruct->fsmName_, 01385 WebUsers::DEFAULT_ITERATOR_USERNAME /*fsmWindowName*/, 01386 WebUsers::DEFAULT_ITERATOR_USERNAME, 01387 iteratorStruct->fsmCommandParameters_); 01388 else if(currentState == "Configured") 01389 { 01390 // no need to pause state machine, no run going on 01391 __COUT__ << "In Configured state. No need to transition to Paused." << __E__; 01392 return true; 01393 } 01394 else 01395 errorStr = "Expected to be in Paused. Unexpectedly, the current state is " + 01396 currentState + 01397 ". Last State Machine error message was as follows: " + 01398 iteratorStruct->theIterator_->theSupervisor_->theStateMachine_ 01399 .getErrorMessage(); 01400 01401 if(errorStr != "") 01402 { 01403 __SS__ << "Iterator failed to pause because of the following error: " 01404 << errorStr; 01405 __SS_THROW__; 01406 } 01407 return false; 01408 } 01409 else if(iteratorStruct->doHaltAction_) 01410 { 01411 // transition to halted state 01412 __COUT__ << "Transitioning FSM to Halted..." << __E__; 01413 01414 if(currentState == "Halted") 01415 { 01416 // done with early halt exit! 01417 __COUT__ << "Transition to Halted complete." << __E__; 01418 return true; 01419 } 01420 else if(currentState == "Running" || // launch transition to halt 01421 currentState == "Paused") 01422 errorStr = iteratorStruct->theIterator_->theSupervisor_ 01423 ->attemptStateMachineTransition( 01424 0, 01425 0, 01426 "Abort", 01427 iteratorStruct->fsmName_, 01428 WebUsers::DEFAULT_ITERATOR_USERNAME /*fsmWindowName*/, 01429 WebUsers::DEFAULT_ITERATOR_USERNAME, 01430 iteratorStruct->fsmCommandParameters_); 01431 else if(currentState == "Configured") // launch transition to halt 01432 errorStr = iteratorStruct->theIterator_->theSupervisor_ 01433 ->attemptStateMachineTransition( 01434 0, 01435 0, 01436 "Halt", 01437 iteratorStruct->fsmName_, 01438 WebUsers::DEFAULT_ITERATOR_USERNAME /*fsmWindowName*/, 01439 WebUsers::DEFAULT_ITERATOR_USERNAME, 01440 iteratorStruct->fsmCommandParameters_); 01441 else 01442 errorStr = "Expected to be in Halted. Unexpectedly, the current state is " + 01443 currentState + 01444 ". Last State Machine error message was as follows: " + 01445 iteratorStruct->theIterator_->theSupervisor_->theStateMachine_ 01446 .getErrorMessage(); 01447 01448 if(errorStr != "") 01449 { 01450 __SS__ << "Iterator failed to halt because of the following error: " 01451 << errorStr; 01452 __SS_THROW__; 01453 } 01454 return false; 01455 } 01456 else if(iteratorStruct->doResumeAction_) 01457 { 01458 // Note: check command gets one shot to resume 01459 01460 // transition to running state 01461 __COUT__ << "Transitioning FSM to Running..." << __E__; 01462 01463 if(currentState == "Paused") // launch transition to running 01464 errorStr = iteratorStruct->theIterator_->theSupervisor_ 01465 ->attemptStateMachineTransition( 01466 0, 01467 0, 01468 "Resume", 01469 iteratorStruct->fsmName_, 01470 WebUsers::DEFAULT_ITERATOR_USERNAME /*fsmWindowName*/, 01471 WebUsers::DEFAULT_ITERATOR_USERNAME, 01472 iteratorStruct->fsmCommandParameters_); 01473 01474 if(errorStr != "") 01475 { 01476 __SS__ << "Iterator failed to run because of the following error: " 01477 << errorStr; 01478 __SS_THROW__; 01479 } 01480 return false; 01481 } 01482 01484 // normal running 01485 01486 if(currentState != "Running") 01487 { 01488 if(iteratorStruct->runIsDone_ && currentState == "Configured") 01489 { 01490 // indication of done 01491 __COUT__ << "Reached end of run " << iteratorStruct->fsmNextRunNumber_ 01492 << __E__; 01493 return true; 01494 } 01495 01496 errorStr = "Expected to be in Running. Unexpectedly, the current state is " + 01497 currentState + ". Last State Machine error message was as follows: " + 01498 iteratorStruct->theIterator_->theSupervisor_->theStateMachine_ 01499 .getErrorMessage(); 01500 } 01501 else // else in Running state! Check for end of run 01502 { 01503 bool waitOnRunningThreads = false; 01504 if("True" == iteratorStruct->commands_[iteratorStruct->commandIndex_] 01505 .params_[IterateTable::commandRunParams_.WaitOnRunningThreads_]) 01506 waitOnRunningThreads = true; 01507 01508 time_t remainingDurationInSeconds; // parameter converted during start to the 01509 // stop linux timestamp 01510 sscanf(iteratorStruct->commands_[iteratorStruct->commandIndex_] 01511 .params_[IterateTable::commandRunParams_.DurationInSeconds_] 01512 .c_str(), 01513 "%ld", 01514 &remainingDurationInSeconds); 01515 01516 __COUT__ << "waitOnRunningThreads " << waitOnRunningThreads << __E__; 01517 __COUT__ << "remainingDurationInSeconds " << remainingDurationInSeconds << __E__; 01518 01520 // priority 1 is waiting on running threads 01521 if(waitOnRunningThreads) 01522 { 01523 // get status of all running FE workloops 01524 GatewaySupervisor* theSupervisor = 01525 iteratorStruct->theIterator_->theSupervisor_; 01526 01527 bool allFrontEndsAreDone = true; 01528 for(auto& it : theSupervisor->allSupervisorInfo_.getAllFETypeSupervisorInfo()) 01529 { 01530 try 01531 { 01532 std::string status = theSupervisor->send(it.second.getDescriptor(), 01533 "WorkLoopStatusRequest"); 01534 01535 __COUT__ << "FESupervisor instance " << it.first 01536 << " has status = " << status << std::endl; 01537 01538 if(status != CoreSupervisorBase::WORK_LOOP_DONE) 01539 { 01540 allFrontEndsAreDone = false; 01541 break; 01542 } 01543 } 01544 catch(xdaq::exception::Exception& e) 01545 { 01546 __SS__ << "Could not retrieve status from FESupervisor instance " 01547 << it.first << "." << std::endl; 01548 __COUT_WARN__ << ss.str(); 01549 errorStr = ss.str(); 01550 01551 if(errorStr != "") 01552 { 01553 __SS__ 01554 << "Iterator failed to run because of the following error: " 01555 << errorStr; 01556 __SS_THROW__; 01557 } 01558 } 01559 } 01560 01561 if(allFrontEndsAreDone) 01562 { 01563 // need to end run! 01564 __COUT__ << "FE workloops all complete! Stopping run..." << __E__; 01565 01566 errorStr = iteratorStruct->theIterator_->theSupervisor_ 01567 ->attemptStateMachineTransition( 01568 0, 01569 0, 01570 "Stop", 01571 iteratorStruct->fsmName_, 01572 WebUsers::DEFAULT_ITERATOR_USERNAME /*fsmWindowName*/, 01573 WebUsers::DEFAULT_ITERATOR_USERNAME, 01574 iteratorStruct->fsmCommandParameters_); 01575 01576 if(errorStr != "") 01577 { 01578 __SS__ 01579 << "Iterator failed to stop run because of the following error: " 01580 << errorStr; 01581 __SS_THROW__; 01582 } 01583 01584 // write indication of run done into duration 01585 iteratorStruct->runIsDone_ = true; 01586 01587 return false; 01588 } 01589 } 01590 01592 // priority 2 is duration, if <= 0 it is ignored 01593 if(remainingDurationInSeconds > 1) 01594 { 01595 --remainingDurationInSeconds; 01596 01597 // write back to string 01598 char str[200]; 01599 sprintf(str, "%ld", remainingDurationInSeconds); 01600 iteratorStruct->commands_[iteratorStruct->commandIndex_] 01601 .params_[IterateTable::commandRunParams_.DurationInSeconds_] = 01602 str; // re-store as string 01603 } 01604 else if(remainingDurationInSeconds == 1) 01605 { 01606 // need to end run! 01607 __COUT__ << "Time duration reached! Stopping run..." << __E__; 01608 01609 errorStr = iteratorStruct->theIterator_->theSupervisor_ 01610 ->attemptStateMachineTransition( 01611 0, 01612 0, 01613 "Stop", 01614 iteratorStruct->fsmName_, 01615 WebUsers::DEFAULT_ITERATOR_USERNAME /*fsmWindowName*/, 01616 WebUsers::DEFAULT_ITERATOR_USERNAME, 01617 iteratorStruct->fsmCommandParameters_); 01618 01619 if(errorStr != "") 01620 { 01621 __SS__ << "Iterator failed to stop run because of the following error: " 01622 << errorStr; 01623 __SS_THROW__; 01624 } 01625 01626 // write indication of run done into duration 01627 iteratorStruct->runIsDone_ = true; 01628 01629 return false; 01630 } 01631 } 01632 01633 if(errorStr != "") 01634 { 01635 __SS__ << "Iterator failed to run because of the following error: " << errorStr; 01636 __SS_THROW__; 01637 } 01638 return false; 01639 } 01640 01641 //======================================================================================================================== 01642 // return true if done 01643 bool Iterator::checkCommandConfigure(IteratorWorkLoopStruct* iteratorStruct) 01644 { 01645 sleep(1); // sleep to give FSM time to transition 01646 01647 // all RunControlStateMachine access commands should be mutually exclusive with 01648 // GatewaySupervisor main thread state machine accesses should be mutually exclusive 01649 // with GatewaySupervisor main thread state machine accesses lockout the messages 01650 // array for the remainder of the scope this guarantees the reading thread can safely 01651 // access the messages 01652 if(iteratorStruct->theIterator_->theSupervisor_->VERBOSE_MUTEX) 01653 __COUT__ << "Waiting for FSM access" << __E__; 01654 std::lock_guard<std::mutex> lock( 01655 iteratorStruct->theIterator_->theSupervisor_->stateMachineAccessMutex_); 01656 if(iteratorStruct->theIterator_->theSupervisor_->VERBOSE_MUTEX) 01657 __COUT__ << "Have FSM access" << __E__; 01658 01659 if(iteratorStruct->theIterator_->theSupervisor_->theStateMachine_.isInTransition()) 01660 return false; 01661 01662 std::string errorStr = ""; 01663 std::string currentState = iteratorStruct->theIterator_->theSupervisor_ 01664 ->theStateMachine_.getCurrentStateName(); 01665 01666 if(currentState == "Halted") 01667 errorStr = 01668 iteratorStruct->theIterator_->theSupervisor_->attemptStateMachineTransition( 01669 0, 01670 0, 01671 "Configure", 01672 iteratorStruct->fsmName_, 01673 WebUsers::DEFAULT_ITERATOR_USERNAME /*fsmWindowName*/, 01674 WebUsers::DEFAULT_ITERATOR_USERNAME, 01675 iteratorStruct->fsmCommandParameters_); 01676 else if(currentState != "Configured") 01677 errorStr = "Expected to be in Configure. Unexpectedly, the current state is " + 01678 currentState + "." + 01679 ". Last State Machine error message was as follows: " + 01680 iteratorStruct->theIterator_->theSupervisor_->theStateMachine_ 01681 .getErrorMessage(); 01682 else // else successfully done (in Configured state!) 01683 { 01684 __COUT__ << "checkCommandConfigureAlias complete." << __E__; 01685 01686 // also activate the Iterator config manager to mimic active config 01687 std::pair<std::string, TableGroupKey> newActiveGroup = 01688 iteratorStruct->cfgMgr_->getTableGroupFromAlias( 01689 iteratorStruct->fsmCommandParameters_[0]); 01690 iteratorStruct->cfgMgr_->loadTableGroup( 01691 newActiveGroup.first, newActiveGroup.second, true /*activate*/); 01692 01693 __COUT__ << "originalTrackChanges " << iteratorStruct->originalTrackChanges_ 01694 << __E__; 01695 __COUT__ << "originalConfigGroup " << iteratorStruct->originalConfigGroup_ 01696 << __E__; 01697 __COUT__ << "originalConfigKey " << iteratorStruct->originalConfigKey_ << __E__; 01698 01699 __COUT__ << "currentTrackChanges " 01700 << ConfigurationInterface::isVersionTrackingEnabled() << __E__; 01701 __COUT__ << "originalConfigGroup " 01702 << iteratorStruct->cfgMgr_->getActiveGroupName() << __E__; 01703 __COUT__ << "originalConfigKey " << iteratorStruct->cfgMgr_->getActiveGroupKey() 01704 << __E__; 01705 01706 return true; 01707 } 01708 01709 if(errorStr != "") 01710 { 01711 __SS__ << "Iterator failed to configure with system alias '" 01712 << (iteratorStruct->fsmCommandParameters_.size() 01713 ? iteratorStruct->fsmCommandParameters_[0] 01714 : "UNKNOWN") 01715 << "' because of the following error: " << errorStr; 01716 __SS_THROW__; 01717 } 01718 return false; 01719 } 01720 01721 //======================================================================================================================== 01722 bool Iterator::handleCommandRequest(HttpXmlDocument& xmldoc, 01723 const std::string& command, 01724 const std::string& parameter) 01725 { 01726 __COUTV__(command); 01727 if(command == "iteratePlay") 01728 { 01729 playIterationPlan(xmldoc, parameter); 01730 return true; 01731 } 01732 else if(command == "iteratePause") 01733 { 01734 pauseIterationPlan(xmldoc); 01735 return true; 01736 } 01737 else if(command == "iterateHalt") 01738 { 01739 haltIterationPlan(xmldoc); 01740 return true; 01741 } 01742 else if(command == "getIterationPlanStatus") 01743 { 01744 getIterationPlanStatus(xmldoc); 01745 return true; 01746 } 01747 else // return true if iterator has control of state machine 01748 { 01749 // lockout the messages array for the remainder of the scope 01750 // this guarantees the reading thread can safely access the messages 01751 if(theSupervisor_->VERBOSE_MUTEX) 01752 __COUT__ << "Waiting for iterator access" << __E__; 01753 std::lock_guard<std::mutex> lock(accessMutex_); 01754 if(theSupervisor_->VERBOSE_MUTEX) 01755 __COUT__ << "Have iterator access" << __E__; 01756 01757 if(iteratorBusy_) 01758 { 01759 __SS__ << "Error - Can not accept request because the Iterator " 01760 << "is currently " 01761 << "in control of State Machine progress. "; 01762 __COUT_ERR__ << "\n" << ss.str(); 01763 __MOUT_ERR__ << "\n" << ss.str(); 01764 01765 xmldoc.addTextElementToData("state_tranisition_attempted", 01766 "0"); // indicate to GUI transition NOT attempted 01767 xmldoc.addTextElementToData( 01768 "state_tranisition_attempted_err", 01769 ss.str()); // indicate to GUI transition NOT attempted 01770 01771 return true; // to block other commands 01772 } 01773 } 01774 return false; 01775 } 01776 01777 //======================================================================================================================== 01778 void Iterator::playIterationPlan(HttpXmlDocument& xmldoc, const std::string& planName) 01779 { 01780 __MOUT__ << "Attempting to play iteration plan '" << planName << ".'" << __E__; 01781 __COUT__ << "Attempting to play iteration plan '" << planName << ".'" << __E__; 01782 01783 // setup "play" command 01784 01785 // lockout the messages array for the remainder of the scope 01786 // this guarantees the reading thread can safely access the messages 01787 if(theSupervisor_->VERBOSE_MUTEX) 01788 __COUT__ << "Waiting for iterator access" << __E__; 01789 std::lock_guard<std::mutex> lock(accessMutex_); 01790 if(theSupervisor_->VERBOSE_MUTEX) 01791 __COUT__ << "Have iterator access" << __E__; 01792 01793 if(!activePlanIsRunning_ && !commandPlay_) 01794 { 01795 if(!workloopRunning_) 01796 { 01797 // start thread with member variables initialized 01798 01799 workloopRunning_ = true; 01800 01801 // must start thread first 01802 std::thread([](Iterator* iterator) { Iterator::IteratorWorkLoop(iterator); }, 01803 this) 01804 .detach(); 01805 } 01806 01807 activePlanName_ = planName; 01808 commandPlay_ = true; 01809 } 01810 else 01811 { 01812 __SS__ << "Invalid play command attempted. Can only play when the Iterator is " 01813 "inactive or paused." 01814 << " If you would like to restart an iteration plan, first try halting." 01815 << __E__; 01816 __MOUT__ << ss.str(); 01817 01818 xmldoc.addTextElementToData("error_message", ss.str()); 01819 01820 __COUT__ << "Invalid play command attempted. " << commandPlay_ << " " 01821 << activePlanName_ << __E__; 01822 } 01823 } 01824 01825 //======================================================================================================================== 01826 void Iterator::pauseIterationPlan(HttpXmlDocument& xmldoc) 01827 { 01828 __MOUT__ << "Attempting to pause iteration plan '" << activePlanName_ << ".'" 01829 << __E__; 01830 __COUT__ << "Attempting to pause iteration plan '" << activePlanName_ << ".'" 01831 << __E__; 01832 01833 // setup "pause" command 01834 01835 // lockout the messages array for the remainder of the scope 01836 // this guarantees the reading thread can safely access the messages 01837 if(theSupervisor_->VERBOSE_MUTEX) 01838 __COUT__ << "Waiting for iterator access" << __E__; 01839 std::lock_guard<std::mutex> lock(accessMutex_); 01840 if(theSupervisor_->VERBOSE_MUTEX) 01841 __COUT__ << "Have iterator access" << __E__; 01842 01843 if(workloopRunning_ && activePlanIsRunning_ && !commandPause_) 01844 { 01845 commandPause_ = true; 01846 } 01847 else 01848 { 01849 __SS__ << "Invalid pause command attempted. Can only pause when running." 01850 << __E__; 01851 __MOUT__ << ss.str(); 01852 01853 xmldoc.addTextElementToData("error_message", ss.str()); 01854 01855 __COUT__ << "Invalid pause command attempted. " << workloopRunning_ << " " 01856 << activePlanIsRunning_ << " " << commandPause_ << " " << activePlanName_ 01857 << __E__; 01858 } 01859 } 01860 01861 //======================================================================================================================== 01862 void Iterator::haltIterationPlan(HttpXmlDocument& xmldoc) 01863 { 01864 __MOUT__ << "Attempting to halt iteration plan '" << activePlanName_ << ".'" << __E__; 01865 __COUT__ << "Attempting to halt iteration plan '" << activePlanName_ << ".'" << __E__; 01866 01867 // setup "halt" command 01868 01869 if(workloopRunning_) 01870 { 01871 // lockout the messages array for the remainder of the scope 01872 // this guarantees the reading thread can safely access the messages 01873 if(theSupervisor_->VERBOSE_MUTEX) 01874 __COUT__ << "Waiting for iterator access" << __E__; 01875 std::lock_guard<std::mutex> lock(accessMutex_); 01876 if(theSupervisor_->VERBOSE_MUTEX) 01877 __COUT__ << "Have iterator access" << __E__; 01878 01879 __COUT__ << "activePlanIsRunning_: " << activePlanIsRunning_ << __E__; 01880 __COUT__ << "Passing halt command to iterator thread." << __E__; 01881 commandHalt_ = true; 01882 01883 // clear 01884 activePlanName_ = ""; 01885 activeCommandIndex_ = -1; 01886 } 01887 else // no thread, so halt (and reset Error') without command to thread 01888 { 01889 __COUT__ << "No thread, so conducting halt." << __E__; 01890 Iterator::haltIterator(this); 01891 // 01892 // activePlanIsRunning_ = false; 01893 // iteratorBusy_ = false; 01894 // 01895 // bool haltAttempted = false; 01896 // try 01897 // { 01898 // haltAttempted = Iterator::haltIterator(theSupervisor_, lastFsmName_); 01899 // } 01900 // catch(const std::runtime_error& e) 01901 // { 01902 // haltAttempted = false; 01903 // __COUT__ << "Halt error: " << e.what() << __E__; 01904 // } 01905 // 01906 // if(!haltAttempted) //then show error 01907 // { 01908 // __SS__ << "Invalid halt command attempted. Can only halt when there is 01909 // an active iteration plan." << __E__; 01910 // __MOUT_ERR__ << ss.str(); 01911 // 01912 // xmldoc.addTextElementToData("error_message", ss.str()); 01913 // 01914 // __COUT__ << "Invalid halt command attempted. " << 01915 // workloopRunning_ << " " << 01916 // activePlanIsRunning_ << " " << 01917 // commandHalt_ << " " << 01918 // activePlanName_ << __E__; 01919 // } 01920 // else 01921 // __COUT__ << "Halt was attempted." << __E__; 01922 } 01923 } 01924 01925 //======================================================================================================================== 01926 // return state machine and iterator status 01927 void Iterator::getIterationPlanStatus(HttpXmlDocument& xmldoc) 01928 { 01929 xmldoc.addTextElementToData( 01930 "current_state", 01931 theSupervisor_->theStateMachine_.isInTransition() 01932 ? theSupervisor_->theStateMachine_.getCurrentTransitionName( 01933 theSupervisor_->stateMachineLastCommandInput_) 01934 : theSupervisor_->theStateMachine_.getCurrentStateName()); 01935 01936 // xmldoc.addTextElementToData("in_transition", 01937 // theSupervisor_->theStateMachine_.isInTransition() ? "1" : "0"); 01938 if(theSupervisor_->theStateMachine_.isInTransition()) 01939 xmldoc.addTextElementToData( 01940 "transition_progress", 01941 theSupervisor_->theProgressBar_.readPercentageString()); 01942 else 01943 xmldoc.addTextElementToData("transition_progress", "100"); 01944 01945 char tmp[20]; 01946 sprintf(tmp, "%lu", theSupervisor_->theStateMachine_.getTimeInState()); 01947 xmldoc.addTextElementToData("time_in_state", tmp); 01948 01949 // lockout the messages array for the remainder of the scope 01950 // this guarantees the reading thread can safely access the messages 01951 if(theSupervisor_->VERBOSE_MUTEX) 01952 __COUT__ << "Waiting for iterator access" << __E__; 01953 std::lock_guard<std::mutex> lock(accessMutex_); 01954 if(theSupervisor_->VERBOSE_MUTEX) 01955 __COUT__ << "Have iterator access" << __E__; 01956 01957 xmldoc.addTextElementToData("active_plan", activePlanName_); 01958 xmldoc.addTextElementToData("last_started_plan", lastStartedPlanName_); 01959 xmldoc.addTextElementToData("last_finished_plan", lastFinishedPlanName_); 01960 01961 sprintf(tmp, "%u", activeCommandIndex_); 01962 xmldoc.addTextElementToData("current_command_index", tmp); 01963 sprintf(tmp, "%ld", time(0) - activeCommandStartTime_); 01964 xmldoc.addTextElementToData("current_command_duration", tmp); 01965 sprintf(tmp, "%u", activeCommandIteration_); 01966 xmldoc.addTextElementToData("current_command_iteration", tmp); 01967 01968 for(const auto& depthIteration : depthIterationStack_) 01969 { 01970 sprintf(tmp, "%u", depthIteration); 01971 xmldoc.addTextElementToData("depth_iteration", tmp); 01972 } 01973 01974 if(activePlanIsRunning_ && iteratorBusy_) 01975 { 01976 if(workloopRunning_) 01977 xmldoc.addTextElementToData("active_plan_status", "Running"); 01978 else 01979 xmldoc.addTextElementToData("active_plan_status", "Error"); 01980 } 01981 else if(!activePlanIsRunning_ && iteratorBusy_) 01982 xmldoc.addTextElementToData("active_plan_status", "Paused"); 01983 else 01984 xmldoc.addTextElementToData("active_plan_status", "Inactive"); 01985 01986 xmldoc.addTextElementToData("error_message", errorMessage_); 01987 }