diff --git a/MAC/APL/APLCommon/include/APL/APLCommon/ParentControl.h b/MAC/APL/APLCommon/include/APL/APLCommon/ParentControl.h index 8ccc9271467144865db2b8c5a3a83ca61f04cdf7..740c2ce6c26c35e921b6f655f9fd600c766ffca0 100644 --- a/MAC/APL/APLCommon/include/APL/APLCommon/ParentControl.h +++ b/MAC/APL/APLCommon/include/APL/APLCommon/ParentControl.h @@ -141,6 +141,8 @@ private: GCFTimerPort itsTimerPort; // for internal timers + uint32 itsFirstConnectTimerID; // ID of timer used to guard the first connect + string itsServiceName; // serviceinfo of program uint32 itsInstanceNr; diff --git a/MAC/APL/APLCommon/src/ChildControl.cc b/MAC/APL/APLCommon/src/ChildControl.cc index 86d3bbbc8d025788302cf6ec6b6264570f8a3b80..450ae3bfbe431ecea64c10aac82ae50a1dfbd730 100644 --- a/MAC/APL/APLCommon/src/ChildControl.cc +++ b/MAC/APL/APLCommon/src/ChildControl.cc @@ -358,6 +358,11 @@ bool ChildControl::requestState (CTState::CTstateNr aState, iter->result = CT_RESULT_NO_ERROR; iter->nrRetries = 0; iter->retryTime = 0; + // when quit is requested and there is still no connection, clear action list first + if (aState >= CTState::QUIT && !iter->port) { + _removeAction(iter->cntlrName, CTState::ANYSTATE); + iter->port = (GCFPortInterface*) -1; + } itsActionList.push_back(*iter); } @@ -657,21 +662,21 @@ void ChildControl::_processActionList() continue; } - // is there a connection with this controller? - if (action->requestedState > CTState::CONNECTED && !controller->port) { - LOG_DEBUG_STR("parking:" << action->cntlrName << "->" << - cts.name(action->requestedState) << " until connection is made"); - itsActionList.push_back(*action); // add at back + // did the connection with this controller failed? + if (controller->port == (GCFPortInterface*)-1) { + LOG_DEBUG_STR("ActionList:removing " << action->cntlrName << "->" << + cts.name(action->requestedState) << " because connection failed"); action++; // hop to next itsActionList.pop_front(); // remove at front. nrActions--; // one less to handle. continue; } - // did the connection with this controller failed? - if (controller->port == (GCFPortInterface*)-1) { - LOG_DEBUG_STR("ActionList:removing " << action->cntlrName << "->" << - cts.name(action->requestedState) << " because connection failed"); + // is there a connection with this controller? + if (action->requestedState > CTState::CONNECTED && !controller->port) { + LOG_DEBUG_STR("parking:" << action->cntlrName << "->" << + cts.name(action->requestedState) << " until connection is made"); + itsActionList.push_back(*action); // add at back action++; // hop to next itsActionList.pop_front(); // remove at front. nrActions--; // one less to handle. @@ -834,7 +839,7 @@ void ChildControl::_removeAction (const string& aName, const_CIiter end = itsActionList.end(); while (iter != end) { - if (iter->cntlrName == aName && iter->requestedState == requestedState) { + if (iter->cntlrName == aName && (iter->requestedState == requestedState || requestedState == CTState::ANYSTATE)) { itsActionList.erase(iter); return; } diff --git a/MAC/APL/APLCommon/src/ParentControl.cc b/MAC/APL/APLCommon/src/ParentControl.cc index 686c37b3a7c131a572f37023056eec9061b0761d..a505a78092c1f0d71f6a90811b1aeaf5ba8e80fa 100644 --- a/MAC/APL/APLCommon/src/ParentControl.cc +++ b/MAC/APL/APLCommon/src/ParentControl.cc @@ -100,12 +100,13 @@ ParentControl* ParentControl::instance() // ParentControl(name, parenthost, parentService)) // ParentControl::ParentControl() : - GCFTask ((State)&ParentControl::initial, "ParentControl"), - itsParentList (), - itsSDPort (0), - itsMainTaskPort (0), - itsTimerPort (*this, "parentControlTimer"), - itsControllerName() + GCFTask ((State)&ParentControl::initial, "ParentControl"), + itsParentList (), + itsSDPort (0), + itsMainTaskPort (0), + itsTimerPort (*this, "parentControlTimer"), + itsFirstConnectTimerID(0), + itsControllerName () { // Log the protocols I use. registerProtocol(CONTROLLER_PROTOCOL, CONTROLLER_PROTOCOL_STRINGS); @@ -322,6 +323,13 @@ CTState::CTstateNr ParentControl::getNextState(PIiter parent) return (parent->requestedState); } + // make sure there is no way back once we are shutting down. + if (parent->currentState >= CTState::QUIT) { + CTState cts; + LOG_INFO_STR("Ignoring state-change to " << cts.name(parent->requestedState) << " because we are in Quit-state already"); + return (CTState::QUITED); + } + // look if signal is inband uint32 i = 0; while (stateFlowTable[i].signal) { @@ -550,7 +558,6 @@ GCFEvent::TResult ParentControl::initial(GCFEvent& event, switch (event.signal) { case F_INIT: case F_ENTRY: - case F_EXIT: break; case F_CONNECTED: @@ -581,6 +588,11 @@ GCFEvent::TResult ParentControl::initial(GCFEvent& event, itsSDPort->open(); break; + case F_EXIT: + // CTStartDaemon should send response within a reasonable time. + itsFirstConnectTimerID = itsTimerPort.setTimer(10.0); + break; + default: LOG_WARN_STR ("initial: " << eventName(event) << "@" << port.getName() << " not handled"); status = GCFEvent::NOT_HANDLED; @@ -699,6 +711,13 @@ GCFEvent::TResult ParentControl::operational(GCFEvent& event, uint32 timerType; GCFTimerEvent& timerEvent = static_cast<GCFTimerEvent&>(event); LOG_TRACE_VAR_STR("timerID:" << timerEvent.id); + if (timerEvent.id == itsFirstConnectTimerID) { + LOG_FATAL("CTStartdeamon did not send startup info in time, aborting program!"); + // No connection have been made to parents yet because we are starting up. Just quit program. + GCFScheduler::instance()->stop(); + break; + } + PIiter parent = findParentOnTimerID(timerEvent.id, &timerType); if (!isParent(parent)) { LOG_WARN ("Timerevent is not of a known parent, ignore"); @@ -710,7 +729,7 @@ GCFEvent::TResult ParentControl::operational(GCFEvent& event, case TT_STATE_TIMER: break; case TT_STOP_TIMER: - nowInState(parent->name, CTState::RELEASED); // force to QUIT state, disable oob mechanism + nowInState(parent->name, CTState::QUIT); // force to QUIT state, disable oob mechanism parent->stopTimer = 0; _doRequestedAction(parent); return (GCFEvent::HANDLED); @@ -751,6 +770,10 @@ GCFEvent::TResult ParentControl::operational(GCFEvent& event, break; case STARTDAEMON_NEWPARENT: { + // stop timer if it still running. + itsTimerPort.cancelTimer(itsFirstConnectTimerID); + itsFirstConnectTimerID = 0; + // a new parent wants us to connect to it, STARTDAEMONNewparentEvent NPevent(event); diff --git a/MAC/APL/MainCU/src/ObservationControl/ObservationControl.cc b/MAC/APL/MainCU/src/ObservationControl/ObservationControl.cc index 8ae558096cb357358475ccac949d12399facfeaf..d422e12412760d9cef7cc0e545d29ba91dad69c1 100644 --- a/MAC/APL/MainCU/src/ObservationControl/ObservationControl.cc +++ b/MAC/APL/MainCU/src/ObservationControl/ObservationControl.cc @@ -730,9 +730,10 @@ void ObservationControl::doHeartBeatTask() // check if enough stations are left too do our job. // TODO: add criteria to SAS database and test those iso this foolish criteria. if (nrChilds != itsNrControllers) { - LOG_WARN_STR("Only " << nrChilds << " out of " << itsNrControllers << " stations still available."); + LOG_WARN_STR("Only " << nrChilds << " out of " << itsNrControllers << " controllers still available."); // if no more children left while we are not in the quit-phase (stoptimer still running) - if (!nrChilds && itsStopTimer) { + if (itsStopTimer && itsChildControl->countChilds(0, CNTLRTYPE_STATIONCTRL)==0) { +// if (!nrChilds && itsStopTimer) { LOG_FATAL("Too less stations left, FORCING QUIT OF OBSERVATION"); if (itsState < CTState::RESUME) { itsQuitReason = CT_RESULT_LOST_CONNECTION; diff --git a/MAC/APL/StationCU/src/BeamControl/BeamControl.cc b/MAC/APL/StationCU/src/BeamControl/BeamControl.cc index bf717ea34f20303e6829cc230c8d480ac0c4dfac..6ca4a0549e3dadb2880c40f41457f6f1aec0cfa3 100644 --- a/MAC/APL/StationCU/src/BeamControl/BeamControl.cc +++ b/MAC/APL/StationCU/src/BeamControl/BeamControl.cc @@ -909,12 +909,15 @@ GCFEvent::TResult BeamControl::_defaultEventHandler(GCFEvent& event, case CONTROL_RESUME: case CONTROL_SUSPEND: case CONTROL_RELEASE: - case CONTROL_QUIT: if (sendControlResult(port, event.signal, getName(), CT_RESULT_NO_ERROR)) { result = GCFEvent::HANDLED; } break; + case CONTROL_QUIT: + TRAN(BeamControl::quiting_state); + break; + break; case CONTROL_CONNECTED: case CONTROL_RESYNCED: case CONTROL_SCHEDULED: diff --git a/MAC/APL/StationCU/src/StationControl/StationControl.cc b/MAC/APL/StationCU/src/StationControl/StationControl.cc index a07102a2aa817600684ef1b664a0d5afceae1964..efe9867457efad470082d502103bfb562495b475 100644 --- a/MAC/APL/StationCU/src/StationControl/StationControl.cc +++ b/MAC/APL/StationCU/src/StationControl/StationControl.cc @@ -644,27 +644,6 @@ GCFEvent::TResult StationControl::operational_state(GCFEvent& event, GCFPortInte // return (GCFEvent::NEXT_STATE); } - // TODO: CLEAN UP THE CODE BELOW - -#if 0 - // before passing a new state request from the ObsController to the - // activeObs, make sure the last state is reached. -LOG_DEBUG_STR(formatString("event.signal = %04X", event.signal)); -LOG_DEBUG_STR("F_INDIR = " << F_INDIR(event.signal)); -LOG_DEBUG_STR("F_OUTDIR = " << F_OUTDIR(event.signal)); -LOG_DEBUG_STR("inSync = " << (theObs->second->inSync() ? "true" : "false")); - if (F_OUTDIR(event.signal) && !theObs->second->inSync()) { - // TODO - CTState cts; - LOG_FATAL_STR("Ignoring change to state " << cts.name(cts.signal2stateNr(event.signal)) << - " for observation " << treeID << " because obs is still in state " << - cts.name(theObs->second->curState())); - sendControlResult(*itsParentPort, event.signal, cntlrName, - CT_RESULT_OUT_OF_SYNC); - break; - - } -#endif // pass event to observation FSM LOG_TRACE_FLOW("Dispatch to observation FSM's"); theObs->second->doEvent(event, port); @@ -701,6 +680,10 @@ LOG_TRACE_FLOW_STR("There are " << cntlrStates.size() << " busy controllers"); " failed with error " << cntlrStates[i].result); sendControlResult(*itsParentPort, event.signal, cntlrName, cntlrStates[i].result); + LOG_ERROR_STR("Initiating QUIT sequence for observation " << theObs->second->getName()); + CONTROLQuitEvent quitevent; + quitevent.cntlrName = theObs->second->getName(); + theObs->second->doEvent(quitevent, port); break; } LOG_TRACE_COND_STR ("Still waiting for " << cntlrStates[i].name);