]> SALOME platform Git repositories - modules/kernel.git/blob - src/Container/Container_i.cxx
Salome HOME
[EDF27816] : Add non regression test
[modules/kernel.git] / src / Container / Container_i.cxx
1 // Copyright (C) 2007-2023  CEA, EDF, OPEN CASCADE
2 //
3 // Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
5 //
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.
10 //
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.
15 //
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
19 //
20 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
21 //
22
23 //  SALOME Container : implementation of container and engine for Kernel
24 //  File   : Container_i.cxx
25 //  Author : Paul RASCLE, EDF - MARC TAJCHMAN, CEA 
26 //  Module : SALOME
27 //  $Header$
28 //#define private public
29 //
30 #include <string.h>
31 #include <stdio.h>
32 #include <time.h>
33 #include <sys/types.h>
34 #include <memory>
35 #ifndef WIN32
36 #include <sys/time.h>
37 #include <dlfcn.h>
38 #include <unistd.h>
39 #include <sys/wait.h>
40 #include <errno.h>
41 #include <stdlib.h>
42 #else
43 #include <signal.h>
44 #include <process.h>
45 #include <direct.h>
46 int SIGUSR1 = 1000;
47 #endif
48
49 #include "utilities.h"
50 #include <SALOMEconfig.h>
51 #include CORBA_SERVER_HEADER(SALOME_Component)
52 #include CORBA_SERVER_HEADER(SALOME_Exception)
53 #include <pthread.h>  // must be before Python.h !
54 #include "OpUtil.hxx"
55 #include "SALOME_Container_i.hxx"
56 #include "SALOME_Component_i.hxx"
57 #include "SALOME_FileRef_i.hxx"
58 #include "SALOME_FileTransfer_i.hxx"
59 #include "Salome_file_i.hxx"
60 #include "SALOME_NamingService.hxx"
61 #include "SALOME_Fake_NamingService.hxx"
62 #include "SALOME_Embedded_NamingService_Client.hxx"
63 #include "SALOME_Embedded_NamingService.hxx"
64 #include "Basics_Utils.hxx"
65 #include "PythonCppUtils.hxx"
66
67 #ifdef _XOPEN_SOURCE
68 #undef _XOPEN_SOURCE
69 #endif
70
71 #include <Python.h>
72 #include <structmember.h>
73 #include "Container_init_python.hxx"
74 #ifdef BOS26455_WITH_BOOST_PYTHON
75 #include <boost/python.hpp>
76 #endif
77
78 bool _Sleeping = false ;
79
80 // // Needed by multi-threaded Python --- Supervision
81 int _ArgC ;
82 char ** _ArgV ;
83
84 extern "C" {void ActSigIntHandler() ; }
85 #ifndef WIN32
86 extern "C" {void SigIntHandler(int, siginfo_t *, void *) ; }
87 #else
88 extern "C" {void SigIntHandler( int ) ; }
89 #endif
90
91 #ifndef WIN32
92 #define LIB "lib"
93 #ifdef __APPLE__
94 #define ENGINESO "Engine.dylib"
95 #else
96 #define ENGINESO "Engine.so"
97 #endif
98 #else
99 #define LIB ""
100 #define ENGINESO "Engine.dll"
101 #endif
102
103 #ifdef WIN32
104 #define SEP ';'
105 #define SLASH '\\'
106 #else
107 #define SEP ':'
108 #define SLASH '/'
109 #endif
110
111 std::map<std::string, int> Abstract_Engines_Container_i::_cntInstances_map;
112 std::map<std::string, void *> Abstract_Engines_Container_i::_library_map;
113 std::map<std::string, void *> Abstract_Engines_Container_i::_toRemove_map;
114 omni_mutex Abstract_Engines_Container_i::_numInstanceMutex ;
115
116 static PyObject* _pyCont;
117
118 int checkifexecutable(const std::string&);
119 int findpathof(const std::string& path, std::string&, const std::string&);
120
121 /*! \class Engines_Container_i
122  *  \brief C++ implementation of Engines::Container interface
123  *
124  */
125
126
127 //=============================================================================
128 /*! 
129 *  Default constructor, not for use
130 */
131 //=============================================================================
132
133 Abstract_Engines_Container_i::Abstract_Engines_Container_i () :
134   _NS(nullptr),_id(nullptr),_numInstance(0)
135 {
136 }
137
138 //=============================================================================
139 /*! 
140 *  Constructor to use
141 */
142 //=============================================================================
143
144 Abstract_Engines_Container_i::Abstract_Engines_Container_i (CORBA::ORB_ptr orb, 
145                                                             PortableServer::POA_ptr poa,
146                                                             char *containerName ,
147                                                             int argc , char* argv[],
148                                                             SALOME_NamingService_Container_Abstract *ns,
149                                                             bool isServantAloneInProcess
150                                                             ) :
151   _NS(nullptr),_id(0),_numInstance(0),_isServantAloneInProcess(isServantAloneInProcess)
152 {
153   _pid = (long)getpid();
154
155   if(ns)
156     ActSigIntHandler() ;
157
158   _argc = argc ;
159   _argv = argv ;
160
161   std::string hostname = Kernel_Utils::GetHostname();
162 #ifndef WIN32
163   MESSAGE(hostname << " " << getpid() << 
164     " Engines_Container_i starting argc " <<
165     _argc << " Thread " << pthread_self() ) ;
166 #else
167   MESSAGE(hostname << " " << _getpid() << 
168     " Engines_Container_i starting argc " << _argc<< " Thread " << pthread_self().p ) ;
169 #endif
170
171   int i = 0 ;
172   while ( _argv[ i ] )
173   {
174     MESSAGE("           argv" << i << " " << _argv[ i ]) ;
175     i++ ;
176   }
177
178   if ( argc < 2 )
179   {
180     INFOS("SALOME_Container usage : SALOME_Container ServerName");
181     ASSERT(0) ;
182   }
183   SCRUTE(argv[1]);
184   _isSupervContainer = false;
185
186   _orb = CORBA::ORB::_duplicate(orb) ;
187   _poa = PortableServer::POA::_duplicate(poa) ;
188
189   // Pour les containers paralleles: il ne faut pas enregistrer et activer
190   // le container generique, mais le container specialise
191
192   {
193     _id = _poa->activate_object(this);
194     // key point : if ns is nullptr : this servant is alone in its process
195     //             if ns is not null : this servant embedded into single process.
196     _NS = ns==nullptr ? new SALOME_NamingService : ns->clone();
197     _NS->init_orb( _orb ) ;
198     CORBA::Object_var obj=_poa->id_to_reference(*_id);
199     Engines::Container_var pCont = Engines::Container::_narrow(obj);
200     _remove_ref();
201
202     _containerName =  SALOME_NamingService_Abstract::BuildContainerNameForNS(containerName, hostname.c_str());
203     SCRUTE(_containerName);
204     _NS->Register(pCont, _containerName.c_str());
205     MESSAGE("Engines_Container_i::Engines_Container_i : Container name " << _containerName);
206
207     // Python: 
208     // import SALOME_Container
209     // pycont = SALOME_Container.SALOME_Container_i(containerIORStr)
210
211     CORBA::String_var sior =  _orb->object_to_string(pCont);
212     std::string myCommand="pyCont = SALOME_Container.SALOME_Container_i('";
213     myCommand += _containerName + "','";
214     myCommand += sior;
215     myCommand += "')\n";
216     SCRUTE(myCommand);
217
218     //[RNV]: Comment the PyEval_AcquireLock() and PyEval_ReleaseLock() because this 
219     //approach leads to the deadlock of the main thread of the application on Windows platform
220     //in case if cppContainer runs in the standalone mode. The problem with the PyThreadState 
221     //described by ABN seems not reproduced, to be checked carefully later...
222     {
223       AutoGIL gstate;    
224       //// [ABN]: using the PyGILState* API here is unstable. omniORB logic is invoked
225       //// by the Python code executed below, and in some (random) cases, the Python code
226       //// execution ends with a PyThreadState which was not the one we have here.
227       //// (TODO: understand why ...)
228       //// To be on the safe side we get and load the thread state ourselves:    
229       //PyEval_AcquireLock();  // get GIL
230       //PyThreadState * mainThreadState = PyThreadState_Get();
231       //PyThreadState_Swap(mainThreadState);
232
233 #ifdef WIN32
234       // mpv: this is temporary solution: there is a unregular crash if not
235       //Sleep(2000);
236       //
237       // first element is the path to Registry.dll, but it's wrong
238       PyRun_SimpleString("import sys\n");
239       PyRun_SimpleString("sys.path = sys.path[1:]\n");
240 #endif
241       PyRun_SimpleString("import SALOME_Container\n");
242       PyRun_SimpleString((char*)myCommand.c_str());
243       PyObject *mainmod = PyImport_AddModule("__main__");
244       PyObject *globals = PyModule_GetDict(mainmod);
245       _pyCont = PyDict_GetItemString(globals, "pyCont");
246       //PyThreadState_Swap(NULL);
247       //PyEval_ReleaseLock();
248     }
249
250     fileTransfer_i* aFileTransfer = new fileTransfer_i();
251     CORBA::Object_var obref=aFileTransfer->_this();
252     _fileTransfer = Engines::fileTransfer::_narrow(obref);
253     aFileTransfer->_remove_ref();
254   }
255 }
256
257 //=============================================================================
258 /*! 
259 *  Destructor
260 */
261 //=============================================================================
262
263 Abstract_Engines_Container_i::~Abstract_Engines_Container_i()
264 {
265   MESSAGE("Abstract_Container_i::~Abstract_Container_i()");
266   if(_id)
267     delete _id;
268   if(_NS)
269     delete _NS;
270   cleanAllPyScripts();
271 }
272
273 //=============================================================================
274 //! Get container name
275 /*! 
276 *  CORBA attribute: Container name (see constructor)
277 */
278 //=============================================================================
279
280 char* Abstract_Engines_Container_i::name()
281 {
282   return CORBA::string_dup(_containerName.c_str()) ;
283 }
284
285 //=============================================================================
286 //! Get container working directory
287 /*! 
288 *  CORBA attribute: Container working directory 
289 */
290 //=============================================================================
291
292 char* Abstract_Engines_Container_i::workingdir()
293 {
294   char wd[256];
295   getcwd (wd,256);
296   return CORBA::string_dup(wd) ;
297 }
298
299 //=============================================================================
300 //! Get container log file name
301 /*! 
302 *  CORBA attribute: Container log file name
303 */
304 //=============================================================================
305
306 char* Abstract_Engines_Container_i::logfilename()
307 {
308   return CORBA::string_dup(_logfilename.c_str()) ;
309 }
310
311 //! Set container log file name
312 void Abstract_Engines_Container_i::logfilename(const char* name)
313 {
314   _logfilename=name;
315 }
316
317 //=============================================================================
318 //! Get container host name
319 /*! 
320 *  CORBA method: Get the hostName of the Container (without domain extensions)
321 */
322 //=============================================================================
323
324 char* Abstract_Engines_Container_i::getHostName()
325 {
326   std::string s = Kernel_Utils::GetHostname();
327   //  MESSAGE("Engines_Container_i::getHostName " << s);
328   return CORBA::string_dup(s.c_str()) ;
329 }
330
331 //=============================================================================
332 //! Get container PID
333 /*! 
334 *  CORBA method: Get the PID (process identification) of the Container
335 */
336 //=============================================================================
337
338 CORBA::Long Abstract_Engines_Container_i::getPID()
339 {
340   return (CORBA::Long)getpid();
341 }
342
343 //=============================================================================
344 //! Ping the servant to check it is still alive
345 /*! 
346 *  CORBA method: check if servant is still alive
347 */
348 //=============================================================================
349 void Abstract_Engines_Container_i::ping()
350 {
351   MESSAGE("Engines_Container_i::ping() pid "<< getpid());
352 }
353
354 //=============================================================================
355 //! Get number of CPU cores in the calculation node
356 /*!
357 *  CORBA method: get number of CPU cores
358 */
359 //=============================================================================
360
361 CORBA::Long Abstract_Engines_Container_i::getNumberOfCPUCores()
362 {
363   AutoGIL gstate;
364   PyObject *module = PyImport_ImportModuleNoBlock((char*)"salome_psutil");
365   PyObject *result = PyObject_CallMethod(module,
366                                          (char*)"getNumberOfCPUCores", NULL);
367   int n = PyLong_AsLong(result);
368   Py_DECREF(result);
369
370   return (CORBA::Long)n;
371 }
372
373 //=============================================================================
374 //! Get a load of each CPU core in the calculation node
375 /*!
376 *  CORBA method: get a load of each CPU core
377 */
378 //=============================================================================
379 namespace {
380   typedef struct
381   {
382     PyObject_HEAD
383     int softspace;
384     std::string *out;
385   } PyStdOut;
386
387   static void
388   PyStdOut_dealloc(PyStdOut *self)
389   {
390     PyObject_Del(self);
391   }
392
393   static PyObject*
394   PyStdOut_write(PyStdOut* self, PyObject* args)
395   {
396     char *c;
397     if (!PyArg_ParseTuple(args, "s", &c))
398       return NULL;
399
400     *(self->out) = *(self->out) + c;
401
402     Py_INCREF(Py_None);
403     return Py_None;
404   }
405
406   static PyMethodDef PyStdOut_methods[] =
407   {
408     {"write",  (PyCFunction)PyStdOut_write,  METH_VARARGS,
409       PyDoc_STR("write(string) -> None")},
410     {0, 0, 0, 0}  /* sentinel */
411   };
412
413   static PyMemberDef PyStdOut_memberlist[] =
414   {
415     {(char*)"softspace", T_INT, offsetof(PyStdOut, softspace), 0,
416      (char*)"flag indicating that a space needs to be printed; used by print"},
417     {0, 0, 0, 0, 0}   /* sentinel */
418   };
419
420   static PyTypeObject PyStdOut_Type =
421   {
422     /* The ob_type field must be initialized in the module init function
423      * to be portable to Windows without using C++. */
424     PyVarObject_HEAD_INIT(NULL, 0)
425     /* 0, */                      /*ob_size*/
426     "PyOut",                      /*tp_name*/
427     sizeof(PyStdOut),             /*tp_basicsize*/
428     0,                            /*tp_itemsize*/
429     /* methods */
430     (destructor)PyStdOut_dealloc, /*tp_dealloc*/
431     0,                            /*tp_print*/
432     0,                            /*tp_getattr*/
433     0,                            /*tp_setattr*/
434     0,                            /*tp_compare*/
435     0,                            /*tp_repr*/
436     0,                            /*tp_as_number*/
437     0,                            /*tp_as_sequence*/
438     0,                            /*tp_as_mapping*/
439     0,                            /*tp_hash*/
440     0,                            /*tp_call*/
441     0,                            /*tp_str*/
442     PyObject_GenericGetAttr,      /*tp_getattro*/
443     /* softspace is writable:  we must supply tp_setattro */
444     PyObject_GenericSetAttr,      /* tp_setattro */
445     0,                            /*tp_as_buffer*/
446     Py_TPFLAGS_DEFAULT,           /*tp_flags*/
447     0,                            /*tp_doc*/
448     0,                            /*tp_traverse*/
449     0,                            /*tp_clear*/
450     0,                            /*tp_richcompare*/
451     0,                            /*tp_weaklistoffset*/
452     0,                            /*tp_iter*/
453     0,                            /*tp_iternext*/
454     PyStdOut_methods,             /*tp_methods*/
455     PyStdOut_memberlist,          /*tp_members*/
456     0,                            /*tp_getset*/
457     0,                            /*tp_base*/
458     0,                            /*tp_dict*/
459     0,                            /*tp_descr_get*/
460     0,                            /*tp_descr_set*/
461     0,                            /*tp_dictoffset*/
462     0,                            /*tp_init*/
463     0,                            /*tp_alloc*/
464     0,                            /*tp_new*/
465     0,                            /*tp_free*/
466     0,                            /*tp_is_gc*/
467     0,                            /*tp_bases*/
468     0,                            /*tp_mro*/
469     0,                            /*tp_cache*/
470     0,                            /*tp_subclasses*/
471     0,                            /*tp_weaklist*/
472     0,                            /*tp_del*/
473     0,                            /*tp_version_tag*/
474     0,                            /*tp_finalize*/
475   };
476
477   PyObject* newPyStdOut(std::string& out)
478   {
479     PyStdOut* self = PyObject_New(PyStdOut, &PyStdOut_Type);
480     if (self) {
481       self->softspace = 0;
482       self->out=&out;
483     }
484     return (PyObject*)self;
485   }
486
487   std::string parseException()
488   {
489     std::string error;
490     if (PyErr_Occurred())
491     {
492 #ifdef BOS26455_WITH_BOOST_PYTHON
493       PyObject *ptype = nullptr;
494       PyObject *pvalue = nullptr;
495       PyObject *ptraceback = nullptr;
496       PyErr_Fetch(&ptype, &pvalue, &ptraceback);
497       if (ptype == nullptr)
498         return std::string("Null exception type");
499       PyErr_NormalizeException(&ptype, &pvalue, &ptraceback);
500       if (ptraceback != nullptr)
501         PyException_SetTraceback(pvalue, ptraceback);
502       boost::python::handle<> htype(ptype);
503       boost::python::handle<> hvalue(boost::python::allow_null(pvalue));
504       boost::python::handle<> htraceback(boost::python::allow_null(ptraceback));
505       boost::python::object traceback = boost::python::import("traceback");
506       boost::python::object format_exc = traceback.attr("format_exception");
507       boost::python::object formatted = format_exc(htype, hvalue, htraceback);
508       error = boost::python::extract<std::string>(boost::python::str("\n").join(formatted));
509 #else
510       PyObject* new_stderr = newPyStdOut(error);
511       PyObject* old_stderr = PySys_GetObject((char*)"stderr");
512       Py_INCREF(old_stderr);
513       PySys_SetObject((char*)"stderr", new_stderr);
514       PyErr_Print();
515       PySys_SetObject((char*)"stderr", old_stderr);
516       Py_DECREF(new_stderr);
517 #endif
518     }
519     return error;
520   }
521 }
522   
523 Engines::vectorOfDouble* Abstract_Engines_Container_i::loadOfCPUCores()
524 {
525   AutoGIL gstate;
526   PyObject *module = PyImport_ImportModuleNoBlock((char*)"salome_psutil");
527   PyObject *result = PyObject_CallMethod(module,
528                                          (char*)"loadOfCPUCores", "s",
529                                          _load_script.c_str());
530   if (PyErr_Occurred())
531   {
532     std::string error = parseException();
533     PyErr_Print();
534     SALOME::ExceptionStruct es;
535     es.type = SALOME::INTERNAL_ERROR;
536     es.text = CORBA::string_dup(error.c_str());
537     throw SALOME::SALOME_Exception(es);
538   }
539
540   int n = this->getNumberOfCPUCores();
541   if (!PyList_Check(result) || PyList_Size(result) != n) {
542     // bad number of cores
543     Py_DECREF(result);
544     SALOME::ExceptionStruct es;
545     es.type = SALOME::INTERNAL_ERROR;
546     es.text = "wrong number of cores";
547     throw SALOME::SALOME_Exception(es);
548   }
549
550   Engines::vectorOfDouble_var loads = new Engines::vectorOfDouble;
551   loads->length(n);
552   for (Py_ssize_t i = 0; i < PyList_Size(result); ++i) {
553     PyObject* item = PyList_GetItem(result, i);
554     double foo = PyFloat_AsDouble(item);
555     if (foo < 0.0 || foo > 1.0)
556     {
557       // value not in [0, 1] range
558       Py_DECREF(result);
559       SALOME::ExceptionStruct es;
560       es.type = SALOME::INTERNAL_ERROR;
561       es.text = "load not in [0, 1] range";
562       throw SALOME::SALOME_Exception(es);
563     }
564     loads[i] = foo;
565   }
566
567   Py_DECREF(result);
568
569   return loads._retn();
570 }
571
572 //=============================================================================
573 //! Set custom script to calculate a load of each CPU core
574 /*!
575 *  CORBA method: Set custom script to calculate CPU load
576 *  \param script Python script to execute
577 */
578 //=============================================================================
579
580 void Abstract_Engines_Container_i::setPyScriptForCPULoad(const char *script)
581 {
582   _load_script = script;
583 }
584
585 //=============================================================================
586 //! Nullify custom script to calculate each CPU core's load
587 /*!
588 *  CORBA method: reset script for load calculation to default implementation
589 */
590 //=============================================================================
591
592 void Abstract_Engines_Container_i::resetScriptForCPULoad()
593 {
594   _load_script = "";
595 }
596
597 //=============================================================================
598 //! Get total physical memory of calculation node, in megabytes
599 /*!
600 *  CORBA method: get total physical memory of calculation node
601 */
602 //=============================================================================
603
604 CORBA::Long Abstract_Engines_Container_i::getTotalPhysicalMemory()
605 {
606   AutoGIL gstate;
607   PyObject *module = PyImport_ImportModuleNoBlock((char*)"salome_psutil");
608   PyObject *result = PyObject_CallMethod(module,
609                                          (char*)"getTotalPhysicalMemory", NULL);
610   int n = PyLong_AsLong(result);
611   Py_DECREF(result);
612
613   return (CORBA::Long)n;
614 }
615
616 //=============================================================================
617 //! Get used physical memory of calculation node, in megabytes
618 /*!
619 *  CORBA method: get used physical memory of calculation node
620 */
621 //=============================================================================
622
623 CORBA::Long Abstract_Engines_Container_i::getTotalPhysicalMemoryInUse()
624 {
625   AutoGIL gstate;
626   PyObject *module = PyImport_ImportModuleNoBlock((char*)"salome_psutil");
627   PyObject *result = PyObject_CallMethod(module,
628                                          (char*)"getTotalPhysicalMemoryInUse", NULL);
629   int n = PyLong_AsLong(result);
630   Py_DECREF(result);
631
632   return (CORBA::Long)n;
633 }
634
635 //=============================================================================
636 //! Obtain physical memory, used by the current process, in megabytes.
637 /*!
638 *  CORBA method: get physical memory, used by the current process
639 */
640 //=============================================================================
641
642 CORBA::Long Abstract_Engines_Container_i::getTotalPhysicalMemoryInUseByMe()
643 {
644   AutoGIL gstate;
645   PyObject *module = PyImport_ImportModuleNoBlock((char*)"salome_psutil");
646   PyObject *result = PyObject_CallMethod(module,
647                                          (char*)"getTotalPhysicalMemoryInUseByMe", NULL);
648   int n = PyLong_AsLong(result);
649   Py_DECREF(result);
650
651   return (CORBA::Long)n;
652 }
653
654 //=============================================================================
655 //! Shutdown the container
656 /*! 
657 *  CORBA method, oneway: Server shutdown. 
658 *  - Container name removed from naming service,
659 *  - servant deactivation,
660 *  - orb shutdown if no other servants in the process 
661 */
662 //=============================================================================
663 void Abstract_Engines_Container_i::Shutdown()
664 {
665   MESSAGE("Engines_Container_i::Shutdown()");
666
667   // Clear registered temporary files
668   clearTemporaryFiles();
669
670   /* For each component contained in this container
671   * tell it to self-destroy
672   */
673   std::map<std::string, Engines::EngineComponent_var>::iterator itm;
674   for (itm = _listInstances_map.begin(); itm != _listInstances_map.end(); itm++)
675   {
676     try
677     {
678       itm->second->destroy();
679     }
680     catch(const CORBA::Exception&)
681     {
682       // ignore this entry and continue
683     }
684     catch(...)
685     {
686       // ignore this entry and continue
687     }
688   }
689   _listInstances_map.clear();
690
691   // NS unregistering may throw in SSL mode if master process hosting SALOME_Embedded_NamingService servant has vanished
692   // In this case it's skip it and still continue.
693   try
694   {
695     _NS->Destroy_FullDirectory(_containerName.c_str());
696     _NS->Destroy_Name(_containerName.c_str());
697   }
698   catch(...)
699   {
700   }
701   //
702   this->cleanAllPyScripts();
703   //
704   if(_isServantAloneInProcess)
705   {
706     MESSAGE("Effective Shutdown of container Begins...");
707     if(!CORBA::is_nil(_orb))
708       _orb->shutdown(0);
709   }
710 }
711
712 //=============================================================================
713 //! load a component implementation
714 /*! 
715 *  CORBA method
716 *  \param componentName         component name
717 *  \param reason                explains error when load fails
718 *  \return true if dlopen successful or already done, false otherwise
719 */
720 //=============================================================================
721 bool
722 Abstract_Engines_Container_i::load_component_Library(const char* componentName, CORBA::String_out reason)
723 {
724
725   //=================================================================
726   // --- C++ implementation section 
727   //=================================================================
728   std::string retso;
729   if(load_component_CppImplementation(componentName,retso))
730   {
731     reason=CORBA::string_dup("");
732     return true;
733   }
734   else if(retso != "ImplementationNotFound")
735   {
736     reason=CORBA::string_dup(retso.c_str());
737     return false;
738   }
739
740   retso="Component ";
741   retso+=componentName;
742   retso+=": Can't find C++ implementation ";
743   retso+=std::string(LIB) + componentName + ENGINESO;
744
745   //=================================================================
746   // --- Python implementation section 
747   //=================================================================
748   std::string retpy;
749   if(load_component_PythonImplementation(componentName,retpy))
750   {
751     reason=CORBA::string_dup("");
752     return true;
753   }
754   else if(retpy != "ImplementationNotFound")
755   {
756     reason=CORBA::string_dup(retpy.c_str());
757     return false;
758   }
759   
760   retpy="Component ";
761   retpy+=componentName;
762   retpy+=": Can't find python implementation ";
763   retpy+=componentName;
764   retpy+="(.py)";
765
766   //=================================================================
767   // -- Executable implementation section
768   //=================================================================
769   std::string retex;
770   if(load_component_ExecutableImplementation(componentName,retex))
771   {
772     reason=CORBA::string_dup("");
773     return true;
774   }
775   else if(retex != "ImplementationNotFound")
776   {
777     reason=CORBA::string_dup(retex.c_str());
778     return false;
779   }
780
781   retex="Component ";
782   retex+=componentName;
783   retex+=": Can't find executable implementation ";
784   retex+=componentName;
785   retex+=".exe";
786
787   std::string ret="Component implementation not found: ";
788   ret += componentName ;
789   ret += '\n' ;
790   ret += retso+ '\n' ;
791   ret += retpy+ '\n' ;
792   ret += retex+ '\n' ;
793
794   std::cerr << ret << std::endl;
795   reason=CORBA::string_dup(ret.c_str());
796
797   return false;
798 }
799
800 //=============================================================================
801 //! try to load a C++ component implementation
802 /*! 
803 *  C++ method: 
804 *  \param componentName      the name of the component (COMPONENT, for example)
805 *  \param reason             explains error when load fails
806 *  \return true if loading is successful or already done, false otherwise
807 */
808 //=============================================================================
809 bool
810 Abstract_Engines_Container_i::load_component_CppImplementation(const char* componentName, std::string& reason)
811 {
812   std::string aCompName(componentName);
813   std::string impl_name = std::string(LIB) + aCompName + ENGINESO;
814   SCRUTE(impl_name);
815
816   _numInstanceMutex.lock(); // lock to be alone
817   // (see decInstanceCnt, finalize_removal))
818   if (_toRemove_map.count(impl_name) != 0) _toRemove_map.erase(impl_name);
819   if (_library_map.count(impl_name) != 0)
820   {
821     MESSAGE("Library " << impl_name << " already loaded");
822     _numInstanceMutex.unlock();
823     reason="";
824     return true;
825   }
826   _numInstanceMutex.unlock();
827
828 #ifndef WIN32
829   void* handle;
830   handle = dlopen( impl_name.c_str() , RTLD_NOW | RTLD_GLOBAL ) ;
831   if ( !handle )
832   {
833     //not loadable. Try to find the lib file in LD_LIBRARY_PATH
834     std::string path;
835 #ifdef __APPLE__
836       char* p=getenv("DYLD_LIBRARY_PATH");
837 #else
838       char* p=getenv("LD_LIBRARY_PATH");
839 #endif
840       if(p)path=p;
841       path=path+SEP+"/usr/lib"+SEP+"/lib";
842
843       std::string pth;
844       if(findpathof(path, pth, impl_name))
845         {
846           //found but not loadable
847           reason="Component ";
848           reason+=aCompName;
849           reason+=": C++ implementation found ";
850           reason+=pth;
851           reason+=" but it is not loadable. Error:\n";
852           reason+=dlerror();
853           std::cerr << reason << std::endl;
854           return false;
855         }
856       else
857         {
858           //not found
859           //continue with other implementation
860           reason="ImplementationNotFound";
861           return false;
862     }
863   }
864 #else
865   HINSTANCE handle;
866 #ifdef UNICODE
867   std::wstring libToLoad = Kernel_Utils::utf8_decode_s( impl_name );
868 #else
869   std::string libToLoad = impl_name;
870 #endif
871   handle = LoadLibrary(libToLoad.c_str() );
872   if ( !handle )
873   {
874     reason="ImplementationNotFound";
875   }
876 #endif
877
878   if ( handle )
879   {
880     _numInstanceMutex.lock();
881     _library_map[impl_name] = handle;
882     _numInstanceMutex.unlock();
883     reason="";
884     return true;
885   }
886
887   return false;
888
889 }
890 //=============================================================================
891 //! try to load a Python component implementation
892 /*! 
893 *  C++ method: 
894 *  \param componentName         name of the component
895 *  \param reason                explains error when load fails
896 *  \return true if loading is successful or already done, false otherwise
897 */
898 //=============================================================================
899 bool
900 Abstract_Engines_Container_i::load_component_PythonImplementation(const char* componentName, std::string& reason)
901 {
902   std::string aCompName(componentName);
903
904   _numInstanceMutex.lock() ; // lock to be alone (stl container write)
905   if (_library_map.count(aCompName) != 0)
906   {
907     _numInstanceMutex.unlock() ;
908     reason="";
909     return true; // Python Component, already imported
910   }
911   _numInstanceMutex.unlock() ;
912
913   {
914     AutoGIL gstate;
915     PyObject *result = PyObject_CallMethod(_pyCont,
916                                           (char*)"import_component",
917                                           (char*)"s",componentName);
918
919     reason=PyUnicode_AsUTF8(result);
920     Py_XDECREF(result);
921     SCRUTE(reason);
922   }
923
924   if (reason=="")
925   {
926     //Python component has been loaded (import componentName)
927     _numInstanceMutex.lock() ; // lock to be alone (stl container write)
928     _library_map[aCompName] = (void *)_pyCont; // any non O value OK
929     _numInstanceMutex.unlock() ;
930     MESSAGE("import Python: "<< aCompName <<" OK");
931     return true;
932   }
933   else if(reason=="ImplementationNotFound")
934   {
935     //Python implementation has not been found. Continue with other implementation
936     reason="ImplementationNotFound";
937   }
938   else
939   {
940     //Python implementation has been found but loading has failed
941     std::cerr << reason << std::endl;
942   }
943   return false;
944
945 }
946 //=============================================================================
947 //! try to load a Executable component implementation
948 /*! 
949 *  C++ method: 
950 *  \param componentName        name of the component
951 *  \param reason               explains error when load fails
952 *  \return true if loading is successful or already done, false otherwise
953 */
954 //=============================================================================
955 bool
956 Abstract_Engines_Container_i::load_component_ExecutableImplementation(const char* componentName, std::string& reason)
957 {
958   std::string aCompName(componentName);
959   std::string executable=aCompName+".exe";
960
961   std::string path;
962   std::string pth;
963
964   char* p=getenv("PATH");
965   if(p)path=p;
966
967   if (findpathof(path, pth, executable))
968   {
969     if(checkifexecutable(pth))
970     {
971       _numInstanceMutex.lock() ; // lock to be alone (stl container write)
972       _library_map[executable] = (void *)1; // any non O value OK
973       _numInstanceMutex.unlock() ;
974       MESSAGE("import executable: "<< pth <<" OK");
975       reason="";
976       return true;
977     }
978     reason="Component ";
979     reason+=aCompName;
980     reason+=": implementation found ";
981     reason+=pth;
982     reason+=" but it is not executable";
983     std::cerr << reason << std::endl;
984   }
985   else
986   {
987     reason="ImplementationNotFound";
988   }
989   return false;
990 }
991
992 //=============================================================================
993 //! Create a new component instance
994 /*! 
995 *  CORBA method: Creates a new servant instance of a component.
996 *  The servant registers itself to naming service and Registry.tdlib
997 *  \param genericRegisterName  Name of the component instance to register
998 *                         in Registry & Name Service (without _inst_n suffix)
999 *  \return a loaded component
1000 */
1001 //=============================================================================
1002 Engines::EngineComponent_ptr
1003 Abstract_Engines_Container_i::create_component_instance(const char*genericRegisterName)
1004 {
1005   Engines::FieldsDict_var env = new Engines::FieldsDict;
1006   char* reason;
1007   Engines::EngineComponent_ptr compo =
1008     create_component_instance_env(genericRegisterName, env, reason);
1009   CORBA::string_free(reason);
1010   return compo;
1011 }
1012
1013 void EffectiveOverrideEnvironment( const Engines::FieldsDict& env )
1014 {
1015   MESSAGE("Positionning environment on container ");
1016   for (CORBA::ULong i=0; i < env.length(); i++)
1017   {
1018     if (env[i].value.type()->kind() == CORBA::tk_string)
1019     {
1020       const char *value = nullptr;
1021       env[i].value >>= value;
1022       MESSAGE( env[i].key << " = " << value);
1023 #ifndef WIN32
1024       if( setenv(env[i].key,value,1) != 0 )
1025       {
1026         int errsv = errno;
1027         std::string sErr( strerror( errsv) );
1028         MESSAGE(sErr);
1029       }
1030 #endif
1031     }
1032   }
1033 }
1034
1035 std::vector< std::pair<std::string,std::string> > GetOSEnvironment()
1036 {
1037   std::vector< std::pair<std::string,std::string> > ret;
1038 #ifndef WIN32
1039   char **envPt( environ );
1040   for(;*envPt != nullptr; ++envPt)
1041   {
1042     std::string s( *envPt );
1043     auto pos = s.find_first_of('=');
1044     std::string k( s.substr(0,pos) ),v( s.substr(pos+1) );
1045     ret.emplace_back( std::pair<std::string,std::string>(k,v) );
1046   }
1047 #endif
1048   return ret;
1049 }
1050
1051 void Abstract_Engines_Container_i::override_environment( const Engines::FieldsDict& env )
1052 {
1053   EffectiveOverrideEnvironment(env);
1054 }
1055
1056 void Abstract_Engines_Container_i::override_environment_python( const Engines::FieldsDict& env )
1057 {
1058   constexpr char NODE_NAME[] = "ScriptNodeForEnv";
1059   constexpr char SCRIPT[] = R"foo(
1060 import os
1061 for k,v in env:
1062   os.environ[k] = v
1063 )foo";
1064   Engines::PyScriptNode_var scriptNode = this->createPyScriptNode(NODE_NAME,SCRIPT);
1065   auto sz = env.length();
1066   Engines::listofstring keys, vals;
1067   keys.length( sz ); vals.length( sz );
1068   for( auto i = 0 ; i < sz ; ++i )
1069   {
1070     keys[i] = CORBA::string_dup( env[i].key );
1071     const char *value = nullptr;
1072     env[i].value >>= value;
1073     vals[i] = CORBA::string_dup( value );
1074   }
1075   scriptNode->executeSimple(keys,vals);
1076   this->removePyScriptNode(NODE_NAME);
1077 }
1078
1079 Engines::FieldsDict *Abstract_Engines_Container_i::get_os_environment()
1080 {
1081   std::unique_ptr<Engines::FieldsDict> ret( new Engines::FieldsDict );
1082   std::vector< std::pair<std::string,std::string> > retCpp( GetOSEnvironment() );
1083   auto sz = retCpp.size();
1084   ret->length( sz );
1085   for(auto i = 0 ; i < sz ; ++i)
1086   {
1087     (*ret)[i].key = CORBA::string_dup( retCpp[i].first.c_str() );
1088     (*ret)[i].value <<= CORBA::string_dup( retCpp[i].second.c_str() );
1089   }
1090   return ret.release();
1091 }
1092
1093 //=============================================================================
1094 //! Create a new component instance with environment variables specified
1095 /*! 
1096 *  CORBA method: Creates a new servant instance of a component.
1097 *  The servant registers itself to naming service and Registry.
1098 *  \param genericRegisterName  Name of the component instance to register
1099 *                         in Registry & Name Service (without _inst_n suffix)
1100 *  \param env             dict of env variables
1101 *  \param reason          explains error when create_component_instance_env fails
1102 *  \return a loaded component
1103 */
1104 //=============================================================================
1105 Engines::EngineComponent_ptr
1106 Abstract_Engines_Container_i::create_component_instance_env(const char*genericRegisterName,
1107                                                    const Engines::FieldsDict& env,
1108                                                    CORBA::String_out reason)
1109 {
1110   std::string error;
1111   if (_library_map.count(genericRegisterName) != 0)
1112   {
1113     // It's a Python component
1114     Engines::EngineComponent_ptr compo = createPythonInstance(genericRegisterName, error);
1115     reason=CORBA::string_dup(error.c_str());
1116     return compo;
1117   }
1118
1119   std::string impl_name = std::string(LIB) + genericRegisterName + ENGINESO;
1120   if (_library_map.count(impl_name) != 0)
1121   {
1122     // It's a C++ component
1123     void* handle = _library_map[impl_name];
1124     Engines::EngineComponent_ptr compo = createInstance(genericRegisterName, handle, error);
1125     reason=CORBA::string_dup(error.c_str());
1126     return compo;
1127   }
1128
1129   impl_name = std::string(genericRegisterName) + ".exe";
1130   if (_library_map.count(impl_name) != 0)
1131   {
1132     //It's an executable component
1133     Engines::EngineComponent_ptr compo = createExecutableInstance(genericRegisterName, env, error);
1134     reason=CORBA::string_dup(error.c_str());
1135     return compo;
1136   }
1137
1138   error="load_component_Library has probably not been called for component: ";
1139   error += genericRegisterName;
1140   INFOS(error);
1141   reason=CORBA::string_dup(error.c_str());
1142   return Engines::EngineComponent::_nil() ;
1143 }
1144
1145 //=============================================================================
1146 //! Create a new component instance (Executable implementation)
1147 /*! 
1148 *  \param CompName               Name of the component instance
1149 *  \param env                    dict of env variables
1150 *  \param reason                 explains error when creation fails
1151 *  \return a loaded component
1152 *
1153 *   This component is implemented in an executable with name genericRegisterName.exe
1154 *   It must register itself in Naming Service. The container waits some time (10 s max)
1155 *   it's registration.
1156 */
1157 //=============================================================================
1158 Engines::EngineComponent_ptr
1159 Abstract_Engines_Container_i::createExecutableInstance(std::string CompName,
1160                                                       const Engines::FieldsDict& env,
1161                                                       std::string& reason)
1162 {
1163   Engines::EngineComponent_var iobject = Engines::EngineComponent::_nil() ;
1164
1165   _numInstanceMutex.lock() ; // lock on the instance number
1166   _numInstance++ ;
1167   int numInstance = _numInstance ;
1168   _numInstanceMutex.unlock() ;
1169
1170   char aNumI[12];
1171   sprintf( aNumI , "%d" , numInstance ) ;
1172   std::string instanceName = CompName + "_inst_" + aNumI ;
1173   std::string component_registerName = _containerName + "/" + instanceName;
1174
1175   //check if an entry exist in naming service
1176   CORBA::Object_var nsobj = _NS->Resolve(component_registerName.c_str());
1177   if ( !CORBA::is_nil(nsobj) )
1178   {
1179     // unregister the registered component
1180     _NS->Destroy_Name(component_registerName.c_str());
1181     //kill or shutdown it ???
1182   }
1183
1184   // first arg container ior string
1185   // second arg container name
1186   // third arg instance name
1187
1188   Engines::Container_var pCont= _this();
1189   CORBA::String_var sior =  _orb->object_to_string(pCont);
1190
1191   std::string command;
1192   command="mkdir -p ";
1193   command+=instanceName;
1194   command+=";cd ";
1195   command+=instanceName;
1196   command+=";";
1197   command+=CompName ;
1198   command+=".exe";
1199   command+=" ";
1200   command+= sior; // container ior string
1201   command+=" ";
1202   command+=_containerName; //container name
1203   command+=" ";
1204   command+=instanceName; //instance name
1205   command+=" &";
1206   MESSAGE("SALOME_Container::create_component_instance command=" << command);
1207
1208 #ifndef WIN32
1209   // use fork/execl instead of system to get finer control on env variables
1210   int status;
1211   pid_t pid = fork();
1212   if(pid == 0) // child
1213   {
1214     EffectiveOverrideEnvironment(env);
1215
1216     execl("/bin/sh", "sh", "-c", command.c_str() , (char *)0);
1217     status=-1;
1218   }
1219   else if(pid < 0)       // failed to fork
1220   {
1221     status=-1;
1222   }
1223   else            //parent
1224   {
1225     pid_t tpid;
1226     do
1227     {
1228       tpid = wait(&status);
1229     } while (tpid != pid);
1230   }
1231 #else
1232   // launch component with a system call
1233   int status=system(command.c_str());
1234 #endif
1235
1236   if (status == -1)
1237   {
1238     reason="SALOME_Container::create_component_instance system failed (system command status -1)";
1239     MESSAGE(reason);
1240     return Engines::EngineComponent::_nil();
1241   }
1242 #ifndef WIN32
1243   else if (WEXITSTATUS(status) == 217)
1244   {
1245     reason="SALOME_Container::create_component_instance system failed (system command status 217)";
1246     MESSAGE(reason);
1247     return Engines::EngineComponent::_nil();
1248   }
1249 #endif
1250   else
1251   {
1252     int count=20;
1253     if (getenv("TIMEOUT_TO_WAIT_EXE_COMPONENT") != 0)
1254     {
1255       std::string new_count_str = getenv("TIMEOUT_TO_WAIT_EXE_COMPONENT");
1256       int new_count;
1257       std::istringstream ss(new_count_str);
1258       if (!(ss >> new_count))
1259       {
1260         INFOS("[Container] TIMEOUT_TO_WAIT_EXE_COMPONENT should be an int");
1261       }
1262       else
1263         count = new_count;
1264     }
1265     INFOS("[Container] waiting " << count << " second steps exe component ");
1266     CORBA::Object_var obj = CORBA::Object::_nil() ;
1267     while ( CORBA::is_nil(obj) && count )
1268     {
1269 #ifndef WIN32
1270       sleep( 1 ) ;
1271 #else
1272       Sleep(1000);
1273 #endif
1274       count-- ;
1275       MESSAGE( count << ". Waiting for component " << CompName);
1276       obj = _NS->Resolve(component_registerName.c_str());
1277     }
1278
1279     if(CORBA::is_nil(obj))
1280     {
1281       reason="SALOME_Container::create_component_instance failed";
1282       MESSAGE(reason);
1283       return Engines::EngineComponent::_nil();
1284     }
1285     else
1286     {
1287       MESSAGE("SALOME_Container::create_component_instance successful");
1288       iobject = Engines::EngineComponent::_narrow(obj);
1289       _listInstances_map[instanceName] = iobject;
1290       return iobject._retn();
1291     }
1292   }
1293 }
1294
1295
1296 //=============================================================================
1297 //! Create a new component instance (Python implementation)
1298 /*! 
1299 *  \param CompName               Name of the component instance
1300 *  \param reason                 explains error when creation fails
1301 *  \return a loaded component
1302 */
1303 //=============================================================================
1304 Engines::EngineComponent_ptr
1305 Abstract_Engines_Container_i::createPythonInstance(std::string CompName,
1306                                           std::string& reason)
1307 {
1308   Engines::EngineComponent_var iobject = Engines::EngineComponent::_nil() ;
1309
1310   _numInstanceMutex.lock() ; // lock on the instance number
1311   _numInstance++ ;
1312   int numInstance = _numInstance ;
1313   _numInstanceMutex.unlock() ;
1314
1315   char aNumI[12];
1316   sprintf( aNumI , "%d" , numInstance ) ;
1317   std::string instanceName = CompName + "_inst_" + aNumI ;
1318   std::string component_registerName = _containerName + "/" + instanceName;
1319   std::string iors;
1320   {
1321     AutoGIL gstate;
1322     PyObject *result = PyObject_CallMethod(_pyCont,
1323                                           (char*)"create_component_instance",
1324                                           (char*)"ss",
1325                                           CompName.c_str(),
1326                                           instanceName.c_str());
1327     const char *ior;
1328     const char *error;
1329     PyArg_ParseTuple(result,"ss", &ior, &error);
1330     iors = ior;
1331     reason=error;
1332     Py_DECREF(result);
1333   }
1334
1335   if( iors!="" )
1336   {
1337     CORBA::Object_var obj = _orb->string_to_object(iors.c_str());
1338     iobject = Engines::EngineComponent::_narrow( obj ) ;
1339     _listInstances_map[instanceName] = iobject;
1340   }
1341   return iobject._retn();
1342 }
1343
1344 char *
1345 Abstract_Engines_Container_i::create_python_service_instance(const char * CompName,
1346                                                     CORBA::String_out reason)
1347 {
1348   CORBA::Object_var object = CORBA::Object::_nil();
1349
1350   _numInstanceMutex.lock() ; // lock on the instance number
1351   _numInstance++ ;
1352   int numInstance = _numInstance ;
1353   _numInstanceMutex.unlock() ;
1354
1355   char aNumI[12];
1356   sprintf( aNumI , "%d" , numInstance ) ;
1357   std::string instanceName = std::string(CompName) + "_inst_" + aNumI ;
1358   std::string component_registerName = _containerName + "/" + instanceName;
1359
1360   char * _ior = nullptr;
1361   {
1362     AutoGIL gstate;
1363     PyObject *result = PyObject_CallMethod(_pyCont,
1364                                           (char*)"create_component_instance",
1365                                           (char*)"ss",
1366                                           CompName,
1367                                           instanceName.c_str());
1368     const char *ior;
1369     const char *error;
1370     PyArg_ParseTuple(result,"ss", &ior, &error);
1371     reason = CORBA::string_dup(error);
1372     _ior = CORBA::string_dup(ior);
1373     Py_DECREF(result);
1374   }
1375   return _ior;
1376 }
1377
1378
1379 //=============================================================================
1380 //! Create a new component instance (C++ implementation)
1381 /*! 
1382 *  C++ method: create a servant instance of a component.
1383 *  \param genericRegisterName    Name of the component instance to register
1384 *                                in Registry & Name Service,
1385 *                                (without _inst_n suffix, like "COMPONENT")
1386 *  \param handle                 loaded library handle
1387 *  \param reason                 explains error when creation fails
1388 *  \return a loaded component
1389
1390 *  example with names:
1391 *    - aGenRegisterName = COMPONENT (= first argument)
1392 *    - _containerName = /Containers/cli76ce/FactoryServer
1393 *    - factoryName = COMPONENTEngine_factory
1394 *    - component_registerBase = /Containers/cli76ce/FactoryServer/COMPONENT
1395 *    - instanceName = COMPONENT_inst_1
1396 *    - component_registerName = /Containers/cli76ce/FactoryServer/COMPONENT_inst_1
1397 */
1398 //=============================================================================
1399 Engines::EngineComponent_ptr
1400 Abstract_Engines_Container_i::createInstance(std::string genericRegisterName,
1401                                     void *handle,
1402                                     std::string& reason)
1403 {
1404   // --- find the factory
1405
1406   std::string aGenRegisterName = genericRegisterName;
1407   std::string factory_name = aGenRegisterName + std::string("Engine_factory");
1408   SCRUTE(factory_name) ;
1409
1410   typedef PortableServer::ObjectId* (*FACTORY_FUNCTION) (CORBA::ORB_ptr,
1411                                                          PortableServer::POA_ptr, 
1412                                                          PortableServer::ObjectId *, 
1413                                                          const char *, 
1414                                                          const char *) ;
1415
1416 #ifndef WIN32
1417   FACTORY_FUNCTION Component_factory = (FACTORY_FUNCTION)dlsym( handle, factory_name.c_str() );
1418 #else
1419   FACTORY_FUNCTION Component_factory = (FACTORY_FUNCTION)GetProcAddress( (HINSTANCE)handle, factory_name.c_str() );
1420 #endif
1421
1422   if ( !Component_factory )
1423   {
1424     MESSAGE( "Can't resolve symbol: " + factory_name );
1425 #ifndef WIN32
1426     reason=dlerror();
1427     MESSAGE(reason);
1428 #endif
1429     return Engines::EngineComponent::_nil() ;
1430   }
1431
1432   // --- create instance
1433
1434   Engines::EngineComponent_var iobject = Engines::EngineComponent::_nil() ;
1435
1436   try
1437   {
1438     _numInstanceMutex.lock() ; // lock on the instance number
1439     _numInstance++ ;
1440     int numInstance = _numInstance ;
1441     _numInstanceMutex.unlock() ;
1442
1443     char aNumI[12];
1444     sprintf( aNumI , "%d" , numInstance ) ;
1445     std::string instanceName = aGenRegisterName + "_inst_" + aNumI ;
1446     std::string component_registerName =
1447       _containerName + "/" + instanceName;
1448
1449     // --- Instantiate required CORBA object
1450
1451     PortableServer::ObjectId *id ; //not owner, do not delete (nore use var)
1452     id = (Component_factory) ( _orb, _poa, _id, instanceName.c_str(),
1453                                                 aGenRegisterName.c_str() ) ;
1454     if (id == NULL)
1455     {
1456       reason="Can't get ObjectId from factory";
1457       INFOS(reason);
1458       return iobject._retn();
1459     }
1460
1461     // --- get reference from id
1462
1463     CORBA::Object_var obj = _poa->id_to_reference(*id);
1464     iobject = Engines::EngineComponent::_narrow( obj ) ;
1465
1466     _numInstanceMutex.lock() ; // lock to be alone (stl container write)
1467     _listInstances_map[instanceName] = iobject;
1468     _cntInstances_map[aGenRegisterName] += 1;
1469     _numInstanceMutex.unlock() ;
1470     SCRUTE(aGenRegisterName);
1471     SCRUTE(_cntInstances_map[aGenRegisterName]);
1472
1473     // --- register the engine under the name
1474     //     containerName(.dir)/instanceName(.object)
1475
1476     _NS->Register( iobject , component_registerName.c_str() ) ;
1477     MESSAGE( component_registerName.c_str() << " bound" ) ;
1478   }
1479   catch (...)
1480   {
1481     reason="Container_i::createInstance exception caught";
1482     INFOS(reason) ;
1483   }
1484   return iobject._retn();
1485 }
1486
1487 //=============================================================================
1488 //! Find an existing (in the container) component instance
1489 /*!
1490 *  CORBA method: Finds a servant instance of a component
1491 *  \param registeredName  Name of the component in Registry or Name Service,
1492 *                         without instance suffix number
1493 *  \return the first found instance
1494 */
1495 //=============================================================================
1496 Engines::EngineComponent_ptr
1497 Abstract_Engines_Container_i::find_component_instance( const char* registeredName)
1498 {
1499   Engines::EngineComponent_var anEngine = Engines::EngineComponent::_nil();
1500   std::map<std::string,Engines::EngineComponent_var>::iterator itm =_listInstances_map.begin();
1501   while (itm != _listInstances_map.end())
1502   {
1503     std::string instance = (*itm).first;
1504     SCRUTE(instance);
1505     if (instance.find(registeredName) == 0)
1506     {
1507       anEngine = (*itm).second;
1508       return anEngine._retn();
1509     }
1510     itm++;
1511   }
1512   return anEngine._retn();
1513 }
1514
1515 //=============================================================================
1516 //! Remove the component instance from container
1517 /*!
1518 *  CORBA method: Stops the component servant, and deletes all related objects
1519 *  \param component_i     Component to be removed
1520 */
1521 //=============================================================================
1522
1523 void Abstract_Engines_Container_i::remove_impl(Engines::EngineComponent_ptr component_i)
1524 {
1525   ASSERT(! CORBA::is_nil(component_i));
1526   std::string instanceName = component_i->instanceName() ;
1527   MESSAGE("unload component " << instanceName);
1528   _numInstanceMutex.lock() ; // lock to be alone (stl container write)
1529   _listInstances_map.erase(instanceName);
1530   _numInstanceMutex.unlock() ;
1531   component_i->destroy() ;
1532   _NS->Destroy_Name(instanceName.c_str());
1533 }
1534
1535 //=============================================================================
1536 //! Unload component libraries from the container
1537 /*!
1538 *  CORBA method: Discharges unused libraries from the container.
1539 */
1540 //=============================================================================
1541 void Abstract_Engines_Container_i::finalize_removal()
1542 {
1543   MESSAGE("finalize unload : dlclose");
1544   _numInstanceMutex.lock(); // lock to be alone
1545   // (see decInstanceCnt, load_component_Library)
1546   std::map<std::string, void *>::iterator ith;
1547   for (ith = _toRemove_map.begin(); ith != _toRemove_map.end(); ith++)
1548   {
1549     void *handle = (*ith).second;
1550     std::string impl_name= (*ith).first;
1551     if (handle)
1552     {
1553       SCRUTE(handle);
1554       SCRUTE(impl_name);
1555       //        dlclose(handle);                // SALOME unstable after ...
1556       //        _library_map.erase(impl_name);
1557     }
1558   }
1559   _toRemove_map.clear();
1560   _numInstanceMutex.unlock();
1561 }
1562
1563 //=============================================================================
1564 //! Decrement component instance reference count
1565 /*!
1566 *
1567 */
1568 //=============================================================================
1569 void Abstract_Engines_Container_i::decInstanceCnt(std::string genericRegisterName)
1570 {
1571   if(_cntInstances_map.count(genericRegisterName)==0)
1572     return;
1573   std::string aGenRegisterName =genericRegisterName;
1574   MESSAGE("Engines_Container_i::decInstanceCnt " << aGenRegisterName);
1575   ASSERT(_cntInstances_map[aGenRegisterName] > 0);
1576   _numInstanceMutex.lock(); // lock to be alone
1577   // (see finalize_removal, load_component_Library)
1578   _cntInstances_map[aGenRegisterName] -= 1;
1579   SCRUTE(_cntInstances_map[aGenRegisterName]);
1580   if (_cntInstances_map[aGenRegisterName] == 0)
1581   {
1582     std::string impl_name =
1583       Engines_Component_i::GetDynLibraryName(aGenRegisterName.c_str());
1584     SCRUTE(impl_name);
1585     void* handle = _library_map[impl_name];
1586     ASSERT(handle);
1587     _toRemove_map[impl_name] = handle;
1588   }
1589   _numInstanceMutex.unlock();
1590 }
1591
1592 //=============================================================================
1593 //! Find or create a new component instance
1594 /*!
1595 *  CORBA method: find or create an instance of the component (servant),
1596 *  load a new component class (dynamic library) if required,
1597 *
1598 *  ---- FOR COMPATIBILITY WITH 2.2 ----
1599 *
1600 *  ---- USE ONLY FOR MULTISTUDY INSTANCES ! --------
1601 *
1602 *  The servant registers itself to naming service and Registry.
1603 *  \param genericRegisterName  Name of the component to register
1604 *                              in Registry & Name Service
1605 *  \param componentName       Name of the constructed library of the component
1606 *  \return a loaded component
1607 */
1608 //=============================================================================
1609
1610 Engines::EngineComponent_ptr
1611 Abstract_Engines_Container_i::load_impl( const char* genericRegisterName,
1612                                          const char* /*componentName*/ )
1613 {
1614   char* reason;
1615   std::string impl_name = std::string(LIB) + genericRegisterName + ENGINESO;
1616   Engines::EngineComponent_var iobject = Engines::EngineComponent::_nil() ;
1617   if (load_component_Library(genericRegisterName,reason))
1618     iobject = find_or_create_instance(genericRegisterName, impl_name);
1619   CORBA::string_free(reason);
1620   return iobject._retn();
1621 }
1622
1623 Engines::EmbeddedNamingService_ptr Abstract_Engines_Container_i::get_embedded_NS_if_ssl()
1624 {
1625   SALOME_Embedded_NamingService_Client *nsc(dynamic_cast<SALOME_Embedded_NamingService_Client *>(this->_NS));
1626   if(nsc)
1627   {
1628     Engines::EmbeddedNamingService_var obj = nsc->GetObject();
1629     return Engines::EmbeddedNamingService::_duplicate(obj);
1630   }
1631   else
1632   {
1633     SALOME_Fake_NamingService *fns(dynamic_cast<SALOME_Fake_NamingService *>(this->_NS));
1634     if(fns)
1635     {
1636       Engines::EmbeddedNamingService_var ret = GetEmbeddedNamingService();
1637       return ret._retn();
1638     }
1639     else
1640       return Engines::EmbeddedNamingService::_nil();
1641   } 
1642 }
1643
1644 //=============================================================================
1645 //! Finds an already existing component instance or create a new instance
1646 /*!
1647 *  C++ method: Finds an already existing servant instance of a component, or
1648 *              create an instance.
1649 *  ---- USE ONLY FOR MULTISTUDY INSTANCES ! --------
1650 *  \param genericRegisterName    Name of the component instance to register
1651 *                                in Registry & Name Service,
1652 *                                (without _inst_n suffix, like "COMPONENT")
1653 *  \param componentLibraryName   like "libCOMPONENTEngine.so"
1654 *  \return a loaded component
1655 *
1656 *  example with names:
1657 *    - aGenRegisterName = COMPONENT (= first argument)
1658 *    - impl_name = libCOMPONENTEngine.so (= second argument)
1659 *    - _containerName = /Containers/cli76ce/FactoryServer
1660 *    - factoryName = COMPONENTEngine_factory
1661 *    - component_registerBase = /Containers/cli76ce/FactoryServer/COMPONENT
1662 *    - instanceName = COMPONENT_inst_1
1663 *    - component_registerName = /Containers/cli76ce/FactoryServer/COMPONENT_inst_1
1664 */
1665 //=============================================================================
1666
1667 Engines::EngineComponent_ptr
1668 Abstract_Engines_Container_i::find_or_create_instance(std::string genericRegisterName,
1669                                                       std::string componentLibraryName)
1670 {
1671   std::string aGenRegisterName = genericRegisterName;
1672   std::string impl_name = componentLibraryName;
1673   if (_library_map.count(impl_name) == 0)
1674   {
1675     INFOS("shared library " << impl_name <<" must be loaded before creating instance");
1676     return Engines::EngineComponent::_nil() ;
1677   }
1678   else
1679   {
1680     // --- find a registered instance in naming service, or create
1681
1682     void* handle = _library_map[impl_name];
1683     std::string component_registerBase =
1684       _containerName + "/" + aGenRegisterName;
1685     Engines::EngineComponent_var iobject = Engines::EngineComponent::_nil() ;
1686     std::string reason;
1687     try
1688     {
1689       CORBA::Object_var obj =
1690         _NS->ResolveFirst( component_registerBase.c_str());
1691       if ( CORBA::is_nil( obj ) )
1692       {
1693         iobject = createInstance(genericRegisterName,
1694                                  handle,
1695                                  reason);
1696       }
1697       else
1698       {
1699         iobject = Engines::EngineComponent::_narrow( obj ) ;
1700       }
1701     }
1702     catch (...)
1703     {
1704       INFOS( "Container_i::load_impl caught" ) ;
1705     }
1706     return iobject._retn();
1707   }
1708 }
1709
1710 //=============================================================================
1711 //! Indicate if container is a python one
1712 /*! 
1713 *  Retrieves only with container naming convention if it is a python container
1714 */
1715 //=============================================================================
1716 bool Abstract_Engines_Container_i::isPythonContainer(const char* ContainerName)
1717 {
1718   bool ret=false;
1719   size_t len=strlen(ContainerName);
1720   if(len>=2)
1721     if(strcmp(ContainerName+len-2,"Py")==0)
1722       ret=true;
1723   return ret;
1724 }
1725
1726 //=============================================================================
1727 //! Kill the container
1728 /*!
1729 *  CORBA method: Kill the container process with exit(0).
1730 *  To remove :  never returns !
1731 */
1732 //=============================================================================
1733 bool Abstract_Engines_Container_i::Kill_impl()
1734 {
1735   MESSAGE("Engines_Container_i::Kill() pid "<< getpid() << " containerName "
1736     << _containerName.c_str() << " machineName "
1737     << Kernel_Utils::GetHostname().c_str());
1738   INFOS("===============================================================");
1739   INFOS("= REMOVE calls to Kill_impl in C++ container                  =");
1740   INFOS("===============================================================");
1741   //_exit( 0 ) ;
1742   ASSERT(0);
1743   return false;
1744 }
1745
1746 //=============================================================================
1747 /*! 
1748 *  
1749 */
1750 //=============================================================================
1751 void ActSigIntHandler()
1752 {
1753 #ifndef WIN32
1754   struct sigaction SigIntAct ;
1755   SigIntAct.sa_sigaction = &SigIntHandler ;
1756   sigemptyset(&SigIntAct.sa_mask);
1757   SigIntAct.sa_flags = SA_SIGINFO ;
1758 #endif
1759
1760   // DEBUG 03.02.2005 : the first parameter of sigaction is not a mask of signals
1761   // (SIGINT | SIGUSR1) :
1762   // it must be only one signal ===> one call for SIGINT 
1763   // and an other one for SIGUSR1
1764
1765 #ifndef WIN32
1766   if ( sigaction( SIGINT , &SigIntAct, NULL ) ) 
1767   {
1768     perror("SALOME_Container main ") ;
1769     exit(0) ;
1770   }
1771   if ( sigaction( SIGUSR1 , &SigIntAct, NULL ) )
1772   {
1773     perror("SALOME_Container main ") ;
1774     exit(0) ;
1775   }
1776   if ( sigaction( SIGUSR2 , &SigIntAct, NULL ) )
1777   {
1778     perror("SALOME_Container main ") ;
1779     exit(0) ;
1780   }
1781
1782   //PAL9042 JR : during the execution of a Signal Handler (and of methods called through Signal Handlers)
1783   //             use of streams (and so on) should never be used because :
1784   //             streams of C++ are naturally thread-safe and use pthread_mutex_lock ===>
1785   //             A stream operation may be interrupted by a signal and if the Handler use stream we
1786   //             may have a "Dead-Lock" ===HangUp
1787   //==INFOS is commented
1788   //  INFOS(pthread_self() << "SigIntHandler activated") ;
1789
1790 #else  
1791   signal( SIGINT, SigIntHandler );
1792 // legacy code required to supervisor. Commented in order to avoid problems on Windows 
1793 //  signal( SIGUSR1, SigIntHandler );
1794 #endif
1795
1796 }
1797
1798 void SetCpuUsed() ;
1799 void CallCancelThread() ;
1800
1801 #ifndef WIN32
1802 void SigIntHandler(int /*what*/ ,
1803                    siginfo_t * siginfo ,
1804                    void * /*toto*/ ) 
1805 {
1806   //PAL9042 JR : during the execution of a Signal Handler (and of methods called through Signal Handlers)
1807   //             use of streams (and so on) should never be used because :
1808   //             streams of C++ are naturally thread-safe and use pthread_mutex_lock ===>
1809   //             A stream operation may be interrupted by a signal and if the Handler use stream we
1810   //             may have a "Dead-Lock" ===HangUp
1811   //==MESSAGE is commented
1812   //  MESSAGE(pthread_self() << "SigIntHandler what     " << what << std::endl
1813   //          << "              si_signo " << siginfo->si_signo << std::endl
1814   //          << "              si_code  " << siginfo->si_code << std::endl
1815   //          << "              si_pid   " << siginfo->si_pid) ;
1816
1817   if ( _Sleeping )
1818   {
1819     _Sleeping = false ;
1820     //     MESSAGE("SigIntHandler END sleeping.") ;
1821     return ;
1822   }
1823   else
1824   {
1825     ActSigIntHandler() ;
1826     if ( siginfo->si_signo == SIGUSR1 )
1827     {
1828       SetCpuUsed() ;
1829     }
1830     else if ( siginfo->si_signo == SIGUSR2 )
1831     {
1832       CallCancelThread() ;
1833     }
1834     else 
1835     {
1836       _Sleeping = true ;
1837       //      MESSAGE("SigIntHandler BEGIN sleeping.") ;
1838       int count = 0 ;
1839       while( _Sleeping )
1840       {
1841         sleep( 1 ) ;
1842         count += 1 ;
1843       }
1844       //      MESSAGE("SigIntHandler LEAVE sleeping after " << count << " s.") ;
1845     }
1846     return ;
1847   }
1848 }
1849 #else // Case WIN32
1850 void SigIntHandler( int what )
1851 {
1852 #ifndef WIN32
1853   MESSAGE( pthread_self() << "SigIntHandler what     " << what << std::endl );
1854 #else
1855   MESSAGE( "SigIntHandler what     " << what << std::endl );
1856 #endif
1857   if ( _Sleeping )
1858   {
1859     _Sleeping = false ;
1860     MESSAGE("SigIntHandler END sleeping.") ;
1861     return ;
1862   }
1863   else
1864   {
1865     ActSigIntHandler() ;
1866     if ( what == SIGUSR1 )
1867     {
1868       SetCpuUsed() ;
1869     }
1870     else
1871     {
1872       _Sleeping = true ;
1873       MESSAGE("SigIntHandler BEGIN sleeping.") ;
1874       int count = 0 ;
1875       while( _Sleeping ) 
1876       {
1877         Sleep( 1000 ) ;
1878         count += 1 ;
1879       }
1880       MESSAGE("SigIntHandler LEAVE sleeping after " << count << " s.") ;
1881     }
1882     return ;
1883   }
1884 }
1885 #endif
1886
1887 //=============================================================================
1888 //! Get or create a file reference object associated to a local file (to transfer it)
1889 /*!
1890 *  CORBA method: get or create a fileRef object associated to a local file
1891 *  (a file on the computer on which runs the container server), which stores
1892 *  a list of (machine, localFileName) corresponding to copies already done.
1893 *
1894 *  \param  origFileName absolute path for a local file to copy on other
1895 *          computers
1896 *  \return a fileRef object associated to the file.
1897 */
1898 //=============================================================================
1899 Engines::fileRef_ptr
1900 Abstract_Engines_Container_i::createFileRef(const char* origFileName)
1901 {
1902   std::string origName(origFileName);
1903   Engines::fileRef_var theFileRef = Engines::fileRef::_nil();
1904
1905   if (origName[0] != '/')
1906   {
1907     INFOS("path of file to copy must be an absolute path beginning with '/'");
1908     return Engines::fileRef::_nil();
1909   }
1910
1911   if (CORBA::is_nil(_fileRef_map[origName]))
1912   {
1913     CORBA::Object_var obj=_poa->id_to_reference(*_id);
1914     Engines::Container_var pCont = Engines::Container::_narrow(obj);
1915     fileRef_i* aFileRef = new fileRef_i(pCont, origFileName);
1916     theFileRef = Engines::fileRef::_narrow(aFileRef->_this());
1917     _numInstanceMutex.lock() ; // lock to be alone (stl container write)
1918     _fileRef_map[origName] = theFileRef;
1919     _numInstanceMutex.unlock() ;
1920   }
1921
1922   theFileRef =  Engines::fileRef::_duplicate(_fileRef_map[origName]);
1923   ASSERT(! CORBA::is_nil(theFileRef));
1924   return theFileRef._retn();
1925 }
1926
1927 //=============================================================================
1928 //! Get a fileTransfer reference
1929 /*!
1930 *  CORBA method:
1931 *  \return a reference to the fileTransfer object
1932 */
1933 //=============================================================================
1934 Engines::fileTransfer_ptr
1935 Abstract_Engines_Container_i::getFileTransfer()
1936 {
1937   Engines::fileTransfer_var aFileTransfer
1938     = Engines::fileTransfer::_duplicate(_fileTransfer);
1939   return aFileTransfer._retn();
1940 }
1941
1942 //=============================================================================
1943 //! Create a Salome file
1944 //=============================================================================
1945 Engines::Salome_file_ptr
1946 Abstract_Engines_Container_i::createSalome_file(const char* origFileName)
1947 {
1948   std::string origName(origFileName);
1949   if (CORBA::is_nil(_Salome_file_map[origName]))
1950   {
1951     Salome_file_i* aSalome_file = new Salome_file_i();
1952     aSalome_file->setContainer(Engines::Container::_duplicate(this->_this()));
1953     try
1954     {
1955       aSalome_file->setLocalFile(origFileName);
1956       aSalome_file->recvFiles();
1957     }
1958     catch (const SALOME::SALOME_Exception& /*e*/) //!< TODO: unused variable
1959     {
1960       return Engines::Salome_file::_nil();
1961     }
1962
1963     Engines::Salome_file_var theSalome_file = Engines::Salome_file::_nil();
1964     theSalome_file = Engines::Salome_file::_narrow(aSalome_file->_this());
1965     _numInstanceMutex.lock() ; // lock to be alone (stl container write)
1966     _Salome_file_map[origName] = theSalome_file;
1967     _numInstanceMutex.unlock() ;
1968   }
1969
1970   Engines::Salome_file_ptr theSalome_file =
1971     Engines::Salome_file::_duplicate(_Salome_file_map[origName]);
1972   ASSERT(!CORBA::is_nil(theSalome_file));
1973   return theSalome_file;
1974 }
1975
1976 //=============================================================================
1977 /*! \brief copy a file from a remote host (container) to the local host
1978  * \param container the remote container
1979  * \param remoteFile the file to copy locally from the remote host into localFile
1980  * \param localFile the local file
1981  */
1982 //=============================================================================
1983 void Abstract_Engines_Container_i::copyFile(Engines::Container_ptr container, const char* remoteFile, const char* localFile)
1984 {
1985   Engines::fileTransfer_var fileTransfer = container->getFileTransfer();
1986
1987   FILE* fp;
1988   if ((fp = fopen(localFile,"wb")) == NULL)
1989   {
1990     INFOS("file " << localFile << " cannot be open for writing");
1991     return;
1992   }
1993
1994   CORBA::Long fileId = fileTransfer->open(remoteFile);
1995   if (fileId > 0)
1996   {
1997     Engines::fileBlock* aBlock;
1998     int toFollow = 1;
1999     int ctr=0;
2000     while (toFollow)
2001     {
2002       ctr++;
2003       //SCRUTE(ctr);
2004       aBlock = fileTransfer->getBlock(fileId);
2005       toFollow = aBlock->length();
2006       //SCRUTE(toFollow);
2007       CORBA::Octet *buf = aBlock->get_buffer();
2008       fwrite(buf, sizeof(CORBA::Octet), toFollow, fp);
2009       delete aBlock;
2010     }
2011     fclose(fp);
2012     MESSAGE("end of transfer");
2013     fileTransfer->close(fileId);
2014   }
2015   else
2016   {
2017     INFOS("open reference file for copy impossible");
2018   }
2019 }
2020
2021 //=============================================================================
2022 /*! \brief create a PyNode object to execute remote python code
2023  * \param nodeName the name of the node
2024  * \param code the python code to load
2025  * \return the PyNode
2026  */
2027 //=============================================================================
2028 Engines::PyNode_ptr Abstract_Engines_Container_i::createPyNode(const char* nodeName, const char* code)
2029 {
2030   Engines::PyNode_var node= Engines::PyNode::_nil();
2031   long ierr(-1);
2032   std::string astr;
2033   {
2034     AutoGIL gstate;
2035     PyObject *res = PyObject_CallMethod(_pyCont,
2036       (char*)"create_pynode",
2037       (char*)"ss",
2038       nodeName,
2039       code);
2040     if(res==NULL)
2041     {
2042       //internal error
2043       PyErr_Print();
2044       SALOME::ExceptionStruct es;
2045       es.type = SALOME::INTERNAL_ERROR;
2046       es.text = "can not create a python node";
2047       throw SALOME::SALOME_Exception(es);
2048     }
2049     ierr=PyLong_AsLong(PyTuple_GetItem(res,0));
2050     PyObject* result=PyTuple_GetItem(res,1);
2051     astr = PyUnicode_AsUTF8(result);
2052     Py_DECREF(res);
2053   }
2054   if(ierr==0)
2055   {
2056     Utils_Locker lck(&_mutexForDftPy);
2057     CORBA::Object_var obj=_orb->string_to_object(astr.c_str());
2058     node=Engines::PyNode::_narrow(obj);
2059     std::map<std::string,Engines::PyNode_var>::iterator it(_dftPyNode.find(nodeName));
2060     if(it==_dftPyNode.end())
2061     {
2062       _dftPyNode[nodeName]=node;
2063     }
2064     else
2065     {
2066       Engines::PyNode_var oldNode((*it).second);
2067       if(!CORBA::is_nil(oldNode))
2068         oldNode->UnRegister();
2069       (*it).second=node;
2070     }
2071     if(!CORBA::is_nil(node))
2072       node->Register();
2073     return node._retn();
2074   }
2075   else
2076   {
2077     SALOME::ExceptionStruct es;
2078     es.type = SALOME::INTERNAL_ERROR;
2079     es.text = astr.c_str();
2080     throw SALOME::SALOME_Exception(es);
2081   }
2082 }
2083
2084 //=============================================================================
2085 /*! \brief Retrieves the last created PyNode instance with createPyNode.
2086  *
2087  */
2088 //=============================================================================
2089 Engines::PyNode_ptr Abstract_Engines_Container_i::getDefaultPyNode(const char *nodeName)
2090 {
2091   Utils_Locker lck(&_mutexForDftPy);
2092   std::map<std::string,Engines::PyNode_var>::iterator it(_dftPyNode.find(nodeName));
2093   if(it==_dftPyNode.end())
2094     return Engines::PyNode::_nil();
2095   else
2096   {
2097     Engines::PyNode_var tmpVar((*it).second);
2098     if(!CORBA::is_nil(tmpVar))
2099       return Engines::PyNode::_duplicate(tmpVar);
2100     else
2101       return Engines::PyNode::_nil();
2102   }
2103 }
2104
2105 //=============================================================================
2106 /*! \brief create a PyScriptNode object to execute remote python code
2107  * \param nodeName the name of the node
2108  * \param code the python code to load
2109  * \return the PyScriptNode
2110  */
2111 //=============================================================================
2112 Engines::PyScriptNode_ptr Abstract_Engines_Container_i::createPyScriptNode(const char* nodeName, const char* code)
2113 {
2114   Engines::PyScriptNode_var node= Engines::PyScriptNode::_nil();
2115   long ierr(-1);
2116   std::string astr;
2117   {
2118     AutoGIL gstate;
2119     PyObject *res = PyObject_CallMethod(_pyCont,
2120       (char*)"create_pyscriptnode",
2121       (char*)"ss",
2122       nodeName,
2123       code);
2124     if(res==NULL)
2125     {
2126       //internal error
2127       PyErr_Print();
2128       SALOME::ExceptionStruct es;
2129       es.type = SALOME::INTERNAL_ERROR;
2130       es.text = "can not create a python node";
2131       throw SALOME::SALOME_Exception(es);
2132     }
2133     ierr=PyLong_AsLong(PyTuple_GetItem(res,0));
2134     PyObject* result=PyTuple_GetItem(res,1);
2135     astr = PyUnicode_AsUTF8(result);
2136     Py_DECREF(res);
2137   }
2138
2139   if(ierr==0)
2140   {
2141     Utils_Locker lck(&_mutexForDftPy);
2142     CORBA::Object_var obj=_orb->string_to_object(astr.c_str());
2143     node=Engines::PyScriptNode::_narrow(obj);
2144     std::map<std::string,Engines::PyScriptNode_var>::iterator it(_dftPyScriptNode.find(nodeName));
2145     if(it==_dftPyScriptNode.end())
2146     {
2147       _dftPyScriptNode[nodeName]=node;
2148     }
2149     else
2150     {
2151       Engines::PyScriptNode_var oldNode((*it).second);
2152       if(!CORBA::is_nil(oldNode))
2153         oldNode->UnRegister();
2154       (*it).second=node;
2155     }
2156     return node._retn();
2157   }
2158   else
2159   {
2160     SALOME::ExceptionStruct es;
2161     es.type = SALOME::INTERNAL_ERROR;
2162     es.text = astr.c_str();
2163     throw SALOME::SALOME_Exception(es);
2164   }
2165 }
2166
2167 void Abstract_Engines_Container_i::removePyScriptNode(const char *nodeName)
2168 {
2169   std::map<std::string,Engines::PyScriptNode_var>::iterator it(_dftPyScriptNode.find(nodeName));
2170   if(it==_dftPyScriptNode.end())
2171     {
2172       std::ostringstream oss; oss << "Engines_Container_i::removePyScriptNode : node \"" << nodeName << "\" is not map !";
2173       SALOME::ExceptionStruct es;
2174       es.type = SALOME::INTERNAL_ERROR;
2175       es.text = oss.str().c_str();
2176       throw SALOME::SALOME_Exception(es);
2177     }
2178   (*it).second->UnRegister();
2179   _dftPyScriptNode.erase(it);
2180 }
2181
2182 void Abstract_Engines_Container_i::cleanAllPyScripts()
2183 {
2184   for(std::map<std::string,Engines::PyNode_var>::iterator it=_dftPyNode.begin();it!=_dftPyNode.end();it++)
2185     {
2186       Engines::PyNode_var tmpVar((*it).second);
2187       if(!CORBA::is_nil(tmpVar))
2188         tmpVar->UnRegister();
2189     }
2190   _dftPyNode.clear();
2191   for(std::map<std::string,Engines::PyScriptNode_var>::iterator it=_dftPyScriptNode.begin();it!=_dftPyScriptNode.end();it++)
2192     {
2193       Engines::PyScriptNode_var tmpVar((*it).second);
2194       if(!CORBA::is_nil(tmpVar))
2195         tmpVar->UnRegister();
2196     }
2197   _dftPyScriptNode.clear();
2198 }
2199
2200 //=============================================================================
2201 /*! \brief Retrieves the last created PyScriptNode instance with createPyScriptNode.
2202  *
2203  */
2204 //=============================================================================
2205 Engines::PyScriptNode_ptr Abstract_Engines_Container_i::getDefaultPyScriptNode(const char *nodeName)
2206 {
2207   Utils_Locker lck(&_mutexForDftPy);
2208   std::map<std::string,Engines::PyScriptNode_var>::iterator it(_dftPyScriptNode.find(nodeName));
2209   if(it==_dftPyScriptNode.end())
2210     return Engines::PyScriptNode::_nil();
2211   else
2212   {
2213     Engines::PyScriptNode_var tmpVar((*it).second);
2214     if(!CORBA::is_nil(tmpVar))
2215       return Engines::PyScriptNode::_duplicate(tmpVar);
2216     else
2217       return Engines::PyScriptNode::_nil();
2218   }
2219 }
2220
2221 //=============================================================================
2222 /* int checkifexecutable(const char *filename)
2223 *
2224 * Return non-zero if the name is an executable file, and
2225 * zero if it is not executable, or if it does not exist.
2226 */
2227 //=============================================================================
2228 int checkifexecutable(const std::string& filename)
2229 {
2230   int result;
2231   struct stat statinfo;
2232
2233   result = stat(filename.c_str(), &statinfo);
2234   if (result < 0) return 0;
2235   if (!S_ISREG(statinfo.st_mode)) return 0;
2236
2237 #ifdef WIN32
2238   return 1;
2239 #else
2240   if (statinfo.st_uid == geteuid()) return statinfo.st_mode & S_IXUSR;
2241   if (statinfo.st_gid == getegid()) return statinfo.st_mode & S_IXGRP;
2242   return statinfo.st_mode & S_IXOTH;
2243 #endif
2244 }
2245
2246
2247 //=============================================================================
2248 /*! \brief Find a file by searching in a path
2249  *  \param filename file name to search
2250  *  \param path path to search in
2251  *  \param pth the complete file path if found
2252  *  \return 1 if found 0 if not 
2253 */
2254 //=============================================================================
2255 int findpathof(const std::string& path, std::string& pth, const std::string& filename)
2256 {
2257   if ( path.size() == 0 ) return 0;
2258
2259   std::string::size_type offset = 0;
2260   std::string::size_type pos = 0;
2261   int found = 0;
2262   struct stat statinfo;
2263
2264   while(!found)
2265   {
2266     pos = path.find( SEP, offset );
2267     pth = path.substr( offset, pos - offset );
2268     if ( pth.size() > 0 )
2269     {
2270       if( pth[pth.size()-1] != SLASH ) pth += SLASH;
2271       pth += filename;
2272       int result=stat(pth.c_str(), &statinfo);
2273       if(result == 0) found=1;
2274     }
2275     if (pos == std::string::npos) break;
2276     offset = pos+1;
2277   }
2278   return found;
2279 }
2280
2281 void Abstract_Engines_Container_i::registerTemporaryFile( const std::string& fileName )
2282 {
2283   _tmp_files.remove( fileName );
2284   _tmp_files.push_back( fileName );
2285 }
2286
2287 void Abstract_Engines_Container_i::unregisterTemporaryFile( const std::string& fileName )
2288 {
2289   _tmp_files.remove( fileName );
2290 }
2291
2292 void Abstract_Engines_Container_i::clearTemporaryFiles()
2293 {
2294   std::list<std::string>::const_iterator it;
2295   for ( it = _tmp_files.begin(); it != _tmp_files.end(); ++it ) {
2296 #if defined(WIN32) && defined(UNICODE)
2297         std::wstring aFile = Kernel_Utils::utf8_decode_s(*it);
2298         std::wstring command = (GetFileAttributes(aFile.c_str()) == FILE_ATTRIBUTE_DIRECTORY) ? L"rd /Q \"" : L"del /F /Q \"";
2299         command += aFile;
2300         command += L"\" 2>NUL";
2301         _wsystem(command.c_str());
2302 #else
2303 #if defined(WIN32)
2304         std::string aFile = *it;
2305         std::string command = (GetFileAttributes(aFile.c_str()) == FILE_ATTRIBUTE_DIRECTORY) ? "rd /Q \"" : "del /F /Q \"";
2306         command += aFile;
2307         command += "\" 2>NUL";
2308 #else
2309         std::string command = "rm -rf ";
2310         command += *it;
2311 #endif
2312         system(command.c_str());
2313 #endif
2314   }
2315   _tmp_files.clear();
2316 }
2317
2318 static Engines_Container_SSL_i *_container_singleton_ssl = nullptr;
2319
2320 static Engines::Container_var _container_ref_singleton_ssl;
2321
2322 Engines_Container_SSL_i *KERNEL::getContainerSA()
2323 {
2324   if(!_container_singleton_ssl)
2325   {
2326     CORBA::ORB_var orb = KERNEL::GetRefToORB();
2327     CORBA::Object_var obj = orb->resolve_initial_references("RootPOA");
2328     PortableServer::POA_var poa = PortableServer::POA::_narrow(obj);
2329     PortableServer::POAManager_var pman = poa->the_POAManager();
2330     CORBA::PolicyList policies;
2331     policies.length(0);
2332     //
2333     char *argv[4] = {"Container","FactoryServer","toto",nullptr};
2334     SALOME_Fake_NamingService ns;
2335     _container_singleton_ssl = new Engines_Container_SSL_i(orb,poa,"FactoryServer",2,argv,&ns,false);
2336     PortableServer::ObjectId * cont_id = _container_singleton_ssl->getCORBAId();
2337     //
2338     CORBA::Object_var zeRef = poa->id_to_reference(*cont_id);
2339     _container_ref_singleton_ssl = Engines::Container::_narrow(zeRef);
2340   }
2341   return _container_singleton_ssl;
2342 }
2343
2344 Engines::Container_var KERNEL::getContainerRefSA()
2345 {
2346   getContainerSA();
2347   return _container_ref_singleton_ssl;
2348 }