+// Copyright (C) 2006-2021 CEA/DEN, EDF R&D
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library 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
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+//
#include "yacsconfig.h"
#include "RuntimeSALOME.hxx"
#include "Exception.hxx"
#include "Executor.hxx"
#include "parsers.hxx"
-#include "VisitorSaveState.hxx"
+#include "VisitorSalomeSaveState.hxx"
#include "VisitorSaveSalomeSchema.hxx"
#include "LoadState.hxx"
#include "Dispatcher.hxx"
#include "LinkInfo.hxx"
+#include "ObserverAsPlugin.hxx"
#ifdef SALOME_KERNEL
+
+#include "KernelBasis.hxx"
+#include "SALOME_Launcher.hxx"
+#include "ServiceUnreachable.hxx"
+#include "SALOME_NamingService_Wrapper.hxx"
#include "SALOME_NamingService.hxx"
#include "SALOME_ModuleCatalog.hh"
+#include "Basics_Utils.hxx"
#endif
#include <iostream>
#include <fstream>
+#include <signal.h>
+#include <list>
+
+#if defined WIN32 || defined __APPLE__
+#else
#include <argp.h>
+#endif
using YACS::YACSLoader;
using namespace YACS::ENGINE;
static char doc[] ="driver -- a SALOME YACS graph executor";
static char args_doc[] = "graph.xml";
+#if defined WIN32 || defined __APPLE__
+#else
static struct argp_option options[] =
{
- {"display", 'd', "level", 0, "Display dot files: 0=never to 3=very often"},
+ {"display", 'd', "level", 0, "Display dot files: 0=never to 3=very often (default 0)"},
{"verbose", 'v', 0, 0, "Produce verbose output" },
{"stop-on-error", 's', 0, 0, "Stop on first error" },
{"dump-on-error", 'e', "file", OPTION_ARG_OPTIONAL, "Stop on first error and dump state"},
{"dump-final", 'f', "file", OPTION_ARG_OPTIONAL, "dump final state"},
+ {"dump", 'g', "nbsec", OPTION_ARG_OPTIONAL, "dump state"},
{"load-state", 'l', "file", 0, "Load State from a previous partial execution"},
{"save-xml-schema", 'x', "file", OPTION_ARG_OPTIONAL, "dump xml schema"},
+ {"shutdown", 't', "level", 0, "Shutdown the schema: 0=no shutdown to 3=full shutdown (default 1)"},
+ {"reset", 'r', "level", 0, "Reset the schema before execution: 0=nothing, 1=reset error nodes to ready state (default 0)"},
+ {"kill-port", 'k', "port", 0, "Kill Salome application running on the specified port if the driver process is killed (with SIGINT or SIGTERM)"},
+ {"init_port", 'i', "value", OPTION_ARG_OPTIONAL, "Initialisation value of a port, specified as bloc.node.port=value."},
{ 0 }
};
+#endif
struct arguments
{
int stop;
char *dumpErrorFile;
char *finalDump;
+ int dump;
char *xmlSchema;
char *loadState;
+ int shutdown;
+ int reset;
+ int killPort;
+ std::list<std::string> init_ports;
};
+typedef struct {
+ int nbsec;
+ string dumpFile;
+ string lockFile;
+} thread_st;
+
+#if defined WIN32 || defined __APPLE__
+static int
+#else
static error_t
+#endif
parse_opt (int key, char *arg, struct argp_state *state)
{
+#if defined WIN32 || defined __APPLE__
+#else
// Get the input argument from argp_parse, which we
// know is a pointer to our arguments structure.
struct arguments *myArgs = (arguments*)state->input;
case 'd':
myArgs->display = atoi(arg);
break;
+ case 't':
+ myArgs->shutdown = atoi(arg);
+ break;
+ case 'r':
+ myArgs->reset = atoi(arg);
+ break;
case 'v':
myArgs->verbose = 1;
break;
if (arg)
myArgs->dumpErrorFile = arg;
else
- myArgs->dumpErrorFile = "dumpErrorState.xml";
+ myArgs->dumpErrorFile = (char *)"dumpErrorState.xml";
break;
case 'f':
if (arg)
myArgs->finalDump = arg;
else
- myArgs->finalDump = "finalDumpState.xml";
+ myArgs->finalDump = (char *)"finalDumpState.xml";
+ break;
+ case 'g':
+ if (arg)
+ myArgs->dump = atoi(arg);
+ else
+ myArgs->dump = 60;
break;
case 'l':
myArgs->loadState = arg;
if (arg)
myArgs->xmlSchema = arg;
else
- myArgs->xmlSchema = "saveSchema.xml";
+ myArgs->xmlSchema = (char *)"saveSchema.xml";
break;
+ case 'k':
+ myArgs->killPort = atoi(arg);
+ break;
+ case 'i':
+ if (arg)
+ myArgs->init_ports.push_back(std::string(arg));
+ break;
case ARGP_KEY_ARG:
if (state->arg_num >=1) // Too many arguments.
default:
return ARGP_ERR_UNKNOWN;
}
+#endif
return 0;
}
// Our argp parser.
+#if defined WIN32 || defined __APPLE__
+#else
static struct argp argp = { options, parse_opt, args_doc, doc };
+#endif
+
+void timer(std::string msg)
+{
+#if defined WIN32 || defined __APPLE__
+#else
+ struct timeval tv;
+ gettimeofday(&tv,NULL);
+ long t=tv.tv_sec*1000+tv.tv_usec/1000;
+ static long t0=t;
+ gettimeofday(&tv,NULL);
+ std::cerr << msg << tv.tv_sec*1000+tv.tv_usec/1000-t0 << " ms" << std::endl;
+#endif
+}
+
+Proc* p=0;
+static struct arguments myArgs;
+
+void Handler(int theSigId)
+{
+ if(p)
+ {
+ p->cleanNodes();
+ //if requested save state
+ bool isFinalDump = (strlen(myArgs.finalDump) != 0);
+ if (isFinalDump)
+ {
+ YACS::ENGINE::VisitorSalomeSaveState vst(p);
+ vst.openFileDump(myArgs.finalDump);
+ p->accept(&vst);
+ vst.closeFileDump();
+ }
+ //if requested shutdown schema
+ if(myArgs.shutdown < 999)
+ {
+ p->shutdown(myArgs.shutdown);
+ }
+ }
+ if (myArgs.killPort)
+ {
+ ostringstream command;
+ command << "killSalomeWithPort.py " << myArgs.killPort;
+ int status = system(command.str().c_str());
+ if (status == 0)
+ cerr << "Salome application on port " << myArgs.killPort << " is killed" << endl;
+ else
+ cerr << "Error: Can't kill Salome application on port " << myArgs.killPort << endl;
+ }
+ _exit(1);
+}
+
+void * dumpState(void *arg)
+{
+ thread_st *st = (thread_st*)arg;
+ YACS::StatesForNode state = p->getEffectiveState();
+ while((state != YACS::DONE) && (state != YACS::LOADFAILED) && (state != YACS::EXECFAILED) && (state != YACS::INTERNALERR) && (state != YACS::DISABLED) && (state != YACS::FAILED) && (state != YACS::ERROR)){
+#ifdef WIN32
+ Sleep(st->nbsec);
+#else
+ sleep(st->nbsec);
+#endif
+ string cmd = "touch " + st->lockFile;
+ system(cmd.c_str());
+ YACS::ENGINE::VisitorSalomeSaveState vst(p);
+ vst.openFileDump(st->dumpFile);
+ p->accept(&vst);
+ vst.closeFileDump();
+ cmd = "rm -f " + st->lockFile;
+ system(cmd.c_str());
+ state = p->getEffectiveState();
+ }
+ delete st;
+ return NULL;
+}
+#ifndef WIN32
+typedef void (*sighandler_t)(int);
+sighandler_t setsig(int sig, sighandler_t handler)
+{
+ struct sigaction context, ocontext;
+ context.sa_handler = handler;
+ sigemptyset(&context.sa_mask);
+ context.sa_flags = 0;
+ if (sigaction(sig, &context, &ocontext) == -1)
+ return SIG_ERR;
+ return ocontext.sa_handler;
+}
+#endif
-main (int argc, char* argv[])
+bool parse_init_port(const std::string& input, std::string& node, std::string& port, std::string& value)
+{
+ bool ok = true;
+ size_t pos_eq = input.find('=');
+ if(pos_eq == std::string::npos || pos_eq == input.size())
+ return false;
+ value = input.substr(pos_eq+1);
+ size_t pos_dot = input.rfind('.', pos_eq);
+ if(!pos_dot || pos_dot == std::string::npos || pos_dot >= pos_eq-1)
+ return false;
+ port = input.substr(pos_dot+1, pos_eq-pos_dot-1);
+ node = input.substr(0, pos_dot);
+ return true;
+}
+
+void InitializeSSL()
+{
+ setSSLMode(true);
+ KERNEL::getLauncherSA();
+}
+
+int main (int argc, char* argv[])
{
- struct arguments myArgs;
// Default values.
myArgs.display = 0;
myArgs.verbose = 0;
myArgs.stop = 0;
- myArgs.dumpErrorFile= "";
- myArgs.finalDump = "";
- myArgs.loadState = "";
- myArgs.xmlSchema = "";
+ myArgs.dumpErrorFile= (char *)"";
+ myArgs.finalDump = (char *)"";
+ myArgs.dump = 0;
+ myArgs.loadState = (char *)"";
+ myArgs.xmlSchema = (char *)"";
+ myArgs.shutdown = 1;
+ myArgs.reset = 0;
+ myArgs.killPort = 0;
+ myArgs.init_ports.clear();
// Parse our arguments; every option seen by parse_opt will be reflected in arguments.
+#if defined WIN32 || defined __APPLE__
+#else
argp_parse (&argp, argc, argv, 0, 0, &myArgs);
- cerr << "graph = " << myArgs.args[0]
- << " options: display=" << myArgs.display
- << " verbose="<<myArgs.verbose
- << " stop-on-error=" << myArgs.stop;
+ std::cerr << "graph = " << myArgs.args[0];
+ std::cerr << " options: display=" << myArgs.display;
+ std::cerr << " verbose="<<myArgs.verbose;
+ std::cerr << " stop-on-error=" << myArgs.stop;
+ std::cerr << " shutdown=" << myArgs.shutdown;
+ std::cerr << " reset=" << myArgs.reset;
+ if (myArgs.killPort)
+ std::cerr << " kill-port=" << myArgs.killPort;
if (myArgs.stop)
- cerr << " dumpErrorFile=" << myArgs.dumpErrorFile << endl;
+ std::cerr << " dumpErrorFile=" << myArgs.dumpErrorFile << std::endl;
else
- cerr << endl;
+ std::cerr << std::endl;
+ std::list<std::string>::const_iterator it;
+ for(it=myArgs.init_ports.begin(); it != myArgs.init_ports.end(); it++)
+ {
+ std::cerr << (*it) << std::endl;
+ }
+#endif
+
+#ifndef WIN32
+ setsig(SIGINT,&Handler);
+ setsig(SIGTERM,&Handler);
+#endif
- RuntimeSALOME::setRuntime();
+ InitializeSSL();
+
+ timer("Starting ");
+ long flags = RuntimeSALOME::UsePython + RuntimeSALOME::UseCorba + RuntimeSALOME::UseXml + \
+ RuntimeSALOME::UseCpp + RuntimeSALOME::UseSalome;
+ RuntimeSALOME::setRuntime(flags, argc, argv);
// Try to load the session catalog if it exists
try
CORBA::ORB_ptr orb = runTime->getOrb();
if (orb)
{
- SALOME_NamingService namingService(orb);
+ SALOME_NamingService_Wrapper namingService(orb);
+ //SALOME_NamingService namingService(orb);
CORBA::Object_var obj = namingService.Resolve("/Kernel/ModulCatalog");
SALOME_ModuleCatalog::ModuleCatalog_var aModuleCatalog = SALOME_ModuleCatalog::ModuleCatalog::_narrow(obj);
if (! CORBA::is_nil(aModuleCatalog))
try
{
- Proc* p=loader.load(myArgs.args[0]);
+ timer("Elapsed time before load: ");
+ p=loader.load(myArgs.args[0]);
if(p==0)
{
std::cerr << "The imported file is probably not a YACS schema file" << std::endl;
return 1;
}
+ // Initialize the ports
+ for(std::list<std::string>::iterator it=myArgs.init_ports.begin(); it != myArgs.init_ports.end(); it++)
+ {
+ std::string node, port, value;
+ if(parse_init_port((*it), node, port, value))
+ {
+ std::cerr << "Initialization node=" << node
+ << " port=" << port
+ << " value=" << value << std::endl;
+
+ std::string init_state;
+ init_state = p->setInPortValue(node, port, value);
+ if(value.compare(init_state))
+ {
+ std::cerr << "Error on initialization:" << init_state << std::endl;
+ return 1;
+ }
+ }
+ else
+ {
+ std::cerr << "Error on parsing initialization string:" << (*it) << std::endl;
+ return 1;
+ }
+ }
+
//Get the parser logger
Logger* logger=p->getLogger("parser");
//Print errors logged if any
//Don't execute if there are errors
if(logger->hasErrors())
{
+ if(!p->isValid())
+ {
+ std::string report=p->getErrorReport();
+ std::cerr << "The schema is not valid and can not be executed" << std::endl;
+ std::cerr << report << std::endl;
+ }
delete p;
Runtime* r=YACS::ENGINE::getRuntime();
Dispatcher* disp=Dispatcher::getDispatcher();
delete disp;
return 1;
}
+ timer("Elapsed time after load: ");
if(!p->isValid())
{
delete disp;
return 1;
}
+ timer("Elapsed time after validation: ");
// Check consistency
LinkInfo info(LinkInfo::ALL_DONT_STOP);
delete disp;
return 1;
}
+ timer("Elapsed time after check consistency: ");
//execution
bool isXmlSchema = (strlen(myArgs.xmlSchema) != 0);
stateParser* rootParser = new stateParser();
stateLoader myStateLoader(rootParser, p);
myStateLoader.parse(myArgs.loadState);
+ if(myArgs.reset>0)
+ {
+ p->resetState(myArgs.reset);
+ p->exUpdateState();
+ }
}
if (myArgs.stop)
else
executor.setStopOnError(false, myArgs.dumpErrorFile);
- std::ofstream f("toto");
- p->writeDot(f);
- f.close();
+ if(myArgs.display>0)
+ {
+ std::ofstream f("toto");
+ p->writeDot(f);
+ f.close();
+ }
+ bool isDump = (myArgs.dump != 0);
+ pthread_t th;
+ if (isDump)
+ {
+ thread_st *st = new thread_st;
+ st->nbsec = myArgs.dump;
+ st->dumpFile = string("dumpState_") + myArgs.args[0];
+ string rootFile = st->dumpFile.substr(0,st->dumpFile.find("."));
+ st->lockFile = rootFile + ".lock";
+ pthread_create(&th,NULL,&dumpState,(void*)st);
+ }
+ YACS::ENGINE::LoadObserversPluginIfAny(p,&executor);
cerr << "+++++++++++++++++++ start calculation +++++++++++++++++++" << endl;
executor.RunW(p,myArgs.display, fromScratch);
cerr << "+++++++++++++++++++ end calculation +++++++++++++++++++" << endl;
- cerr << "Proc state : " << p->getEffectiveState() << endl;
+ cerr << "Proc state : " << Node::getStateName(p->getEffectiveState()) << endl;
+ timer("Elapsed time after execution: ");
+
+ // Return 0 if SCHEMA OK
+ // Return 1 for YACS ERROR (EXCEPTION NOT CATCHED)
+ // Return 2 for YACS SCHEMA ERROR/FAILED
+ int return_value = 0;
if(p->getEffectiveState() != YACS::DONE)
{
std::string report=p->getErrorReport();
std::cerr << "Execution has ended in error" << std::endl;
std::cerr << report << std::endl;
+ return_value = 2;
+ }
+
+ if(myArgs.display>0)
+ {
+ std::ofstream g("titi");
+ p->writeDot(g);
+ g.close();
}
- std::ofstream g("titi");
- p->writeDot(g);
- g.close();
+ if (isDump)
+ {
+ pthread_join(th,NULL);
+ }
bool isFinalDump = (strlen(myArgs.finalDump) != 0);
if (isFinalDump)
{
- YACS::ENGINE::VisitorSaveState vst(p);
+ YACS::ENGINE::VisitorSalomeSaveState vst(p);
vst.openFileDump(myArgs.finalDump);
p->accept(&vst);
vst.closeFileDump();
}
+ if(myArgs.shutdown < 999)
+ {
+ p->shutdown(myArgs.shutdown);
+ }
delete p;
Runtime* r=YACS::ENGINE::getRuntime();
Dispatcher* disp=Dispatcher::getDispatcher();
r->fini();
delete r;
delete disp;
- return 0;
+ YACS::ENGINE::UnLoadObserversPluginIfAny();
+ return return_value;
}
catch (YACS::Exception& e)
{
}
catch(CORBA::SystemException& ex)
{
- cerr << "Caught a CORBA::SystemException." ;
+ cerr << "Caught a CORBA::SystemException.:" << __FILE__ << ":" << __LINE__ << ":" ;
CORBA::Any tmp;
tmp <<= ex;
CORBA::TypeCode_var tc = tmp.type();