diff --git a/.gitattributes b/.gitattributes index bfaca3230869cf58e7204e39874c2cadb779c823..9d7a5d66a8a149f07987fd49ffc5917b217b421e 100644 --- a/.gitattributes +++ b/.gitattributes @@ -2421,6 +2421,8 @@ MAC/APL/CEPCU/src/CEPlogProcessor/CEPDatapoints.dpl -text MAC/APL/CEPCU/src/CEPlogProcessor/CEPDatapointtypes.dpl -text MAC/APL/CEPCU/src/CEPlogProcessor/CircularBuffer.h -text MAC/APL/CEPCU/src/CEPlogProcessor/rtlogsender.py -text +MAC/APL/CEPCU/src/OnlineControl/forkexec.cc -text +MAC/APL/CEPCU/src/OnlineControl/forkexec.h -text MAC/APL/CEPCU/src/OnlineControl/tPVSSMapping.cc -text MAC/APL/CEPCU/src/PythonControl/PythonControl.conf -text MAC/APL/CEPCU/src/PythonControl/tMDparser.cc -text diff --git a/CMake/variants/variants.RS005C b/CMake/variants/variants.RS005C index 2fb3ca3b231ba6d8a6861d380307be03647505e1..667ce2d8e6dcce26bb6d8034a864dc078a4fd2c3 100644 --- a/CMake/variants/variants.RS005C +++ b/CMake/variants/variants.RS005C @@ -1,5 +1,6 @@ # Preset rs002 specific options option(USE_BACKTRACE "Use backtrace" OFF) +option(BUILD_SHARED_LIBS "Build shared libraries" OFF) # Path to Postgres C API set(PQ_ROOT_DIR /usr/local/pgsql) diff --git a/MAC/APL/CEPCU/CMakeLists.txt b/MAC/APL/CEPCU/CMakeLists.txt index 01fca5d2dcc6e3833b1a88f8119f361a52de7dfc..2d8bc3474a045b8af49b61220f85cbb7e6315da4 100644 --- a/MAC/APL/CEPCU/CMakeLists.txt +++ b/MAC/APL/CEPCU/CMakeLists.txt @@ -1,7 +1,7 @@ # $Id$ # Do not split the following line, otherwise makeversion will fail! -lofar_package(CEPCU 1.0 DEPENDS Common ALC PLC ApplCommon MACIO GCFTM GCFRTDB APLCommon RTDBCommon OTDB) +lofar_package(CEPCU 1.0 DEPENDS Common ApplCommon MACIO GCFTM GCFRTDB APLCommon RTDBCommon OTDB) include(LofarFindPackage) lofar_find_package(Boost REQUIRED COMPONENTS date_time) diff --git a/MAC/APL/CEPCU/src/OnlineControl/CEPApplMgr.cc b/MAC/APL/CEPCU/src/OnlineControl/CEPApplMgr.cc deleted file mode 100644 index f2b50def6608296b7766d3cf48fb7f3a66ef8354..0000000000000000000000000000000000000000 --- a/MAC/APL/CEPCU/src/OnlineControl/CEPApplMgr.cc +++ /dev/null @@ -1,198 +0,0 @@ -//# CEPApplMgr.cc: Implementation of the Virtual CEPApplMgr task -//# -//# Copyright (C) 2002-2004 -//# ASTRON (Netherlands Foundation for Research in Astronomy) -//# P.O.Box 2, 7990 AA Dwingeloo, The Netherlands, seg@astron.nl -//# -//# This program is free software; you can redistribute it and/or modify -//# it under the terms of the GNU General Public License as published by -//# the Free Software Foundation; either version 2 of the License, or -//# (at your option) any later version. -//# -//# This program is distributed in the hope that it will be useful, -//# but WITHOUT ANY WARRANTY; without even the implied warranty of -//# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -//# GNU General Public License for more details. -//# -//# You should have received a copy of the GNU General Public License -//# along with this program; if not, write to the Free Software -//# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -//# -//# $Id$ - -#include <lofar_config.h> -#include <Common/StringUtil.h> -#include <APL/APLCommon/Controller_Protocol.ph> -#include <GCF/TM/GCF_Scheduler.h> -#include "CEPApplMgr.h" - -namespace LOFAR { - using namespace GCF::TM; - using namespace ACC::ALC; - using namespace APLCommon; - namespace CEPCU { - - -// -// CEPApplMgr(interface, appl) -// -CEPApplMgr::CEPApplMgr(CEPApplMgrInterface& interface, - const string& appName, - uint32 expRuntime, - const string& acdHost, - const string& paramFile) : - itsProcName (appName), - itsParamFile (paramFile), - itsCAMInterface(interface), - // (nrProcs, expectedlifetime,activityLevel,architecture); - itsACclient (this, appName, 10, expRuntime, 1, 0, acdHost), - itsReqState (CTState::NOSTATE), - itsCurState (CTState::NOSTATE), - itsContinuePoll(true) -{ - use(); // to avoid that this object will be deleted in GCFTask::stop; -} - -// -// ~CEPApplMgr() -// -CEPApplMgr::~CEPApplMgr() -{ - GCFScheduler::instance()->deregisterHandler(*this); -} - -// -// workProc() -// -void CEPApplMgr::workProc() -{ - if (itsContinuePoll) { - itsACclient.processACmsgFromServer(); - } -} - -// -// handleAckMsg(cmd, result, info) -// -// Translate ACC ack into MAC state. -// -void CEPApplMgr::handleAckMsg(ACCmd cmd, - uint16 ACCresult, - const string& info) -{ - LOG_INFO(formatString("command: %d, result: %d, info: %s", cmd, ACCresult, info.c_str())); - - uint16 MACresult = (ACCresult & AcCmdMaskOk) ? - CT_RESULT_NO_ERROR : CT_RESULT_UNSPECIFIED; - - switch (cmd) { - case ACCmdBoot: - if (ACCresult == AcCmdMaskOk) { - itsCurState = CTState::CONNECTED; - } - itsCAMInterface.appSetStateResult(itsProcName, CTState::CONNECT, MACresult); - break; - - case ACCmdDefine: - if (ACCresult == AcCmdMaskOk) { - itsCurState = CTState::CLAIMED; - } - itsCAMInterface.appSetStateResult(itsProcName, CTState::CLAIM, MACresult); - break; - - case ACCmdInit: - if (ACCresult == AcCmdMaskOk) { - itsCurState = CTState::PREPARED; - } - itsCAMInterface.appSetStateResult(itsProcName, CTState::PREPARE, MACresult); - break; - - case ACCmdRun: - if (ACCresult == AcCmdMaskOk) { - itsCurState = CTState::RESUMED; - } - itsCAMInterface.appSetStateResult(itsProcName, CTState::RESUME, MACresult); - break; - - case ACCmdPause: - if (ACCresult == AcCmdMaskOk) { - itsCurState = CTState::SUSPENDED; - } - itsCAMInterface.appSetStateResult(itsProcName, CTState::SUSPEND, MACresult); - break; - - case ACCmdRelease: - if (ACCresult == AcCmdMaskOk) { - itsCurState = CTState::RELEASED; - } - itsCAMInterface.appSetStateResult(itsProcName, CTState::RELEASE, MACresult); - break; - - case ACCmdQuit: - if (ACCresult == AcCmdMaskOk) { -// itsContinuePoll = false; - itsCurState = CTState::QUITED; - } - itsCAMInterface.appSetStateResult(itsProcName, CTState::QUIT, MACresult); - break; - - default: - LOG_WARN_STR("Received command = " << cmd << ", result = " << ACCresult - << ", info = " << info << " not handled!"); - break; - } -} - -// -// sendCommand (newState, options) -// -// Translate MAC commands into ACC commands. -// -void CEPApplMgr::sendCommand (CTState::CTstateNr newState, const string& options) -{ - switch (newState) { - case CTState::CONNECT: - itsACclient.boot(0, itsParamFile); - break; - case CTState::CLAIM: - itsACclient.define(0); - break; - case CTState::PREPARE: - itsACclient.init(0); - break; - case CTState::RESUME: - itsACclient.run(0); - break; - case CTState::SUSPEND: - itsACclient.pause(0, 0, options); - break; - case CTState::RELEASE: - itsACclient.release(0); - break; - case CTState::QUIT: - itsACclient.quit(0); - break; - default: - break; - } -} - - -// -// handleAnswerMsg(answer) -// -void CEPApplMgr::handleAnswerMsg (const string& answer) -{ - itsCAMInterface.appSupplyInfoAnswer(itsProcName, answer); -} - -// -// supplyInfoFunc(keyList) -// -string CEPApplMgr::supplyInfoFunc (const string& keyList) -{ - return (itsCAMInterface.appSupplyInfo(itsProcName, keyList)); -} - - } // namespace CEPCU -} // namespace LOFAR diff --git a/MAC/APL/CEPCU/src/OnlineControl/CEPApplMgr.h b/MAC/APL/CEPCU/src/OnlineControl/CEPApplMgr.h deleted file mode 100644 index 61a2ecb1f84aea826335a5eb0c6d7d52e568b2a8..0000000000000000000000000000000000000000 --- a/MAC/APL/CEPCU/src/OnlineControl/CEPApplMgr.h +++ /dev/null @@ -1,215 +0,0 @@ -//# CEPApplMgr.h: factory class for Virtual Backends. -//# -//# Copyright (C) 2002-2005 -//# ASTRON (Netherlands Foundation for Research in Astronomy) -//# P.O.Box 2, 7990 AA Dwingeloo, The Netherlands, seg@astron.nl -//# -//# This program is free software; you can redistribute it and/or modify -//# it under the terms of the GNU General Public License as published by -//# the Free Software Foundation; either version 2 of the License, or -//# (at your option) any later version. -//# -//# This program is distributed in the hope that it will be useful, -//# but WITHOUT ANY WARRANTY; without even the implied warranty of -//# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -//# GNU General Public License for more details. -//# -//# You should have received a copy of the GNU General Public License -//# along with this program; if not, write to the Free Software -//# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -//# -//# $Id$ - -#ifndef CEPAPPLMGR_H -#define CEPAPPLMGR_H - -//# Includes -#include <GCF/TM/GCF_Handler.h> -#include <ALC/ACAsyncClient.h> -#include <APL/APLCommon/CTState.h> - -//# local includes -//# Common Includes - -// forward declaration - -namespace LOFAR { - using APLCommon::CTState; - namespace CEPCU { - -// The CEPApplMgrInterface is an abstract baseclass to define the interface -// the CEPApplMgr will call for passing the results of ACC back to the controller. -class CEPApplMgrInterface -{ -public: - virtual ~CEPApplMgrInterface() {} - - virtual void appSetStateResult (const string& procName, - CTState::CTstateNr newState, - uint16 result) = 0; - virtual string appSupplyInfo (const string& procName, - const string& keyList) = 0; - virtual void appSupplyInfoAnswer(const string& procName, - const string& answer) = 0; -protected: - CEPApplMgrInterface() {} - -private: - // protected copy constructor - CEPApplMgrInterface(const CEPApplMgrInterface&); - // protected assignment operator - CEPApplMgrInterface& operator=(const CEPApplMgrInterface&); -}; - - - -// The CEPApplMgr class acts as an ACClient for the OnlineController but it -// also an active component because is is also inherited from GCFHandler. -// The GCFHandler-workproc will poll the ACC connection for incomming msgs. -class CEPApplMgr : public ACC::ALC::ACClientFunctions, - GCF::TM::GCFHandler -{ -public: - CEPApplMgr(CEPApplMgrInterface& interface, - const string& appName, - uint32 expectedRuntime, - const string& acdHost, - const string& paramFile); - virtual ~CEPApplMgr(); - - // method used by the OnlineController to initiate a new command - void sendCommand (CTState::CTstateNr newState, const string& options); - - // methods may be called from specialized CEPApplMgrInterface - bool boot (const time_t scheduleTime, - const string& configID); - bool define (const time_t scheduleTime) const; - bool init (const time_t scheduleTime) const; - bool run (const time_t scheduleTime) const; - bool pause (const time_t scheduleTime, - const time_t maxWaitTime, - const string& condition) const; - bool release (const time_t scheduleTime) const; - bool quit (const time_t scheduleTime) const; - bool shutdown (const time_t scheduleTime) const; - bool snapshot (const time_t scheduleTime, - const string& destination) const; - bool recover (const time_t scheduleTime, - const string& source) const; - bool reinit (const time_t scheduleTime, - const string& configID) const; - string askInfo (const string& keylist) const; - - bool cancelCmdQueue () const; - - const string& getName() const; - -protected: - // protected copy constructor - CEPApplMgr(const CEPApplMgr&); - // protected assignment operator - CEPApplMgr& operator=(const CEPApplMgr&); - -private: - // implemenation of abstract GCFHandler methods - friend class GCF::TM::GCFHandler; - void workProc(); - void stop(); - - // implemenation of abstract ACClientFunctions methods - friend class ACC::ALC::ACClientFunctions; - void handleAckMsg (ACC::ALC::ACCmd cmd, - uint16 result, - const string& info); - void handleAnswerMsg (const string& answer); - string supplyInfoFunc (const string& keyList); - - // --- datamembers --- - string itsProcName; // my name - string itsParamFile; // name of paramfile - CEPApplMgrInterface& itsCAMInterface; // link to OnlineController - ACC::ALC::ACAsyncClient itsACclient; // link to ACC controller - uint16 itsReqState; // requested state - uint16 itsCurState; // reached state - bool itsContinuePoll; // for workProc -// ACC::ALC::ACCmd itsLastOkCmd; -}; - -inline const string& CEPApplMgr::getName() const -{ - return (itsProcName); -} - -inline bool CEPApplMgr::boot(const time_t scheduleTime, - const string& configID) -{ - itsContinuePoll = true; - return (itsACclient.boot(scheduleTime, configID)); -} - -inline bool CEPApplMgr::define(const time_t scheduleTime) const -{ - return (itsACclient.define(scheduleTime)); -} - -inline bool CEPApplMgr::init(const time_t scheduleTime) const -{ - return (itsACclient.init(scheduleTime)); -} - -inline bool CEPApplMgr::run(const time_t scheduleTime) const -{ - return (itsACclient.run(scheduleTime)); -} - -inline bool CEPApplMgr::pause (const time_t scheduleTime, - const time_t maxWaitTime, - const string& condition) const -{ - return (itsACclient.pause(scheduleTime, maxWaitTime, condition)); -} - -inline bool CEPApplMgr::release (const time_t scheduleTime) const -{ - return (itsACclient.release(scheduleTime)); -} - -inline bool CEPApplMgr::quit (const time_t scheduleTime) const -{ - return (itsACclient.quit(scheduleTime)); -} - -inline bool CEPApplMgr::shutdown (const time_t scheduleTime) const -{ - return (itsACclient.shutdown(scheduleTime)); -} - -inline bool CEPApplMgr::snapshot (const time_t scheduleTime, - const string& destination) const -{ - return (itsACclient.snapshot(scheduleTime, destination)); -} - -inline bool CEPApplMgr::recover (const time_t scheduleTime, - const string& source) const -{ - return (itsACclient.recover(scheduleTime, source)); -} - -inline bool CEPApplMgr::reinit (const time_t scheduleTime, - const string& configID) const -{ - return (itsACclient.reinit(scheduleTime, configID)); -} - -inline bool CEPApplMgr::cancelCmdQueue () const -{ - return itsACclient.cancelCmdQueue(); -} - -inline void CEPApplMgr::stop() -{ } - - } // namespace CEPCU -} // namespace LOFAR -#endif diff --git a/MAC/APL/CEPCU/src/OnlineControl/CMakeLists.txt b/MAC/APL/CEPCU/src/OnlineControl/CMakeLists.txt index a97577bda5839778d9b90238fada73087b9f2d39..5ac310e98b95dff761b473547826c445bfd3d35f 100644 --- a/MAC/APL/CEPCU/src/OnlineControl/CMakeLists.txt +++ b/MAC/APL/CEPCU/src/OnlineControl/CMakeLists.txt @@ -8,6 +8,6 @@ include_directories(${CMAKE_CURRENT_SOURCE_DIR}) lofar_add_bin_program(OnlineControl OnlineControlMain.cc OnlineControl.cc - CEPApplMgr.cc) + forkexec.cc) lofar_add_executable(tPVSSMapping tPVSSMapping.cc) diff --git a/MAC/APL/CEPCU/src/OnlineControl/OnlineControl.cc b/MAC/APL/CEPCU/src/OnlineControl/OnlineControl.cc index d729e40b1b1cae3a8594ce6ff05e025596df8753..64bbb8db60e0f826c0deb28fd5b48aa5688eb48d 100644 --- a/MAC/APL/CEPCU/src/OnlineControl/OnlineControl.cc +++ b/MAC/APL/CEPCU/src/OnlineControl/OnlineControl.cc @@ -41,8 +41,8 @@ #include <APL/APLCommon/ControllerDefines.h> #include <APL/APLCommon/Controller_Protocol.ph> #include <APL/APLCommon/CTState.h> -#include <PLC/PCCmd.h> #include "OnlineControl.h" +#include "forkexec.h" #include <OTDB/TreeValue.h> // << need to include this after OnlineControl! ??? #include "PVSSDatapointDefs.h" @@ -53,7 +53,6 @@ using namespace std; namespace LOFAR { using namespace APLCommon; - using namespace ACC::ALC; using namespace OTDB; namespace CEPCU { @@ -72,15 +71,7 @@ OnlineControl::OnlineControl(const string& cntlrName) : itsParentPort (0), itsTimerPort (0), itsLogControlPort (0), - itsCEPapplications (), - itsResultParams (), itsState (CTState::NOSTATE), - itsUseApplOrder (false), - itsApplOrder (), - itsCurrentAppl (), - itsApplState (CTState::NOSTATE), - itsOverallResult (0), - itsNrOfAcks2Recv (0), itsTreePrefix (""), itsInstanceNr (0), itsStartTime (), @@ -173,117 +164,6 @@ void OnlineControl::_setState(CTState::CTstateNr newState) } -// -// startNewState(newState) -// -void OnlineControl::startNewState(CTState::CTstateNr newState, - const string& options) -{ - // TODO: check if previous state has ended? - - CTState cts; - LOG_INFO_STR("startNewState(" << cts.name(newState) << "," << options << ")"); - - _setState (newState); - - if (!itsUseApplOrder) { // no depencies between applications? - for (CAMiter iter = itsCEPapplications.begin(); - iter != itsCEPapplications.end(); ++iter) { - iter->second->sendCommand(newState, options); - } - itsOverallResult = 0; - itsOptions.clear(); - itsNrOfAcks2Recv = itsCEPapplications.size(); - } - else { - // The applications depend on each other send command to first application. - CAMiter iter = firstApplication(newState); - iter->second->sendCommand(newState, options); - itsOverallResult = 0; - itsNrOfAcks2Recv = 1; - itsOptions = options; - } - - // TODO: start timer??? -} - - -// -// appSetStateResult(procName, newState, result) -// -// A result of a new state was received. Update our admin with this result and -// inform parentController is all Applications have reached the newState now. -// When the applications are dependant of each order send the same command to -// the next application. -// -// NOTE: FUNCTION IS CALLED BY CEPApplMgr -// -void OnlineControl::appSetStateResult(const string& procName, - CTState::CTstateNr aState, - uint16 result) -{ - CTState cts; - LOG_INFO_STR("setStateResult(" << procName <<","<< cts.name(aState) - <<","<< result <<")"); - - // is the result in sync? - if (aState != itsState) { - LOG_ERROR_STR("Application " << procName << " reports result " << result - << " for state " << cts.name(aState) << " while the current state is " - << cts.name(itsState) << ". Ignoring result!"); - return; - } - - if (itsNrOfAcks2Recv <= 0) { - LOG_INFO_STR("Application " << procName << " reports result " << result - << " for state " << cts.name(aState) - << " after parentController was informed. Result will be unknown to Parent."); - return; - } - - // result useOrder action - // OK J if nextAppl sendCmd else inform parent. [A] - // ERROR J if in start sequence: send Error to Parent, reset sequence. [B1] - // ERROR J if in stop sequence: if nextAppl sendCmd else inform parent [B2] - // OK N decr nrOfAcks2Recv if 0 inform parent. [C] - // ERROR N decr nrOfAcks2Recv if 0 inform parent. [D] - - itsOverallResult |= result; - - if (!itsUseApplOrder) { // [C],[D] - if (--itsNrOfAcks2Recv <= 0) { - LOG_DEBUG("All results received, informing parent"); - sendControlResult(*itsParentPort, cts.signal(itsState), - getName(), itsOverallResult); - if (aState == CTState::QUIT) { - finish(); - } - } - return; - } - // [A],[B] not handled yet. - - if ((result == CT_RESULT_NO_ERROR) || (itsState >= CTState::SUSPEND)) { // [A],[B2] - if (hasNextApplication()) { - CAMiter nextApp = nextApplication(); - LOG_DEBUG_STR("Sending " << cts.name(itsState) << " to next application: " - << nextApp->second->getName()); - nextApp->second->sendCommand(itsState, itsOptions); - return; - } - } - - // no more application for [A]or[B2], or error in [B1] - sendControlResult(*itsParentPort, cts.signal(itsState), getName(), itsOverallResult); - itsNrOfAcks2Recv = 0; - noApplication(); // reset order-sequence - - if (aState == CTState::QUIT) { - finish(); - } -} - - // // _databaseEventHandler(event) // @@ -475,14 +355,16 @@ GCFEvent::TResult OnlineControl::active_state(GCFEvent& event, GCFPortInterface& GCFTimerEvent& timerEvent=static_cast<GCFTimerEvent&>(event); if (timerEvent.id == itsStopTimerID) { LOG_DEBUG("StopTimer expired, starting QUIT sequence"); - startNewState(CTState::QUIT, ""/*options*/); itsStopTimerID = 0; - itsFinishTimerID = itsTimerPort->setTimer(5.0); + finish(); +// itsFinishTimerID = itsTimerPort->setTimer(30.0); } +#if 0 else if (timerEvent.id == itsFinishTimerID) { LOG_INFO("Forcing quit"); - finish(); + GCFScheduler::instance()->stop(); } +#endif else { LOG_WARN_STR("Received unknown timer event"); } @@ -500,7 +382,12 @@ GCFEvent::TResult OnlineControl::active_state(GCFEvent& event, GCFPortInterface& // execute this state _setState(CTState::CONNECT); _setupBGPmappingTables(); - _doBoot(); // start ACC's and boot them + uint32 result = _doBoot(); // start ACC's and boot them + // respond to parent + sendControlResult(port, event.signal, msg.cntlrName, result); + if (result == CT_RESULT_NO_ERROR) { + _setState(CTState::CONNECTED); + } break; } @@ -514,14 +401,16 @@ GCFEvent::TResult OnlineControl::active_state(GCFEvent& event, GCFPortInterface& case CONTROL_CLAIM: { CONTROLClaimEvent msg(event); LOG_DEBUG_STR("Received CLAIM(" << msg.cntlrName << ")"); - startNewState(CTState::CLAIM, ""/*options*/); + sendControlResult(port, event.signal, msg.cntlrName, CT_RESULT_NO_ERROR); + _setState(CTState::CLAIMED); break; } case CONTROL_PREPARE: { CONTROLPrepareEvent msg(event); LOG_DEBUG_STR("Received PREPARE(" << msg.cntlrName << ")"); - startNewState(CTState::PREPARE, ""/*options*/); + sendControlResult(port, event.signal, msg.cntlrName, CT_RESULT_NO_ERROR); + _setState(CTState::PREPARED); break; } @@ -529,40 +418,32 @@ GCFEvent::TResult OnlineControl::active_state(GCFEvent& event, GCFPortInterface& CONTROLResumeEvent msg(event); LOG_DEBUG_STR("Received RESUME(" << msg.cntlrName << ")"); itsStartTime = second_clock::universal_time(); // adjust to latest run. - startNewState(CTState::RESUME, ""/*options*/); -// LOG_DEBUG_STR("Starttime set to " << to_simple_string(itsStartTime)); + sendControlResult(port, event.signal, msg.cntlrName, CT_RESULT_NO_ERROR); + _setState(CTState::RESUMED); break; } case CONTROL_SUSPEND: { CONTROLSuspendEvent msg(event); LOG_DEBUG_STR("Received SUSPEND(" << msg.cntlrName << ")"); - startNewState(CTState::SUSPEND, PAUSE_OPTION_NOW); + sendControlResult(port, event.signal, msg.cntlrName, CT_RESULT_NO_ERROR); + _setState(CTState::SUSPEND); break; } case CONTROL_RELEASE: { CONTROLReleaseEvent msg(event); LOG_DEBUG_STR("Received RELEASE(" << msg.cntlrName << ")"); - startNewState(CTState::RELEASE, ""/*options*/); + sendControlResult(port, event.signal, msg.cntlrName, CT_RESULT_NO_ERROR); + _setState(CTState::RELEASED); break; } case CONTROL_QUIT: { CONTROLQuitEvent msg(event); LOG_DEBUG_STR("Received QUIT(" << msg.cntlrName << ")"); -// ptime now(second_clock::universal_time()); -// LOG_DEBUG_STR("now set to " << to_simple_string(now)); -// LOG_DEBUG_STR("period is " << time_duration(now - itsStartTime).total_seconds()); -// uint32 waitTime = 16 - (time_duration(now - itsStartTime).total_seconds()%16); -// if (waitTime == 16) { // precisely on a multiple of 16! Stop immediately - startNewState(CTState::QUIT, ""/*options*/); -// } -// else { -// // wait for multiple of 16 seconds. -// itsStopTimerID = itsTimerPort->setTimer(waitTime * 1.0); -// LOG_INFO_STR("Delaying quit command for " << waitTime << " seconds to sync on multiple of 16"); -// } + _setState(CTState::QUIT); + finish(); break; } @@ -588,6 +469,7 @@ GCFEvent::TResult OnlineControl::finishing_state(GCFEvent& event, GCFPortInterfa switch (event.signal) { case F_ENTRY: { if (itsInFinishState) { + LOG_WARN("Already in finish state, ignoring request"); return (status); } itsInFinishState = true; @@ -596,12 +478,31 @@ GCFEvent::TResult OnlineControl::finishing_state(GCFEvent& event, GCFPortInterfa itsPropertySet->setValue(PN_FSM_CURRENT_ACTION, GCFPVString("finished")); itsPropertySet->setValue(PN_FSM_ERROR, GCFPVString("")); + ParameterSet* thePS = globalParameterSet(); // shortcut to global PS. + uint32 obsID = thePS->getUint32("Observation.ObsID"); + vector<string> applList = thePS->getStringVector("applications"); + for (size_t a = 0; a < applList.size(); a++) { + // Initialize basic variables + string applName (applList[a]); + string applPrefix(applName+"."); + vector<string> procNames = thePS->getStringVector(applPrefix+"processes","[]"); + string procName = procNames[0]; + string accHost = thePS->getString(applPrefix+"_hostname", "UNKNOWN_HOST"); + + // send stop to BGP + string stopCmd = formatString("ssh %s stopBGL.sh %s %d", + accHost.c_str(), + procName.c_str(), + obsID); + LOG_INFO_STR("About to execute: " << stopCmd); + uint32 result = forkexec(stopCmd.c_str()); + LOG_INFO_STR ("Result of command = " << result); + } + // construct system command for starting an inspection program to qualify the measured data - ParameterSet* thePS = globalParameterSet(); // shortcut to global PS. string myPrefix (thePS->locateModule("OnlineControl")+"OnlineControl."); string inspectProg (thePS->getString(myPrefix+"inspectionProgram", "@inspectionProgram@")); string inspectHost (thePS->getString(myPrefix+"inspectionHost", "@inspectionHost@")); - uint32 obsID (thePS->getUint32("Observation.ObsID", 0)); bool onRemoteMachine(inspectHost != myHostname(false) && inspectHost != myHostname(true)); string startCmd; if (onRemoteMachine) { @@ -611,7 +512,7 @@ GCFEvent::TResult OnlineControl::finishing_state(GCFEvent& event, GCFPortInterfa startCmd = formatString("%s %d &", inspectProg.c_str(), obsID); } LOG_INFO_STR("About to start: " << startCmd); - int32 result = system (startCmd.c_str()); + uint32 result = forkexec(startCmd.c_str()); LOG_INFO_STR ("Result of command = " << result); itsTimerPort->setTimer(302.0); // IONProc, and thus CEPlogProcessor, can take up to 5 minutes to wrap up @@ -717,7 +618,7 @@ void OnlineControl::_setupBGPmappingTables() // Create ParameterSets for all Applications the we have to manage, start all // ACC's and give them the boot command. // -void OnlineControl::_doBoot() +uint32 OnlineControl::_doBoot() { ParameterSet* thePS = globalParameterSet(); // shortcut to global PS. @@ -726,9 +627,10 @@ void OnlineControl::_doBoot() vector<string> applList = thePS->getStringVector("applications"); string paramFileName; + uint32 result; for (size_t a = 0; a < applList.size(); a++) { // Initialize basic variables - uint16 result (CT_RESULT_NO_ERROR); + result = CT_RESULT_NO_ERROR; string applName (applList[a]); string applPrefix(applName+"."); @@ -767,72 +669,40 @@ void OnlineControl::_doBoot() params.replace("_DPname", thePS->getString("_DPname")); // write parset to file. - paramFileName = formatString("%s/ACC_%s_%s.param", LOFAR_SHARE_LOCATION, - getName().c_str(), applName.c_str()); + vector<string> procNames = thePS->getStringVector(applPrefix+"processes"); + string procName = procNames[0]; + uint32 obsID = thePS->getUint32("Observation.ObsID"); + paramFileName = formatString("%s/%s_%d.param", LOFAR_SHARE_LOCATION, procName.c_str(), obsID); params.writeFile(paramFileName); // local copy string accHost(thePS->getString(applPrefix+"_hostname")); LOG_DEBUG_STR("Controller for " << applName << " wil be running on " << accHost); remoteCopy(paramFileName,accHost,LOFAR_SHARE_LOCATION); + string startCmd = formatString("ssh %s startBGL.sh %s %s %s %s %d 1", + accHost.c_str(), + procName.c_str(), + thePS->getString(applPrefix + procName + "._executable").c_str(), + thePS->getString(applPrefix + procName + ".workingdir").c_str(), + paramFileName.c_str(), + obsID); + // Finally start ApplController on the right host LOG_INFO_STR("Starting controller for " << applName << " in 5 seconds "); sleep(5); // sometimes we are too quick, wait a second. - int32 expectedRuntime = time_duration(itsStopTime - itsStartTime).total_seconds(); - uint32 obsID = globalParameterSet()->getUint32("Observation.ObsID"); - CEPApplMgrPtr accClient (new CEPApplMgr(*this, formatString("%s%d", applName.c_str(), obsID), - expectedRuntime, accHost, paramFileName)); - itsCEPapplications[applName] = accClient; + LOG_INFO_STR("About to start: " << startCmd); + result = forkexec(startCmd.c_str()) == 0 ? CT_RESULT_NO_ERROR : CT_RESULT_LOST_CONNECTION; } catch (APSException &e) { // key not found. skip LOG_FATAL(e.text()); result = CT_RESULT_UNSPECIFIED; - appSetStateResult(applList[a], CTState::CONNECT, result); } } // for - // finally setup application Order - vector<string> anApplOrder(thePS->getStringVector("applOrder")); - if (!anApplOrder.empty()) { - setApplOrder(anApplOrder); - } - - // Finally send the boot command. - startNewState(CTState::CONNECT, ""); - + return (result); } -// -// _doQuit() -// -void OnlineControl::_doQuit(void) -{ - try { -#if 0 - for(size_t i = 0;i < itsCepAppParams.size();i++) { - string remoteFile, resultFile, applName; - applName = itsCepAppParams[i].getString("ApplCtrl.application"); - resultFile = formatString("ACC-%s_result.param", applName.c_str()); - remoteFile = string(LOFAR_SHARE_LOCATION) + string("/") + resultFile; -// APLCommon::APLUtilities::copyFromRemote(hostName,remoteFile,resultFile); - itsResultParams.adoptFile(resultFile); - // itsResultParams.replace(KVpair(formatString("%s.quality", getName().c_str()), (int) _qualityGuard.getQuality())); - if (!itsResultParams.isDefined(formatString("%s.faultyNodes", getName().c_str()))) { - itsResultParams.add(formatString("%s.faultyNodes", getName().c_str()), ""); - } - itsResultParams.writeFile(formatString("%s_result.param", getName().c_str())); - } -#endif - } - catch(...) { - } - map<string, CEPApplMgrPtr>::iterator it; - for(it = itsCEPapplications.begin();it != itsCEPapplications.end();++it) { - it->second->quit(0); - } -} - // // _passMetadatToOTDB(); // THIS ROUTINE IS A MODIFIED COPY FROM PYTHONCONTROL.CC @@ -848,227 +718,75 @@ void OnlineControl::_passMetadatToOTDB() } // read parameterset - ParameterSet metadata; - metadata.adoptFile(feedbackFile); - - // Try to setup the connection with the database - string confFile = globalParameterSet()->getString("OTDBconfFile", "SASGateway.conf"); - ConfigLocator CL; - string filename = CL.locate(confFile); - LOG_INFO_STR("Trying to read database information from file " << filename); - ParameterSet otdbconf; - otdbconf.adoptFile(filename); - string database = otdbconf.getString("SASGateway.OTDBdatabase"); - string dbhost = otdbconf.getString("SASGateway.OTDBhostname"); - OTDBconnection conn("paulus", "boskabouter", database, dbhost); - if (!conn.connect()) { - LOG_FATAL_STR("Cannot connect to database " << database << " on machine " << dbhost); - return; - } - LOG_INFO_STR("Connected to database " << database << " on machine " << dbhost); - - TreeValue tv(&conn, getObservationNr(getName())); - - // Loop over the parameterset and send the information to the KVTlogger. - // During the transition phase from parameter-based to record-based storage in OTDB the - // nodenames ending in '_' are implemented both as parameter and as record. - ParameterSet::iterator iter = metadata.begin(); - ParameterSet::iterator end = metadata.end(); - while (iter != end) { - string key(iter->first); // make destoyable copy - rtrim(key, "[]0123456789"); -// bool doubleStorage(key[key.size()-1] == '_'); - bool isRecord(iter->second.isRecord()); - // isRecord doubleStorage - // -------------------------------------------------------------- - // Y Y store as record and as parameters - // Y N store as parameters - // N * store parameter - if (!isRecord) { - LOG_DEBUG_STR("BASIC: " << iter->first << " = " << iter->second); - tv.addKVT(iter->first, iter->second, ptime(microsec_clock::local_time())); + try { + ParameterSet metadata; + metadata.adoptFile(feedbackFile); + + // Try to setup the connection with the database + string confFile = globalParameterSet()->getString("OTDBconfFile", "SASGateway.conf"); + ConfigLocator CL; + string filename = CL.locate(confFile); + LOG_INFO_STR("Trying to read database information from file " << filename); + ParameterSet otdbconf; + otdbconf.adoptFile(filename); + string database = otdbconf.getString("SASGateway.OTDBdatabase"); + string dbhost = otdbconf.getString("SASGateway.OTDBhostname"); + OTDBconnection conn("paulus", "boskabouter", database, dbhost); + if (!conn.connect()) { + LOG_FATAL_STR("Cannot connect to database " << database << " on machine " << dbhost); + return; } - else { -// if (doubleStorage) { -// LOG_DEBUG_STR("RECORD: " << iter->first << " = " << iter->second); -// tv.addKVT(iter->first, iter->second, ptime(microsec_clock::local_time())); -// } - // to store is a node/param values the last _ should be stipped of - key = iter->first; // destroyable copy -// string::size_type pos = key.find_last_of('_'); -// key.erase(pos,1); - ParameterRecord pr(iter->second.getRecord()); - ParameterRecord::const_iterator prIter = pr.begin(); - ParameterRecord::const_iterator prEnd = pr.end(); - while (prIter != prEnd) { - LOG_DEBUG_STR("ELEMENT: " << key+"."+prIter->first << " = " << prIter->second); - tv.addKVT(key+"."+prIter->first, prIter->second, ptime(microsec_clock::local_time())); - prIter++; + LOG_INFO_STR("Connected to database " << database << " on machine " << dbhost); + + TreeValue tv(&conn, getObservationNr(getName())); + + // Loop over the parameterset and send the information to the KVTlogger. + // During the transition phase from parameter-based to record-based storage in OTDB the + // nodenames ending in '_' are implemented both as parameter and as record. + ParameterSet::iterator iter = metadata.begin(); + ParameterSet::iterator end = metadata.end(); + while (iter != end) { + string key(iter->first); // make destoyable copy + rtrim(key, "[]0123456789"); + // bool doubleStorage(key[key.size()-1] == '_'); + bool isRecord(iter->second.isRecord()); + // isRecord doubleStorage + // -------------------------------------------------------------- + // Y Y store as record and as parameters + // Y N store as parameters + // N * store parameter + if (!isRecord) { + LOG_DEBUG_STR("BASIC: " << iter->first << " = " << iter->second); + tv.addKVT(iter->first, iter->second, ptime(microsec_clock::local_time())); } - } - iter++; - } - LOG_INFO_STR(metadata.size() << " metadata values send to SAS"); -} -// -------------------- Application-order administration -------------------- - -// -// setApplOrder(appl-vector) -// -void OnlineControl::setApplOrder(vector<string>& anApplOrder) -{ - itsUseApplOrder = true; // assume everything is right. - itsApplOrder = anApplOrder; - - LOG_DEBUG_STR("setApplOrder: Checking " << itsApplOrder); - - // every application must be in the order list. - ASSERTSTR(itsApplOrder.size() == itsCEPapplications.size(), - "Application orderlist conflicts with length of applicationlist"); - - // check that all applications exist - CAMiter applEnd = itsCEPapplications.end(); - vector<string>::iterator orderIter = itsApplOrder.begin(); - while (orderIter != itsApplOrder.end()) { - CAMiter applIter = itsCEPapplications.begin(); - while (applIter != applEnd) { - LOG_DEBUG_STR("compare: " << applIter->first << " with " << *orderIter); - if (applIter->first == *orderIter) { - break; + else { + // if (doubleStorage) { + // LOG_DEBUG_STR("RECORD: " << iter->first << " = " << iter->second); + // tv.addKVT(iter->first, iter->second, ptime(microsec_clock::local_time())); + // } + // to store is a node/param values the last _ should be stipped of + key = iter->first; // destroyable copy + // string::size_type pos = key.find_last_of('_'); + // key.erase(pos,1); + ParameterRecord pr(iter->second.getRecord()); + ParameterRecord::const_iterator prIter = pr.begin(); + ParameterRecord::const_iterator prEnd = pr.end(); + while (prIter != prEnd) { + LOG_DEBUG_STR("ELEMENT: " << key+"."+prIter->first << " = " << prIter->second); + tv.addKVT(key+"."+prIter->first, prIter->second, ptime(microsec_clock::local_time())); + prIter++; + } } - applIter++; + iter++; } - ASSERTSTR(applIter != applEnd, *orderIter << - " is not a registered application, orderlist is illegal"); - orderIter++; + LOG_INFO_STR(metadata.size() << " metadata values send to SAS"); } - LOG_INFO_STR ("Using application order: " << itsApplOrder); -} - - -// -// firstApplication(newState) -// -OnlineControl::CAMiter OnlineControl::firstApplication(CTState::CTstateNr newState) -{ - if (itsCurrentAppl != "") { - LOG_ERROR_STR("Starting new command-chain while previous command-chain was still at application " - << itsCurrentAppl << ". Results are unpredictable!"); + catch (APSException &e) { + // Parameterfile not found + LOG_FATAL(e.text()); } - - itsApplState = newState; - vector<string>::iterator newApplIter; - switch (newState) { - case CTState::CONNECT: - case CTState::CLAIM: - case CTState::PREPARE: - case CTState::RESUME: - newApplIter = itsApplOrder.begin(); - break; - - case CTState::SUSPEND: - case CTState::RELEASE: - case CTState::QUIT: - newApplIter = itsApplOrder.end(); - newApplIter--; - break; - - default: // satisfy compiler - CTState cts; - ASSERTSTR(false, "Illegal new state in firstApplication(): " - << cts.name(newState)); - break; - } - - itsCurrentAppl = *newApplIter; - LOG_DEBUG_STR("First application is " << itsCurrentAppl); - return (itsCEPapplications.find(itsCurrentAppl)); -} - - -// -// nextApplication() -// -OnlineControl::CAMiter OnlineControl::nextApplication() -{ - ASSERTSTR (hasNextApplication(), "Programming error, must use application ordering"); - - // search current application in the list. - vector<string>::iterator iter = itsApplOrder.begin(); - while (iter != itsApplOrder.end()) { - if (*iter == itsCurrentAppl) { - break; - } - iter++; - } - ASSERTSTR (iter != itsApplOrder.end(), "Application " << itsCurrentAppl - << "not found in applicationList"); - - switch (itsApplState) { - case CTState::CONNECT: - case CTState::CLAIM: - case CTState::PREPARE: - case CTState::RESUME: - iter++; - break; - - case CTState::SUSPEND: - case CTState::RELEASE: - case CTState::QUIT: - iter--; - break; - - default: - ASSERT("Satisfy compiler"); - } - - itsCurrentAppl = *iter; - LOG_DEBUG_STR("Next application is " << itsCurrentAppl); - return (itsCEPapplications.find(itsCurrentAppl)); -} - - -// -// noApplication() -// -void OnlineControl::noApplication() -{ - itsCurrentAppl = ""; - itsOptions.clear(); -} - - -// -// hasNextApplication() -// -bool OnlineControl::hasNextApplication() -{ - if (!itsUseApplOrder) { - return (false); - } - - switch (itsApplState) { - case CTState::CONNECT: - case CTState::CLAIM: - case CTState::PREPARE: - case CTState::RESUME: - return (itsCurrentAppl != *(itsApplOrder.rbegin())); - break; - - case CTState::SUSPEND: - case CTState::RELEASE: - case CTState::QUIT: - return (itsCurrentAppl != *(itsApplOrder.begin())); - break; - - default: { - CTState cts; - ASSERTSTR(false, "Illegal state in hasNextApplication(): " - << cts.name(itsApplState)); - } - } - } +// -------------------- Application-order administration -------------------- // // _connectedHandler(port) @@ -1085,28 +803,5 @@ void OnlineControl::_disconnectedHandler(GCFPortInterface& port) port.close(); } -// -// appSupplyInfo(procName, keyList) -// -// note: function is called by CEPApplMgr -// -string OnlineControl::appSupplyInfo(const string& procName, const string& keyList) -{ - LOG_INFO_STR("appSupplyInfo from " << procName); - string ret(keyList); - return ret; -} - -// -// appSupplyInfoAnswer(procName, answer) -// -// note: function is called by CEPApplMgr -// -void OnlineControl::appSupplyInfoAnswer(const string& procName, const string& answer) -{ - LOG_INFO_STR("Answer from " << procName << ": " << answer); -} - - }; // CEPCU }; // LOFAR diff --git a/MAC/APL/CEPCU/src/OnlineControl/OnlineControl.h b/MAC/APL/CEPCU/src/OnlineControl/OnlineControl.h index 09e695da178ecd507c4aea046f97d215ec09545e..ddbf2fd67f9c4653ec781cf1cb9540313c94c24e 100644 --- a/MAC/APL/CEPCU/src/OnlineControl/OnlineControl.h +++ b/MAC/APL/CEPCU/src/OnlineControl/OnlineControl.h @@ -41,8 +41,6 @@ #include <APL/APLCommon/ParentControl.h> #include <APL/APLCommon/CTState.h> -#include <CEPApplMgr.h> - // forward declaration namespace LOFAR { @@ -57,9 +55,7 @@ using GCF::TM::GCFTask; using GCF::RTDB::RTDBPropertySet; using APLCommon::ParentControl; - -class OnlineControl : public GCFTask, - public CEPApplMgrInterface +class OnlineControl : public GCFTask { public: explicit OnlineControl(const string& cntlrName); @@ -78,25 +74,14 @@ public: static void signalHandler (int signum); void finish(); -protected: // implemenation of abstract CEPApplMgrInterface methods - string appSupplyInfo (const string& procName, const string& keyList); - void appSupplyInfoAnswer (const string& procName, const string& answer); - // A result of one of the applications was received, update the administration - // off the controller and send the result to the parentcontroller if appropriate. - void appSetStateResult (const string& procName, - CTState::CTstateNr newState, - uint16 result); - - private: // avoid defaultconstruction and copying OnlineControl(); OnlineControl(const OnlineControl&); OnlineControl& operator=(const OnlineControl&); + uint32 _doBoot(); void _setupBGPmappingTables(); - void _doBoot(); - void _doQuit(); void _finishController (uint16_t result); void _connectedHandler (GCFPortInterface& port); void _disconnectedHandler (GCFPortInterface& port); @@ -104,22 +89,6 @@ private: void _databaseEventHandler(GCFEvent& event); void _passMetadatToOTDB (); - // Send a command to all (or the first) applications. - void startNewState (CTState::CTstateNr newState, - const string& options); - - // typedefs for the internal adminsitration of all the Applications we control - typedef boost::shared_ptr<CEPApplMgr> CEPApplMgrPtr; - typedef map<string, CEPApplMgrPtr> CAMmap; - typedef map<string, CEPApplMgrPtr>::iterator CAMiter; - - // Internal bookkeeping-finctions for the dependancy-order of the applications. - void setApplOrder (vector<string>& anApplOrder); - CAMiter firstApplication(CTState::CTstateNr aState); - CAMiter nextApplication(); - bool hasNextApplication(); - void noApplication(); - // ----- datamembers ----- RTDBPropertySet* itsPropertySet; RTDBPropertySet* itsBGPApplPropSet; @@ -133,20 +102,8 @@ private: GCFTCPPort* itsLogControlPort; - CAMmap itsCEPapplications; - ParameterSet itsResultParams; - CTState::CTstateNr itsState; - bool itsUseApplOrder; // Applications depend? - vector<string> itsApplOrder; // startOrder of the applications. - string itsCurrentAppl; // current application we are handling. - CTState::CTstateNr itsApplState; // state currently handled by apps. - string itsOptions; // Current active option - - uint16 itsOverallResult; - int16 itsNrOfAcks2Recv; - // ParameterSet variables string itsTreePrefix; uint32 itsInstanceNr; diff --git a/MAC/APL/CEPCU/src/OnlineControl/forkexec.cc b/MAC/APL/CEPCU/src/OnlineControl/forkexec.cc new file mode 100644 index 0000000000000000000000000000000000000000..533fb28fb797027cdff5531372d7af79eb201354 --- /dev/null +++ b/MAC/APL/CEPCU/src/OnlineControl/forkexec.cc @@ -0,0 +1,74 @@ +//# forkexec.cc: Custom fork/exec implementation for more control +//# +//# Copyright (C) 2002-2004 +//# ASTRON (Netherlands Foundation for Research in Astronomy) +//# P.O.Box 2, 7990 AA Dwingeloo, The Netherlands, seg@astron.nl +//# +//# This program is free software; you can redistribute it and/or modify +//# it under the terms of the GNU General Public License as published by +//# the Free Software Foundation; either version 2 of the License, or +//# (at your option) any later version. +//# +//# This program is distributed in the hope that it will be useful, +//# but WITHOUT ANY WARRANTY; without even the implied warranty of +//# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +//# GNU General Public License for more details. +//# +//# You should have received a copy of the GNU General Public License +//# along with this program; if not, write to the Free Software +//# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//# + +//# Always #include <lofar_config.h> first! +#include <lofar_config.h> + +//# Includes +#include "forkexec.h" + +#include <unistd.h> +#include <sys/wait.h> +#include <errno.h> + +namespace LOFAR { + namespace CEPCU { + +int32 forkexec( const char *command ) +{ + int status; + pid_t pid; + + pid = fork(); + + switch (pid) { + case -1: + // error + return -1; + + case 0: + // child process + + // close all filedescriptors + for (int f = dup(2); f > 2; --f) { + while ( close(f) == EINTR ) + ; + } + + execl("/bin/sh", "/bin/sh", "-c", command, static_cast<char*>(0)); + + // only reached if exec fails + _exit(1); + + default: + // parent process + if (waitpid(pid, &status, 0) == -1) { + // error + return errno; + } + + return WEXITSTATUS(status); + } +} + + + } // namespace CEPCU +} // namespace LOFAR diff --git a/MAC/APL/CEPCU/src/OnlineControl/forkexec.h b/MAC/APL/CEPCU/src/OnlineControl/forkexec.h new file mode 100644 index 0000000000000000000000000000000000000000..65a1a59f4160ed66ce3a4453712b1466b3ac42b4 --- /dev/null +++ b/MAC/APL/CEPCU/src/OnlineControl/forkexec.h @@ -0,0 +1,41 @@ +//# PR_BGL.h: Custom fork/exec implementation for more control +//# +//# Copyright (C) 2002-2004 +//# ASTRON (Netherlands Foundation for Research in Astronomy) +//# P.O.Box 2, 7990 AA Dwingeloo, The Netherlands, seg@astron.nl +//# +//# This program is free software; you can redistribute it and/or modify +//# it under the terms of the GNU General Public License as published by +//# the Free Software Foundation; either version 2 of the License, or +//# (at your option) any later version. +//# +//# This program is distributed in the hope that it will be useful, +//# but WITHOUT ANY WARRANTY; without even the implied warranty of +//# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +//# GNU General Public License for more details. +//# +//# You should have received a copy of the GNU General Public License +//# along with this program; if not, write to the Free Software +//# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +//# +//# Note: This source is read best with tabstop 4. +//# +//# $Id: PR_BGL.h 10517 2007-09-17 07:54:57Z overeem $ + +#ifndef LOFAR_CEPCUBIN_FORKEXEC_H +#define LOFAR_CEPCUBIN_FORKEXEC_H + +//# Never #include <config.h> or #include <lofar_config.h> in a header file! +//# Includes +#include <Common/LofarTypes.h> + +namespace LOFAR { + namespace CEPCU { + +// a custom implementation of system( command ) +int32 forkexec( const char *command ); + + } // namespace CEPCU +} // namespace LOFAR + +#endif