1 // Copyright (C) 2007-2021 CEA/DEN, EDF R&D, OPEN CASCADE
3 // Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
6 // This library is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU Lesser General Public
8 // License as published by the Free Software Foundation; either
9 // version 2.1 of the License, or (at your option) any later version.
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 // Lesser General Public License for more details.
16 // You should have received a copy of the GNU Lesser General Public
17 // License along with this library; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
23 // SALOME Container : implementation of container and engine for Kernel
24 // File : Container_i.cxx
25 // Author : Paul RASCLE, EDF - MARC TAJCHMAN, CEA
28 //#define private public
33 #include <sys/types.h>
46 #include "utilities.h"
47 #include <SALOMEconfig.h>
48 #include CORBA_SERVER_HEADER(SALOME_Component)
49 #include CORBA_SERVER_HEADER(SALOME_Exception)
50 #include <pthread.h> // must be before Python.h !
51 #include "SALOME_Container_i.hxx"
52 #include "SALOME_Component_i.hxx"
53 #include "SALOME_FileRef_i.hxx"
54 #include "SALOME_FileTransfer_i.hxx"
55 #include "Salome_file_i.hxx"
56 #include "SALOME_NamingService.hxx"
57 #include "SALOME_Fake_NamingService.hxx"
58 #include "SALOME_Embedded_NamingService_Client.hxx"
59 #include "Basics_Utils.hxx"
66 #include "Container_init_python.hxx"
67 #ifdef BOS26455_WITH_BOOST_PYTHON
68 #include <boost/python.hpp>
71 bool _Sleeping = false ;
73 // // Needed by multi-threaded Python --- Supervision
77 extern "C" {void ActSigIntHandler() ; }
79 extern "C" {void SigIntHandler(int, siginfo_t *, void *) ; }
81 extern "C" {void SigIntHandler( int ) ; }
87 #define ENGINESO "Engine.dylib"
89 #define ENGINESO "Engine.so"
93 #define ENGINESO "Engine.dll"
104 std::map<std::string, int> Abstract_Engines_Container_i::_cntInstances_map;
105 std::map<std::string, void *> Abstract_Engines_Container_i::_library_map;
106 std::map<std::string, void *> Abstract_Engines_Container_i::_toRemove_map;
107 omni_mutex Abstract_Engines_Container_i::_numInstanceMutex ;
109 static PyObject* _pyCont;
111 int checkifexecutable(const std::string&);
112 int findpathof(const std::string& path, std::string&, const std::string&);
114 /*! \class Engines_Container_i
115 * \brief C++ implementation of Engines::Container interface
120 //=============================================================================
122 * Default constructor, not for use
124 //=============================================================================
126 Abstract_Engines_Container_i::Abstract_Engines_Container_i () :
127 _NS(nullptr),_id(nullptr),_numInstance(0)
131 //=============================================================================
135 //=============================================================================
137 Abstract_Engines_Container_i::Abstract_Engines_Container_i (CORBA::ORB_ptr orb,
138 PortableServer::POA_ptr poa,
139 char *containerName ,
140 int argc , char* argv[],
141 SALOME_NamingService_Container_Abstract *ns,
142 bool isServantAloneInProcess
144 _NS(nullptr),_id(0),_numInstance(0),_isServantAloneInProcess(isServantAloneInProcess)
146 _pid = (long)getpid();
154 std::string hostname = Kernel_Utils::GetHostname();
156 MESSAGE(hostname << " " << getpid() <<
157 " Engines_Container_i starting argc " <<
158 _argc << " Thread " << pthread_self() ) ;
160 MESSAGE(hostname << " " << _getpid() <<
161 " Engines_Container_i starting argc " << _argc<< " Thread " << pthread_self().p ) ;
167 MESSAGE(" argv" << i << " " << _argv[ i ]) ;
173 INFOS("SALOME_Container usage : SALOME_Container ServerName");
177 _isSupervContainer = false;
179 _orb = CORBA::ORB::_duplicate(orb) ;
180 _poa = PortableServer::POA::_duplicate(poa) ;
182 // Pour les containers paralleles: il ne faut pas enregistrer et activer
183 // le container generique, mais le container specialise
186 _id = _poa->activate_object(this);
187 // key point : if ns is nullptr : this servant is alone in its process
188 // if ns is not null : this servant embedded into single process.
189 _NS = ns==nullptr ? new SALOME_NamingService : ns->clone();
190 _NS->init_orb( _orb ) ;
191 CORBA::Object_var obj=_poa->id_to_reference(*_id);
192 Engines::Container_var pCont = Engines::Container::_narrow(obj);
195 _containerName = SALOME_NamingService_Abstract::BuildContainerNameForNS(containerName, hostname.c_str());
196 SCRUTE(_containerName);
197 _NS->Register(pCont, _containerName.c_str());
198 MESSAGE("Engines_Container_i::Engines_Container_i : Container name " << _containerName);
201 // import SALOME_Container
202 // pycont = SALOME_Container.SALOME_Container_i(containerIORStr)
204 CORBA::String_var sior = _orb->object_to_string(pCont);
205 std::string myCommand="pyCont = SALOME_Container.SALOME_Container_i('";
206 myCommand += _containerName + "','";
211 //[RNV]: Comment the PyEval_AcquireLock() and PyEval_ReleaseLock() because this
212 //approach leads to the deadlock of the main thread of the application on Windows platform
213 //in case if cppContainer runs in the standalone mode. The problem with the PyThreadState
214 //described by ABN seems not reproduced, to be checked carefully later...
215 PyGILState_STATE gstate = PyGILState_Ensure();
217 //// [ABN]: using the PyGILState* API here is unstable. omniORB logic is invoked
218 //// by the Python code executed below, and in some (random) cases, the Python code
219 //// execution ends with a PyThreadState which was not the one we have here.
220 //// (TODO: understand why ...)
221 //// To be on the safe side we get and load the thread state ourselves:
222 //PyEval_AcquireLock(); // get GIL
223 //PyThreadState * mainThreadState = PyThreadState_Get();
224 //PyThreadState_Swap(mainThreadState);
227 // mpv: this is temporary solution: there is a unregular crash if not
230 // first element is the path to Registry.dll, but it's wrong
231 PyRun_SimpleString("import sys\n");
232 PyRun_SimpleString("sys.path = sys.path[1:]\n");
234 PyRun_SimpleString("import SALOME_Container\n");
235 PyRun_SimpleString((char*)myCommand.c_str());
236 PyObject *mainmod = PyImport_AddModule("__main__");
237 PyObject *globals = PyModule_GetDict(mainmod);
238 _pyCont = PyDict_GetItemString(globals, "pyCont");
240 //PyThreadState_Swap(NULL);
241 //PyEval_ReleaseLock();
242 PyGILState_Release(gstate);
244 fileTransfer_i* aFileTransfer = new fileTransfer_i();
245 CORBA::Object_var obref=aFileTransfer->_this();
246 _fileTransfer = Engines::fileTransfer::_narrow(obref);
247 aFileTransfer->_remove_ref();
251 //=============================================================================
255 //=============================================================================
257 Abstract_Engines_Container_i::~Abstract_Engines_Container_i()
259 MESSAGE("Abstract_Container_i::~Abstract_Container_i()");
267 //=============================================================================
268 //! Get container name
270 * CORBA attribute: Container name (see constructor)
272 //=============================================================================
274 char* Abstract_Engines_Container_i::name()
276 return CORBA::string_dup(_containerName.c_str()) ;
279 //=============================================================================
280 //! Get container working directory
282 * CORBA attribute: Container working directory
284 //=============================================================================
286 char* Abstract_Engines_Container_i::workingdir()
290 return CORBA::string_dup(wd) ;
293 //=============================================================================
294 //! Get container log file name
296 * CORBA attribute: Container log file name
298 //=============================================================================
300 char* Abstract_Engines_Container_i::logfilename()
302 return CORBA::string_dup(_logfilename.c_str()) ;
305 //! Set container log file name
306 void Abstract_Engines_Container_i::logfilename(const char* name)
311 //=============================================================================
312 //! Get container host name
314 * CORBA method: Get the hostName of the Container (without domain extensions)
316 //=============================================================================
318 char* Abstract_Engines_Container_i::getHostName()
320 std::string s = Kernel_Utils::GetHostname();
321 // MESSAGE("Engines_Container_i::getHostName " << s);
322 return CORBA::string_dup(s.c_str()) ;
325 //=============================================================================
326 //! Get container PID
328 * CORBA method: Get the PID (process identification) of the Container
330 //=============================================================================
332 CORBA::Long Abstract_Engines_Container_i::getPID()
334 return (CORBA::Long)getpid();
337 //=============================================================================
338 //! Ping the servant to check it is still alive
340 * CORBA method: check if servant is still alive
342 //=============================================================================
343 void Abstract_Engines_Container_i::ping()
345 MESSAGE("Engines_Container_i::ping() pid "<< getpid());
348 //=============================================================================
349 //! Get number of CPU cores in the calculation node
351 * CORBA method: get number of CPU cores
353 //=============================================================================
355 CORBA::Long Abstract_Engines_Container_i::getNumberOfCPUCores()
357 PyGILState_STATE gstate = PyGILState_Ensure();
358 PyObject *module = PyImport_ImportModuleNoBlock((char*)"salome_psutil");
359 PyObject *result = PyObject_CallMethod(module,
360 (char*)"getNumberOfCPUCores", NULL);
361 int n = PyLong_AsLong(result);
363 PyGILState_Release(gstate);
365 return (CORBA::Long)n;
368 //=============================================================================
369 //! Get a load of each CPU core in the calculation node
371 * CORBA method: get a load of each CPU core
373 //=============================================================================
375 std::string parseException()
378 if (PyErr_Occurred())
380 #ifdef BOS26455_WITH_BOOST_PYTHON
381 PyObject *ptype = nullptr;
382 PyObject *pvalue = nullptr;
383 PyObject *ptraceback = nullptr;
384 PyErr_Fetch(&ptype, &pvalue, &ptraceback);
385 if (ptype == nullptr)
386 return std::string("Null exception type");
387 PyErr_NormalizeException(&ptype, &pvalue, &ptraceback);
388 if (ptraceback != nullptr)
389 PyException_SetTraceback(pvalue, ptraceback);
390 boost::python::handle<> htype(ptype);
391 boost::python::handle<> hvalue(boost::python::allow_null(pvalue));
392 boost::python::handle<> htraceback(boost::python::allow_null(ptraceback));
393 boost::python::object traceback = boost::python::import("traceback");
394 boost::python::object format_exc = traceback.attr("format_exception");
395 boost::python::object formatted = format_exc(htype, hvalue, htraceback);
396 error = boost::python::extract<std::string>(boost::python::str("\n").join(formatted));
398 error = "Python exception is caught";
405 Engines::vectorOfDouble* Abstract_Engines_Container_i::loadOfCPUCores()
407 PyGILState_STATE gstate = PyGILState_Ensure();
408 PyObject *module = PyImport_ImportModuleNoBlock((char*)"salome_psutil");
409 PyObject *result = PyObject_CallMethod(module,
410 (char*)"loadOfCPUCores", "s",
411 _load_script.c_str());
412 if (PyErr_Occurred())
414 std::string error = parseException();
416 PyGILState_Release(gstate);
417 SALOME::ExceptionStruct es;
418 es.type = SALOME::INTERNAL_ERROR;
419 es.text = CORBA::string_dup(error.c_str());
420 throw SALOME::SALOME_Exception(es);
423 int n = this->getNumberOfCPUCores();
424 if (!PyList_Check(result) || PyList_Size(result) != n) {
425 // bad number of cores
426 PyGILState_Release(gstate);
428 SALOME::ExceptionStruct es;
429 es.type = SALOME::INTERNAL_ERROR;
430 es.text = "wrong number of cores";
431 throw SALOME::SALOME_Exception(es);
434 Engines::vectorOfDouble_var loads = new Engines::vectorOfDouble;
436 for (Py_ssize_t i = 0; i < PyList_Size(result); ++i) {
437 PyObject* item = PyList_GetItem(result, i);
438 double foo = PyFloat_AsDouble(item);
439 if (foo < 0.0 || foo > 1.0)
441 // value not in [0, 1] range
442 PyGILState_Release(gstate);
444 SALOME::ExceptionStruct es;
445 es.type = SALOME::INTERNAL_ERROR;
446 es.text = "load not in [0, 1] range";
447 throw SALOME::SALOME_Exception(es);
453 PyGILState_Release(gstate);
455 return loads._retn();
458 //=============================================================================
459 //! Set custom script to calculate a load of each CPU core
461 * CORBA method: Set custom script to calculate CPU load
462 * \param script Python script to execute
464 //=============================================================================
466 void Abstract_Engines_Container_i::setPyScriptForCPULoad(const char *script)
468 _load_script = script;
471 //=============================================================================
472 //! Nullify custom script to calculate each CPU core's load
474 * CORBA method: reset script for load calculation to default implementation
476 //=============================================================================
478 void Abstract_Engines_Container_i::resetScriptForCPULoad()
483 //=============================================================================
484 //! Get total physical memory of calculation node, in megabytes
486 * CORBA method: get total physical memory of calculation node
488 //=============================================================================
490 CORBA::Long Abstract_Engines_Container_i::getTotalPhysicalMemory()
492 PyGILState_STATE gstate = PyGILState_Ensure();
493 PyObject *module = PyImport_ImportModuleNoBlock((char*)"salome_psutil");
494 PyObject *result = PyObject_CallMethod(module,
495 (char*)"getTotalPhysicalMemory", NULL);
496 int n = PyLong_AsLong(result);
498 PyGILState_Release(gstate);
500 return (CORBA::Long)n;
503 //=============================================================================
504 //! Get used physical memory of calculation node, in megabytes
506 * CORBA method: get used physical memory of calculation node
508 //=============================================================================
510 CORBA::Long Abstract_Engines_Container_i::getTotalPhysicalMemoryInUse()
512 PyGILState_STATE gstate = PyGILState_Ensure();
513 PyObject *module = PyImport_ImportModuleNoBlock((char*)"salome_psutil");
514 PyObject *result = PyObject_CallMethod(module,
515 (char*)"getTotalPhysicalMemoryInUse", NULL);
516 int n = PyLong_AsLong(result);
518 PyGILState_Release(gstate);
520 return (CORBA::Long)n;
523 //=============================================================================
524 //! Obtain physical memory, used by the current process, in megabytes.
526 * CORBA method: get physical memory, used by the current process
528 //=============================================================================
530 CORBA::Long Abstract_Engines_Container_i::getTotalPhysicalMemoryInUseByMe()
532 PyGILState_STATE gstate = PyGILState_Ensure();
533 PyObject *module = PyImport_ImportModuleNoBlock((char*)"salome_psutil");
534 PyObject *result = PyObject_CallMethod(module,
535 (char*)"getTotalPhysicalMemoryInUseByMe", NULL);
536 int n = PyLong_AsLong(result);
538 PyGILState_Release(gstate);
540 return (CORBA::Long)n;
543 //=============================================================================
544 //! Shutdown the container
546 * CORBA method, oneway: Server shutdown.
547 * - Container name removed from naming service,
548 * - servant deactivation,
549 * - orb shutdown if no other servants in the process
551 //=============================================================================
552 void Abstract_Engines_Container_i::Shutdown()
554 MESSAGE("Engines_Container_i::Shutdown()");
556 // Clear registered temporary files
557 clearTemporaryFiles();
559 /* For each component contained in this container
560 * tell it to self-destroy
562 std::map<std::string, Engines::EngineComponent_var>::iterator itm;
563 for (itm = _listInstances_map.begin(); itm != _listInstances_map.end(); itm++)
567 itm->second->destroy();
569 catch(const CORBA::Exception&)
571 // ignore this entry and continue
575 // ignore this entry and continue
578 _listInstances_map.clear();
580 // NS unregistering may throw in SSL mode if master process hosting SALOME_Embedded_NamingService servant has vanished
581 // In this case it's skip it and still continue.
584 _NS->Destroy_FullDirectory(_containerName.c_str());
585 _NS->Destroy_Name(_containerName.c_str());
591 this->cleanAllPyScripts();
593 if(_isServantAloneInProcess)
595 MESSAGE("Effective Shutdown of container Begins...");
596 if(!CORBA::is_nil(_orb))
601 //=============================================================================
602 //! load a component implementation
605 * \param componentName component name
606 * \param reason explains error when load fails
607 * \return true if dlopen successful or already done, false otherwise
609 //=============================================================================
611 Abstract_Engines_Container_i::load_component_Library(const char* componentName, CORBA::String_out reason)
614 //=================================================================
615 // --- C++ implementation section
616 //=================================================================
618 if(load_component_CppImplementation(componentName,retso))
620 reason=CORBA::string_dup("");
623 else if(retso != "ImplementationNotFound")
625 reason=CORBA::string_dup(retso.c_str());
630 retso+=componentName;
631 retso+=": Can't find C++ implementation ";
632 retso+=std::string(LIB) + componentName + ENGINESO;
634 //=================================================================
635 // --- Python implementation section
636 //=================================================================
638 if(load_component_PythonImplementation(componentName,retpy))
640 reason=CORBA::string_dup("");
643 else if(retpy != "ImplementationNotFound")
645 reason=CORBA::string_dup(retpy.c_str());
650 retpy+=componentName;
651 retpy+=": Can't find python implementation ";
652 retpy+=componentName;
655 //=================================================================
656 // -- Executable implementation section
657 //=================================================================
659 if(load_component_ExecutableImplementation(componentName,retex))
661 reason=CORBA::string_dup("");
664 else if(retex != "ImplementationNotFound")
666 reason=CORBA::string_dup(retex.c_str());
671 retex+=componentName;
672 retex+=": Can't find executable implementation ";
673 retex+=componentName;
676 std::string ret="Component implementation not found: ";
677 ret += componentName ;
683 std::cerr << ret << std::endl;
684 reason=CORBA::string_dup(ret.c_str());
689 //=============================================================================
690 //! try to load a C++ component implementation
693 * \param componentName the name of the component (COMPONENT, for example)
694 * \param reason explains error when load fails
695 * \return true if loading is successful or already done, false otherwise
697 //=============================================================================
699 Abstract_Engines_Container_i::load_component_CppImplementation(const char* componentName, std::string& reason)
701 std::string aCompName(componentName);
702 std::string impl_name = std::string(LIB) + aCompName + ENGINESO;
705 _numInstanceMutex.lock(); // lock to be alone
706 // (see decInstanceCnt, finalize_removal))
707 if (_toRemove_map.count(impl_name) != 0) _toRemove_map.erase(impl_name);
708 if (_library_map.count(impl_name) != 0)
710 MESSAGE("Library " << impl_name << " already loaded");
711 _numInstanceMutex.unlock();
715 _numInstanceMutex.unlock();
719 handle = dlopen( impl_name.c_str() , RTLD_NOW | RTLD_GLOBAL ) ;
722 //not loadable. Try to find the lib file in LD_LIBRARY_PATH
725 char* p=getenv("DYLD_LIBRARY_PATH");
727 char* p=getenv("LD_LIBRARY_PATH");
730 path=path+SEP+"/usr/lib"+SEP+"/lib";
733 if(findpathof(path, pth, impl_name))
735 //found but not loadable
738 reason+=": C++ implementation found ";
740 reason+=" but it is not loadable. Error:\n";
742 std::cerr << reason << std::endl;
748 //continue with other implementation
749 reason="ImplementationNotFound";
756 std::wstring libToLoad = Kernel_Utils::utf8_decode_s( impl_name );
758 std::string libToLoad = impl_name;
760 handle = LoadLibrary(libToLoad.c_str() );
763 reason="ImplementationNotFound";
769 _numInstanceMutex.lock();
770 _library_map[impl_name] = handle;
771 _numInstanceMutex.unlock();
779 //=============================================================================
780 //! try to load a Python component implementation
783 * \param componentName name of the component
784 * \param reason explains error when load fails
785 * \return true if loading is successful or already done, false otherwise
787 //=============================================================================
789 Abstract_Engines_Container_i::load_component_PythonImplementation(const char* componentName, std::string& reason)
791 std::string aCompName(componentName);
793 _numInstanceMutex.lock() ; // lock to be alone (stl container write)
794 if (_library_map.count(aCompName) != 0)
796 _numInstanceMutex.unlock() ;
798 return true; // Python Component, already imported
800 _numInstanceMutex.unlock() ;
802 PyGILState_STATE gstate = PyGILState_Ensure();
803 PyObject *result = PyObject_CallMethod(_pyCont,
804 (char*)"import_component",
805 (char*)"s",componentName);
807 reason=PyUnicode_AsUTF8(result);
810 PyGILState_Release(gstate);
814 //Python component has been loaded (import componentName)
815 _numInstanceMutex.lock() ; // lock to be alone (stl container write)
816 _library_map[aCompName] = (void *)_pyCont; // any non O value OK
817 _numInstanceMutex.unlock() ;
818 MESSAGE("import Python: "<< aCompName <<" OK");
821 else if(reason=="ImplementationNotFound")
823 //Python implementation has not been found. Continue with other implementation
824 reason="ImplementationNotFound";
828 //Python implementation has been found but loading has failed
829 std::cerr << reason << std::endl;
834 //=============================================================================
835 //! try to load a Executable component implementation
838 * \param componentName name of the component
839 * \param reason explains error when load fails
840 * \return true if loading is successful or already done, false otherwise
842 //=============================================================================
844 Abstract_Engines_Container_i::load_component_ExecutableImplementation(const char* componentName, std::string& reason)
846 std::string aCompName(componentName);
847 std::string executable=aCompName+".exe";
852 char* p=getenv("PATH");
855 if (findpathof(path, pth, executable))
857 if(checkifexecutable(pth))
859 _numInstanceMutex.lock() ; // lock to be alone (stl container write)
860 _library_map[executable] = (void *)1; // any non O value OK
861 _numInstanceMutex.unlock() ;
862 MESSAGE("import executable: "<< pth <<" OK");
868 reason+=": implementation found ";
870 reason+=" but it is not executable";
871 std::cerr << reason << std::endl;
875 reason="ImplementationNotFound";
880 //=============================================================================
881 //! Create a new component instance
883 * CORBA method: Creates a new servant instance of a component.
884 * The servant registers itself to naming service and Registry.
885 * \param genericRegisterName Name of the component instance to register
886 * in Registry & Name Service (without _inst_n suffix)
887 * \return a loaded component
889 //=============================================================================
890 Engines::EngineComponent_ptr
891 Abstract_Engines_Container_i::create_component_instance(const char*genericRegisterName)
893 Engines::FieldsDict_var env = new Engines::FieldsDict;
895 Engines::EngineComponent_ptr compo =
896 create_component_instance_env(genericRegisterName, env, reason);
897 CORBA::string_free(reason);
901 //=============================================================================
902 //! Create a new component instance with environment variables specified
904 * CORBA method: Creates a new servant instance of a component.
905 * The servant registers itself to naming service and Registry.
906 * \param genericRegisterName Name of the component instance to register
907 * in Registry & Name Service (without _inst_n suffix)
908 * \param env dict of env variables
909 * \param reason explains error when create_component_instance_env fails
910 * \return a loaded component
912 //=============================================================================
913 Engines::EngineComponent_ptr
914 Abstract_Engines_Container_i::create_component_instance_env(const char*genericRegisterName,
915 const Engines::FieldsDict& env,
916 CORBA::String_out reason)
919 if (_library_map.count(genericRegisterName) != 0)
921 // It's a Python component
922 Engines::EngineComponent_ptr compo = createPythonInstance(genericRegisterName, error);
923 reason=CORBA::string_dup(error.c_str());
927 std::string impl_name = std::string(LIB) + genericRegisterName + ENGINESO;
928 if (_library_map.count(impl_name) != 0)
930 // It's a C++ component
931 void* handle = _library_map[impl_name];
932 Engines::EngineComponent_ptr compo = createInstance(genericRegisterName, handle, error);
933 reason=CORBA::string_dup(error.c_str());
937 impl_name = std::string(genericRegisterName) + ".exe";
938 if (_library_map.count(impl_name) != 0)
940 //It's an executable component
941 Engines::EngineComponent_ptr compo = createExecutableInstance(genericRegisterName, env, error);
942 reason=CORBA::string_dup(error.c_str());
946 error="load_component_Library has probably not been called for component: ";
947 error += genericRegisterName;
949 reason=CORBA::string_dup(error.c_str());
950 return Engines::EngineComponent::_nil() ;
953 //=============================================================================
954 //! Create a new component instance (Executable implementation)
956 * \param CompName Name of the component instance
957 * \param env dict of env variables
958 * \param reason explains error when creation fails
959 * \return a loaded component
961 * This component is implemented in an executable with name genericRegisterName.exe
962 * It must register itself in Naming Service. The container waits some time (10 s max)
965 //=============================================================================
966 Engines::EngineComponent_ptr
967 Abstract_Engines_Container_i::createExecutableInstance(std::string CompName,
968 const Engines::FieldsDict& env,
971 Engines::EngineComponent_var iobject = Engines::EngineComponent::_nil() ;
973 _numInstanceMutex.lock() ; // lock on the instance number
975 int numInstance = _numInstance ;
976 _numInstanceMutex.unlock() ;
979 sprintf( aNumI , "%d" , numInstance ) ;
980 std::string instanceName = CompName + "_inst_" + aNumI ;
981 std::string component_registerName = _containerName + "/" + instanceName;
983 //check if an entry exist in naming service
984 CORBA::Object_var nsobj = _NS->Resolve(component_registerName.c_str());
985 if ( !CORBA::is_nil(nsobj) )
987 // unregister the registered component
988 _NS->Destroy_Name(component_registerName.c_str());
989 //kill or shutdown it ???
992 // first arg container ior string
993 // second arg container name
994 // third arg instance name
996 Engines::Container_var pCont= _this();
997 CORBA::String_var sior = _orb->object_to_string(pCont);
1000 command="mkdir -p ";
1001 command+=instanceName;
1003 command+=instanceName;
1008 command+= sior; // container ior string
1010 command+=_containerName; //container name
1012 command+=instanceName; //instance name
1014 MESSAGE("SALOME_Container::create_component_instance command=" << command);
1017 // use fork/execl instead of system to get finer control on env variables
1020 if(pid == 0) // child
1022 for (CORBA::ULong i=0; i < env.length(); i++)
1024 if (env[i].value.type()->kind() == CORBA::tk_string)
1027 env[i].value >>= value;
1028 std::string s(env[i].key);
1031 putenv(strdup(s.c_str()));
1035 execl("/bin/sh", "sh", "-c", command.c_str() , (char *)0);
1038 else if(pid < 0) // failed to fork
1047 tpid = wait(&status);
1048 } while (tpid != pid);
1051 // launch component with a system call
1052 int status=system(command.c_str());
1057 reason="SALOME_Container::create_component_instance system failed (system command status -1)";
1059 return Engines::EngineComponent::_nil();
1062 else if (WEXITSTATUS(status) == 217)
1064 reason="SALOME_Container::create_component_instance system failed (system command status 217)";
1066 return Engines::EngineComponent::_nil();
1072 if (getenv("TIMEOUT_TO_WAIT_EXE_COMPONENT") != 0)
1074 std::string new_count_str = getenv("TIMEOUT_TO_WAIT_EXE_COMPONENT");
1076 std::istringstream ss(new_count_str);
1077 if (!(ss >> new_count))
1079 INFOS("[Container] TIMEOUT_TO_WAIT_EXE_COMPONENT should be an int");
1084 INFOS("[Container] waiting " << count << " second steps exe component ");
1085 CORBA::Object_var obj = CORBA::Object::_nil() ;
1086 while ( CORBA::is_nil(obj) && count )
1094 MESSAGE( count << ". Waiting for component " << CompName);
1095 obj = _NS->Resolve(component_registerName.c_str());
1098 if(CORBA::is_nil(obj))
1100 reason="SALOME_Container::create_component_instance failed";
1102 return Engines::EngineComponent::_nil();
1106 MESSAGE("SALOME_Container::create_component_instance successful");
1107 iobject = Engines::EngineComponent::_narrow(obj);
1108 _listInstances_map[instanceName] = iobject;
1109 return iobject._retn();
1115 //=============================================================================
1116 //! Create a new component instance (Python implementation)
1118 * \param CompName Name of the component instance
1119 * \param reason explains error when creation fails
1120 * \return a loaded component
1122 //=============================================================================
1123 Engines::EngineComponent_ptr
1124 Abstract_Engines_Container_i::createPythonInstance(std::string CompName,
1125 std::string& reason)
1127 Engines::EngineComponent_var iobject = Engines::EngineComponent::_nil() ;
1129 _numInstanceMutex.lock() ; // lock on the instance number
1131 int numInstance = _numInstance ;
1132 _numInstanceMutex.unlock() ;
1135 sprintf( aNumI , "%d" , numInstance ) ;
1136 std::string instanceName = CompName + "_inst_" + aNumI ;
1137 std::string component_registerName = _containerName + "/" + instanceName;
1139 PyGILState_STATE gstate = PyGILState_Ensure();
1140 PyObject *result = PyObject_CallMethod(_pyCont,
1141 (char*)"create_component_instance",
1144 instanceName.c_str());
1147 PyArg_ParseTuple(result,"ss", &ior, &error);
1148 std::string iors = ior;
1151 PyGILState_Release(gstate);
1155 CORBA::Object_var obj = _orb->string_to_object(iors.c_str());
1156 iobject = Engines::EngineComponent::_narrow( obj ) ;
1157 _listInstances_map[instanceName] = iobject;
1159 return iobject._retn();
1163 Abstract_Engines_Container_i::create_python_service_instance(const char * CompName,
1164 CORBA::String_out reason)
1166 CORBA::Object_var object = CORBA::Object::_nil();
1168 _numInstanceMutex.lock() ; // lock on the instance number
1170 int numInstance = _numInstance ;
1171 _numInstanceMutex.unlock() ;
1174 sprintf( aNumI , "%d" , numInstance ) ;
1175 std::string instanceName = std::string(CompName) + "_inst_" + aNumI ;
1176 std::string component_registerName = _containerName + "/" + instanceName;
1178 PyGILState_STATE gstate = PyGILState_Ensure();
1179 PyObject *result = PyObject_CallMethod(_pyCont,
1180 (char*)"create_component_instance",
1183 instanceName.c_str());
1186 PyArg_ParseTuple(result,"ss", &ior, &error);
1187 reason = CORBA::string_dup(error);
1188 char * _ior = CORBA::string_dup(ior);
1190 PyGILState_Release(gstate);
1196 //=============================================================================
1197 //! Create a new component instance (C++ implementation)
1199 * C++ method: create a servant instance of a component.
1200 * \param genericRegisterName Name of the component instance to register
1201 * in Registry & Name Service,
1202 * (without _inst_n suffix, like "COMPONENT")
1203 * \param handle loaded library handle
1204 * \param reason explains error when creation fails
1205 * \return a loaded component
1207 * example with names:
1208 * - aGenRegisterName = COMPONENT (= first argument)
1209 * - _containerName = /Containers/cli76ce/FactoryServer
1210 * - factoryName = COMPONENTEngine_factory
1211 * - component_registerBase = /Containers/cli76ce/FactoryServer/COMPONENT
1212 * - instanceName = COMPONENT_inst_1
1213 * - component_registerName = /Containers/cli76ce/FactoryServer/COMPONENT_inst_1
1215 //=============================================================================
1216 Engines::EngineComponent_ptr
1217 Abstract_Engines_Container_i::createInstance(std::string genericRegisterName,
1219 std::string& reason)
1221 // --- find the factory
1223 std::string aGenRegisterName = genericRegisterName;
1224 std::string factory_name = aGenRegisterName + std::string("Engine_factory");
1225 SCRUTE(factory_name) ;
1227 typedef PortableServer::ObjectId* (*FACTORY_FUNCTION) (CORBA::ORB_ptr,
1228 PortableServer::POA_ptr,
1229 PortableServer::ObjectId *,
1234 FACTORY_FUNCTION Component_factory = (FACTORY_FUNCTION)dlsym( handle, factory_name.c_str() );
1236 FACTORY_FUNCTION Component_factory = (FACTORY_FUNCTION)GetProcAddress( (HINSTANCE)handle, factory_name.c_str() );
1239 if ( !Component_factory )
1241 MESSAGE( "Can't resolve symbol: " + factory_name );
1246 return Engines::EngineComponent::_nil() ;
1249 // --- create instance
1251 Engines::EngineComponent_var iobject = Engines::EngineComponent::_nil() ;
1255 _numInstanceMutex.lock() ; // lock on the instance number
1257 int numInstance = _numInstance ;
1258 _numInstanceMutex.unlock() ;
1261 sprintf( aNumI , "%d" , numInstance ) ;
1262 std::string instanceName = aGenRegisterName + "_inst_" + aNumI ;
1263 std::string component_registerName =
1264 _containerName + "/" + instanceName;
1266 // --- Instantiate required CORBA object
1268 PortableServer::ObjectId *id ; //not owner, do not delete (nore use var)
1269 id = (Component_factory) ( _orb, _poa, _id, instanceName.c_str(),
1270 aGenRegisterName.c_str() ) ;
1273 reason="Can't get ObjectId from factory";
1275 return iobject._retn();
1278 // --- get reference from id
1280 CORBA::Object_var obj = _poa->id_to_reference(*id);
1281 iobject = Engines::EngineComponent::_narrow( obj ) ;
1283 _numInstanceMutex.lock() ; // lock to be alone (stl container write)
1284 _listInstances_map[instanceName] = iobject;
1285 _cntInstances_map[aGenRegisterName] += 1;
1286 _numInstanceMutex.unlock() ;
1287 SCRUTE(aGenRegisterName);
1288 SCRUTE(_cntInstances_map[aGenRegisterName]);
1290 // --- register the engine under the name
1291 // containerName(.dir)/instanceName(.object)
1293 _NS->Register( iobject , component_registerName.c_str() ) ;
1294 MESSAGE( component_registerName.c_str() << " bound" ) ;
1298 reason="Container_i::createInstance exception caught";
1301 return iobject._retn();
1304 //=============================================================================
1305 //! Find an existing (in the container) component instance
1307 * CORBA method: Finds a servant instance of a component
1308 * \param registeredName Name of the component in Registry or Name Service,
1309 * without instance suffix number
1310 * \return the first found instance
1312 //=============================================================================
1313 Engines::EngineComponent_ptr
1314 Abstract_Engines_Container_i::find_component_instance( const char* registeredName)
1316 Engines::EngineComponent_var anEngine = Engines::EngineComponent::_nil();
1317 std::map<std::string,Engines::EngineComponent_var>::iterator itm =_listInstances_map.begin();
1318 while (itm != _listInstances_map.end())
1320 std::string instance = (*itm).first;
1322 if (instance.find(registeredName) == 0)
1324 anEngine = (*itm).second;
1325 return anEngine._retn();
1329 return anEngine._retn();
1332 //=============================================================================
1333 //! Remove the component instance from container
1335 * CORBA method: Stops the component servant, and deletes all related objects
1336 * \param component_i Component to be removed
1338 //=============================================================================
1340 void Abstract_Engines_Container_i::remove_impl(Engines::EngineComponent_ptr component_i)
1342 ASSERT(! CORBA::is_nil(component_i));
1343 std::string instanceName = component_i->instanceName() ;
1344 MESSAGE("unload component " << instanceName);
1345 _numInstanceMutex.lock() ; // lock to be alone (stl container write)
1346 _listInstances_map.erase(instanceName);
1347 _numInstanceMutex.unlock() ;
1348 component_i->destroy() ;
1349 _NS->Destroy_Name(instanceName.c_str());
1352 //=============================================================================
1353 //! Unload component libraries from the container
1355 * CORBA method: Discharges unused libraries from the container.
1357 //=============================================================================
1358 void Abstract_Engines_Container_i::finalize_removal()
1360 MESSAGE("finalize unload : dlclose");
1361 _numInstanceMutex.lock(); // lock to be alone
1362 // (see decInstanceCnt, load_component_Library)
1363 std::map<std::string, void *>::iterator ith;
1364 for (ith = _toRemove_map.begin(); ith != _toRemove_map.end(); ith++)
1366 void *handle = (*ith).second;
1367 std::string impl_name= (*ith).first;
1372 // dlclose(handle); // SALOME unstable after ...
1373 // _library_map.erase(impl_name);
1376 _toRemove_map.clear();
1377 _numInstanceMutex.unlock();
1380 //=============================================================================
1381 //! Decrement component instance reference count
1385 //=============================================================================
1386 void Abstract_Engines_Container_i::decInstanceCnt(std::string genericRegisterName)
1388 if(_cntInstances_map.count(genericRegisterName)==0)
1390 std::string aGenRegisterName =genericRegisterName;
1391 MESSAGE("Engines_Container_i::decInstanceCnt " << aGenRegisterName);
1392 ASSERT(_cntInstances_map[aGenRegisterName] > 0);
1393 _numInstanceMutex.lock(); // lock to be alone
1394 // (see finalize_removal, load_component_Library)
1395 _cntInstances_map[aGenRegisterName] -= 1;
1396 SCRUTE(_cntInstances_map[aGenRegisterName]);
1397 if (_cntInstances_map[aGenRegisterName] == 0)
1399 std::string impl_name =
1400 Engines_Component_i::GetDynLibraryName(aGenRegisterName.c_str());
1402 void* handle = _library_map[impl_name];
1404 _toRemove_map[impl_name] = handle;
1406 _numInstanceMutex.unlock();
1409 //=============================================================================
1410 //! Find or create a new component instance
1412 * CORBA method: find or create an instance of the component (servant),
1413 * load a new component class (dynamic library) if required,
1415 * ---- FOR COMPATIBILITY WITH 2.2 ----
1417 * ---- USE ONLY FOR MULTISTUDY INSTANCES ! --------
1419 * The servant registers itself to naming service and Registry.
1420 * \param genericRegisterName Name of the component to register
1421 * in Registry & Name Service
1422 * \param componentName Name of the constructed library of the component
1423 * \return a loaded component
1425 //=============================================================================
1427 Engines::EngineComponent_ptr
1428 Abstract_Engines_Container_i::load_impl( const char* genericRegisterName,
1429 const char* /*componentName*/ )
1432 std::string impl_name = std::string(LIB) + genericRegisterName + ENGINESO;
1433 Engines::EngineComponent_var iobject = Engines::EngineComponent::_nil() ;
1434 if (load_component_Library(genericRegisterName,reason))
1435 iobject = find_or_create_instance(genericRegisterName, impl_name);
1436 CORBA::string_free(reason);
1437 return iobject._retn();
1440 Engines::EmbeddedNamingService_ptr Abstract_Engines_Container_i::get_embedded_NS_if_ssl()
1442 SALOME_Embedded_NamingService_Client *nsc(dynamic_cast<SALOME_Embedded_NamingService_Client *>(this->_NS));
1445 Engines::EmbeddedNamingService_var obj = nsc->GetObject();
1446 return Engines::EmbeddedNamingService::_duplicate(obj);
1450 return Engines::EmbeddedNamingService::_nil();
1454 //=============================================================================
1455 //! Finds an already existing component instance or create a new instance
1457 * C++ method: Finds an already existing servant instance of a component, or
1458 * create an instance.
1459 * ---- USE ONLY FOR MULTISTUDY INSTANCES ! --------
1460 * \param genericRegisterName Name of the component instance to register
1461 * in Registry & Name Service,
1462 * (without _inst_n suffix, like "COMPONENT")
1463 * \param componentLibraryName like "libCOMPONENTEngine.so"
1464 * \return a loaded component
1466 * example with names:
1467 * - aGenRegisterName = COMPONENT (= first argument)
1468 * - impl_name = libCOMPONENTEngine.so (= second argument)
1469 * - _containerName = /Containers/cli76ce/FactoryServer
1470 * - factoryName = COMPONENTEngine_factory
1471 * - component_registerBase = /Containers/cli76ce/FactoryServer/COMPONENT
1472 * - instanceName = COMPONENT_inst_1
1473 * - component_registerName = /Containers/cli76ce/FactoryServer/COMPONENT_inst_1
1475 //=============================================================================
1477 Engines::EngineComponent_ptr
1478 Abstract_Engines_Container_i::find_or_create_instance(std::string genericRegisterName,
1479 std::string componentLibraryName)
1481 std::string aGenRegisterName = genericRegisterName;
1482 std::string impl_name = componentLibraryName;
1483 if (_library_map.count(impl_name) == 0)
1485 INFOS("shared library " << impl_name <<" must be loaded before creating instance");
1486 return Engines::EngineComponent::_nil() ;
1490 // --- find a registered instance in naming service, or create
1492 void* handle = _library_map[impl_name];
1493 std::string component_registerBase =
1494 _containerName + "/" + aGenRegisterName;
1495 Engines::EngineComponent_var iobject = Engines::EngineComponent::_nil() ;
1499 CORBA::Object_var obj =
1500 _NS->ResolveFirst( component_registerBase.c_str());
1501 if ( CORBA::is_nil( obj ) )
1503 iobject = createInstance(genericRegisterName,
1509 iobject = Engines::EngineComponent::_narrow( obj ) ;
1514 INFOS( "Container_i::load_impl caught" ) ;
1516 return iobject._retn();
1520 //=============================================================================
1521 //! Indicate if container is a python one
1523 * Retrieves only with container naming convention if it is a python container
1525 //=============================================================================
1526 bool Abstract_Engines_Container_i::isPythonContainer(const char* ContainerName)
1529 size_t len=strlen(ContainerName);
1531 if(strcmp(ContainerName+len-2,"Py")==0)
1536 //=============================================================================
1537 //! Kill the container
1539 * CORBA method: Kill the container process with exit(0).
1540 * To remove : never returns !
1542 //=============================================================================
1543 bool Abstract_Engines_Container_i::Kill_impl()
1545 MESSAGE("Engines_Container_i::Kill() pid "<< getpid() << " containerName "
1546 << _containerName.c_str() << " machineName "
1547 << Kernel_Utils::GetHostname().c_str());
1548 INFOS("===============================================================");
1549 INFOS("= REMOVE calls to Kill_impl in C++ container =");
1550 INFOS("===============================================================");
1556 //=============================================================================
1560 //=============================================================================
1561 void ActSigIntHandler()
1564 struct sigaction SigIntAct ;
1565 SigIntAct.sa_sigaction = &SigIntHandler ;
1566 sigemptyset(&SigIntAct.sa_mask);
1567 SigIntAct.sa_flags = SA_SIGINFO ;
1570 // DEBUG 03.02.2005 : the first parameter of sigaction is not a mask of signals
1571 // (SIGINT | SIGUSR1) :
1572 // it must be only one signal ===> one call for SIGINT
1573 // and an other one for SIGUSR1
1576 if ( sigaction( SIGINT , &SigIntAct, NULL ) )
1578 perror("SALOME_Container main ") ;
1581 if ( sigaction( SIGUSR1 , &SigIntAct, NULL ) )
1583 perror("SALOME_Container main ") ;
1586 if ( sigaction( SIGUSR2 , &SigIntAct, NULL ) )
1588 perror("SALOME_Container main ") ;
1592 //PAL9042 JR : during the execution of a Signal Handler (and of methods called through Signal Handlers)
1593 // use of streams (and so on) should never be used because :
1594 // streams of C++ are naturally thread-safe and use pthread_mutex_lock ===>
1595 // A stream operation may be interrupted by a signal and if the Handler use stream we
1596 // may have a "Dead-Lock" ===HangUp
1597 //==INFOS is commented
1598 // INFOS(pthread_self() << "SigIntHandler activated") ;
1601 signal( SIGINT, SigIntHandler );
1602 // legacy code required to supervisor. Commented in order to avoid problems on Windows
1603 // signal( SIGUSR1, SigIntHandler );
1609 void CallCancelThread() ;
1612 void SigIntHandler(int /*what*/ ,
1613 siginfo_t * siginfo ,
1616 //PAL9042 JR : during the execution of a Signal Handler (and of methods called through Signal Handlers)
1617 // use of streams (and so on) should never be used because :
1618 // streams of C++ are naturally thread-safe and use pthread_mutex_lock ===>
1619 // A stream operation may be interrupted by a signal and if the Handler use stream we
1620 // may have a "Dead-Lock" ===HangUp
1621 //==MESSAGE is commented
1622 // MESSAGE(pthread_self() << "SigIntHandler what " << what << std::endl
1623 // << " si_signo " << siginfo->si_signo << std::endl
1624 // << " si_code " << siginfo->si_code << std::endl
1625 // << " si_pid " << siginfo->si_pid) ;
1630 // MESSAGE("SigIntHandler END sleeping.") ;
1635 ActSigIntHandler() ;
1636 if ( siginfo->si_signo == SIGUSR1 )
1640 else if ( siginfo->si_signo == SIGUSR2 )
1642 CallCancelThread() ;
1647 // MESSAGE("SigIntHandler BEGIN sleeping.") ;
1654 // MESSAGE("SigIntHandler LEAVE sleeping after " << count << " s.") ;
1660 void SigIntHandler( int what )
1663 MESSAGE( pthread_self() << "SigIntHandler what " << what << std::endl );
1665 MESSAGE( "SigIntHandler what " << what << std::endl );
1670 MESSAGE("SigIntHandler END sleeping.") ;
1675 ActSigIntHandler() ;
1676 if ( what == SIGUSR1 )
1683 MESSAGE("SigIntHandler BEGIN sleeping.") ;
1690 MESSAGE("SigIntHandler LEAVE sleeping after " << count << " s.") ;
1697 //=============================================================================
1698 //! Get or create a file reference object associated to a local file (to transfer it)
1700 * CORBA method: get or create a fileRef object associated to a local file
1701 * (a file on the computer on which runs the container server), which stores
1702 * a list of (machine, localFileName) corresponding to copies already done.
1704 * \param origFileName absolute path for a local file to copy on other
1706 * \return a fileRef object associated to the file.
1708 //=============================================================================
1709 Engines::fileRef_ptr
1710 Abstract_Engines_Container_i::createFileRef(const char* origFileName)
1712 std::string origName(origFileName);
1713 Engines::fileRef_var theFileRef = Engines::fileRef::_nil();
1715 if (origName[0] != '/')
1717 INFOS("path of file to copy must be an absolute path beginning with '/'");
1718 return Engines::fileRef::_nil();
1721 if (CORBA::is_nil(_fileRef_map[origName]))
1723 CORBA::Object_var obj=_poa->id_to_reference(*_id);
1724 Engines::Container_var pCont = Engines::Container::_narrow(obj);
1725 fileRef_i* aFileRef = new fileRef_i(pCont, origFileName);
1726 theFileRef = Engines::fileRef::_narrow(aFileRef->_this());
1727 _numInstanceMutex.lock() ; // lock to be alone (stl container write)
1728 _fileRef_map[origName] = theFileRef;
1729 _numInstanceMutex.unlock() ;
1732 theFileRef = Engines::fileRef::_duplicate(_fileRef_map[origName]);
1733 ASSERT(! CORBA::is_nil(theFileRef));
1734 return theFileRef._retn();
1737 //=============================================================================
1738 //! Get a fileTransfer reference
1741 * \return a reference to the fileTransfer object
1743 //=============================================================================
1744 Engines::fileTransfer_ptr
1745 Abstract_Engines_Container_i::getFileTransfer()
1747 Engines::fileTransfer_var aFileTransfer
1748 = Engines::fileTransfer::_duplicate(_fileTransfer);
1749 return aFileTransfer._retn();
1752 //=============================================================================
1753 //! Create a Salome file
1754 //=============================================================================
1755 Engines::Salome_file_ptr
1756 Abstract_Engines_Container_i::createSalome_file(const char* origFileName)
1758 std::string origName(origFileName);
1759 if (CORBA::is_nil(_Salome_file_map[origName]))
1761 Salome_file_i* aSalome_file = new Salome_file_i();
1762 aSalome_file->setContainer(Engines::Container::_duplicate(this->_this()));
1765 aSalome_file->setLocalFile(origFileName);
1766 aSalome_file->recvFiles();
1768 catch (const SALOME::SALOME_Exception& /*e*/) //!< TODO: unused variable
1770 return Engines::Salome_file::_nil();
1773 Engines::Salome_file_var theSalome_file = Engines::Salome_file::_nil();
1774 theSalome_file = Engines::Salome_file::_narrow(aSalome_file->_this());
1775 _numInstanceMutex.lock() ; // lock to be alone (stl container write)
1776 _Salome_file_map[origName] = theSalome_file;
1777 _numInstanceMutex.unlock() ;
1780 Engines::Salome_file_ptr theSalome_file =
1781 Engines::Salome_file::_duplicate(_Salome_file_map[origName]);
1782 ASSERT(!CORBA::is_nil(theSalome_file));
1783 return theSalome_file;
1786 //=============================================================================
1787 /*! \brief copy a file from a remote host (container) to the local host
1788 * \param container the remote container
1789 * \param remoteFile the file to copy locally from the remote host into localFile
1790 * \param localFile the local file
1792 //=============================================================================
1793 void Abstract_Engines_Container_i::copyFile(Engines::Container_ptr container, const char* remoteFile, const char* localFile)
1795 Engines::fileTransfer_var fileTransfer = container->getFileTransfer();
1798 if ((fp = fopen(localFile,"wb")) == NULL)
1800 INFOS("file " << localFile << " cannot be open for writing");
1804 CORBA::Long fileId = fileTransfer->open(remoteFile);
1807 Engines::fileBlock* aBlock;
1814 aBlock = fileTransfer->getBlock(fileId);
1815 toFollow = aBlock->length();
1817 CORBA::Octet *buf = aBlock->get_buffer();
1818 fwrite(buf, sizeof(CORBA::Octet), toFollow, fp);
1822 MESSAGE("end of transfer");
1823 fileTransfer->close(fileId);
1827 INFOS("open reference file for copy impossible");
1831 //=============================================================================
1832 /*! \brief create a PyNode object to execute remote python code
1833 * \param nodeName the name of the node
1834 * \param code the python code to load
1835 * \return the PyNode
1837 //=============================================================================
1838 Engines::PyNode_ptr Abstract_Engines_Container_i::createPyNode(const char* nodeName, const char* code)
1840 Engines::PyNode_var node= Engines::PyNode::_nil();
1842 PyGILState_STATE gstate = PyGILState_Ensure();
1843 PyObject *res = PyObject_CallMethod(_pyCont,
1844 (char*)"create_pynode",
1852 PyGILState_Release(gstate);
1853 SALOME::ExceptionStruct es;
1854 es.type = SALOME::INTERNAL_ERROR;
1855 es.text = "can not create a python node";
1856 throw SALOME::SALOME_Exception(es);
1858 long ierr=PyLong_AsLong(PyTuple_GetItem(res,0));
1859 PyObject* result=PyTuple_GetItem(res,1);
1860 std::string astr=PyUnicode_AsUTF8(result);
1862 PyGILState_Release(gstate);
1865 Utils_Locker lck(&_mutexForDftPy);
1866 CORBA::Object_var obj=_orb->string_to_object(astr.c_str());
1867 node=Engines::PyNode::_narrow(obj);
1868 std::map<std::string,Engines::PyNode_var>::iterator it(_dftPyNode.find(nodeName));
1869 if(it==_dftPyNode.end())
1871 _dftPyNode[nodeName]=node;
1875 Engines::PyNode_var oldNode((*it).second);
1876 if(!CORBA::is_nil(oldNode))
1877 oldNode->UnRegister();
1880 if(!CORBA::is_nil(node))
1882 return node._retn();
1886 SALOME::ExceptionStruct es;
1887 es.type = SALOME::INTERNAL_ERROR;
1888 es.text = astr.c_str();
1889 throw SALOME::SALOME_Exception(es);
1893 //=============================================================================
1894 /*! \brief Retrieves the last created PyNode instance with createPyNode.
1897 //=============================================================================
1898 Engines::PyNode_ptr Abstract_Engines_Container_i::getDefaultPyNode(const char *nodeName)
1900 Utils_Locker lck(&_mutexForDftPy);
1901 std::map<std::string,Engines::PyNode_var>::iterator it(_dftPyNode.find(nodeName));
1902 if(it==_dftPyNode.end())
1903 return Engines::PyNode::_nil();
1906 Engines::PyNode_var tmpVar((*it).second);
1907 if(!CORBA::is_nil(tmpVar))
1908 return Engines::PyNode::_duplicate(tmpVar);
1910 return Engines::PyNode::_nil();
1914 //=============================================================================
1915 /*! \brief create a PyScriptNode object to execute remote python code
1916 * \param nodeName the name of the node
1917 * \param code the python code to load
1918 * \return the PyScriptNode
1920 //=============================================================================
1921 Engines::PyScriptNode_ptr Abstract_Engines_Container_i::createPyScriptNode(const char* nodeName, const char* code)
1923 Engines::PyScriptNode_var node= Engines::PyScriptNode::_nil();
1925 PyGILState_STATE gstate = PyGILState_Ensure();
1926 PyObject *res = PyObject_CallMethod(_pyCont,
1927 (char*)"create_pyscriptnode",
1935 PyGILState_Release(gstate);
1936 SALOME::ExceptionStruct es;
1937 es.type = SALOME::INTERNAL_ERROR;
1938 es.text = "can not create a python node";
1939 throw SALOME::SALOME_Exception(es);
1941 long ierr=PyLong_AsLong(PyTuple_GetItem(res,0));
1942 PyObject* result=PyTuple_GetItem(res,1);
1943 std::string astr=PyUnicode_AsUTF8(result);
1945 PyGILState_Release(gstate);
1949 Utils_Locker lck(&_mutexForDftPy);
1950 CORBA::Object_var obj=_orb->string_to_object(astr.c_str());
1951 node=Engines::PyScriptNode::_narrow(obj);
1952 std::map<std::string,Engines::PyScriptNode_var>::iterator it(_dftPyScriptNode.find(nodeName));
1953 if(it==_dftPyScriptNode.end())
1955 _dftPyScriptNode[nodeName]=node;
1959 Engines::PyScriptNode_var oldNode((*it).second);
1960 if(!CORBA::is_nil(oldNode))
1961 oldNode->UnRegister();
1964 return node._retn();
1968 SALOME::ExceptionStruct es;
1969 es.type = SALOME::INTERNAL_ERROR;
1970 es.text = astr.c_str();
1971 throw SALOME::SALOME_Exception(es);
1975 void Abstract_Engines_Container_i::removePyScriptNode(const char *nodeName)
1977 std::map<std::string,Engines::PyScriptNode_var>::iterator it(_dftPyScriptNode.find(nodeName));
1978 if(it==_dftPyScriptNode.end())
1980 std::ostringstream oss; oss << "Engines_Container_i::removePyScriptNode : node \"" << nodeName << "\" is not map !";
1981 SALOME::ExceptionStruct es;
1982 es.type = SALOME::INTERNAL_ERROR;
1983 es.text = oss.str().c_str();
1984 throw SALOME::SALOME_Exception(es);
1986 (*it).second->UnRegister();
1987 _dftPyScriptNode.erase(it);
1990 void Abstract_Engines_Container_i::cleanAllPyScripts()
1992 for(std::map<std::string,Engines::PyNode_var>::iterator it=_dftPyNode.begin();it!=_dftPyNode.end();it++)
1994 Engines::PyNode_var tmpVar((*it).second);
1995 if(!CORBA::is_nil(tmpVar))
1996 tmpVar->UnRegister();
1999 for(std::map<std::string,Engines::PyScriptNode_var>::iterator it=_dftPyScriptNode.begin();it!=_dftPyScriptNode.end();it++)
2001 Engines::PyScriptNode_var tmpVar((*it).second);
2002 if(!CORBA::is_nil(tmpVar))
2003 tmpVar->UnRegister();
2005 _dftPyScriptNode.clear();
2008 //=============================================================================
2009 /*! \brief Retrieves the last created PyScriptNode instance with createPyScriptNode.
2012 //=============================================================================
2013 Engines::PyScriptNode_ptr Abstract_Engines_Container_i::getDefaultPyScriptNode(const char *nodeName)
2015 Utils_Locker lck(&_mutexForDftPy);
2016 std::map<std::string,Engines::PyScriptNode_var>::iterator it(_dftPyScriptNode.find(nodeName));
2017 if(it==_dftPyScriptNode.end())
2018 return Engines::PyScriptNode::_nil();
2021 Engines::PyScriptNode_var tmpVar((*it).second);
2022 if(!CORBA::is_nil(tmpVar))
2023 return Engines::PyScriptNode::_duplicate(tmpVar);
2025 return Engines::PyScriptNode::_nil();
2029 //=============================================================================
2030 /* int checkifexecutable(const char *filename)
2032 * Return non-zero if the name is an executable file, and
2033 * zero if it is not executable, or if it does not exist.
2035 //=============================================================================
2036 int checkifexecutable(const std::string& filename)
2039 struct stat statinfo;
2041 result = stat(filename.c_str(), &statinfo);
2042 if (result < 0) return 0;
2043 if (!S_ISREG(statinfo.st_mode)) return 0;
2048 if (statinfo.st_uid == geteuid()) return statinfo.st_mode & S_IXUSR;
2049 if (statinfo.st_gid == getegid()) return statinfo.st_mode & S_IXGRP;
2050 return statinfo.st_mode & S_IXOTH;
2055 //=============================================================================
2056 /*! \brief Find a file by searching in a path
2057 * \param filename file name to search
2058 * \param path path to search in
2059 * \param pth the complete file path if found
2060 * \return 1 if found 0 if not
2062 //=============================================================================
2063 int findpathof(const std::string& path, std::string& pth, const std::string& filename)
2065 if ( path.size() == 0 ) return 0;
2067 std::string::size_type offset = 0;
2068 std::string::size_type pos = 0;
2070 struct stat statinfo;
2074 pos = path.find( SEP, offset );
2075 pth = path.substr( offset, pos - offset );
2076 if ( pth.size() > 0 )
2078 if( pth[pth.size()-1] != SLASH ) pth += SLASH;
2080 int result=stat(pth.c_str(), &statinfo);
2081 if(result == 0) found=1;
2083 if (pos == std::string::npos) break;
2089 void Abstract_Engines_Container_i::registerTemporaryFile( const std::string& fileName )
2091 _tmp_files.remove( fileName );
2092 _tmp_files.push_back( fileName );
2095 void Abstract_Engines_Container_i::unregisterTemporaryFile( const std::string& fileName )
2097 _tmp_files.remove( fileName );
2100 void Abstract_Engines_Container_i::clearTemporaryFiles()
2102 std::list<std::string>::const_iterator it;
2103 for ( it = _tmp_files.begin(); it != _tmp_files.end(); ++it ) {
2104 #if defined(WIN32) && defined(UNICODE)
2105 std::wstring aFile = Kernel_Utils::utf8_decode_s(*it);
2106 std::wstring command = (GetFileAttributes(aFile.c_str()) == FILE_ATTRIBUTE_DIRECTORY) ? L"rd /Q \"" : L"del /F /Q \"";
2108 command += L"\" 2>NUL";
2109 _wsystem(command.c_str());
2112 std::string aFile = *it;
2113 std::string command = (GetFileAttributes(aFile.c_str()) == FILE_ATTRIBUTE_DIRECTORY) ? "rd /Q \"" : "del /F /Q \"";
2115 command += "\" 2>NUL";
2117 std::string command = "rm -rf ";
2120 system(command.c_str());
2126 static Engines_Container_SSL_i *_container_singleton_ssl = nullptr;
2128 static Engines::Container_var _container_ref_singleton_ssl;
2130 Engines_Container_SSL_i *KERNEL::getContainerSA()
2132 if(!_container_singleton_ssl)
2135 CORBA::ORB_var orb = CORBA::ORB_init(argc,nullptr);
2136 CORBA::Object_var obj = orb->resolve_initial_references("RootPOA");
2137 PortableServer::POA_var poa = PortableServer::POA::_narrow(obj);
2138 PortableServer::POAManager_var pman = poa->the_POAManager();
2139 CORBA::PolicyList policies;
2142 char *argv[4] = {"Container","FactoryServer","toto",nullptr};
2143 SALOME_Fake_NamingService ns;
2144 _container_singleton_ssl = new Engines_Container_SSL_i(orb,poa,"FactoryServer",2,argv,&ns,false);
2145 PortableServer::ObjectId * cont_id = _container_singleton_ssl->getCORBAId();
2147 CORBA::Object_var zeRef = poa->id_to_reference(*cont_id);
2148 _container_ref_singleton_ssl = Engines::Container::_narrow(zeRef);
2150 return _container_singleton_ssl;
2153 Engines::Container_var KERNEL::getContainerRefSA()
2156 return _container_ref_singleton_ssl;