Salome HOME
[EDF27816] : WIP
[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( sz ), vals( sz );
1067   for( auto i = 0 ; i < sz ; ++i )
1068   {
1069     keys[i] = CORBA::string_dup( env[i].key );
1070     const char *value = nullptr;
1071     env[i].value >>= value;
1072     vals[i] = CORBA::string_dup( value );
1073   }
1074   scriptNode->executeSimple(keys,vals);
1075   this->removePyScriptNode(NODE_NAME);
1076 }
1077
1078 Engines::FieldsDict *Abstract_Engines_Container_i::get_os_environment()
1079 {
1080   std::unique_ptr<Engines::FieldsDict> ret( new Engines::FieldsDict );
1081   std::vector< std::pair<std::string,std::string> > retCpp( GetOSEnvironment() );
1082   auto sz = retCpp.size();
1083   ret->length( sz );
1084   for(auto i = 0 ; i < sz ; ++i)
1085   {
1086     (*ret)[i].key = CORBA::string_dup( retCpp[i].first.c_str() );
1087     (*ret)[i].value <<= CORBA::string_dup( retCpp[i].second.c_str() );
1088   }
1089   return ret.release();
1090 }
1091
1092 //=============================================================================
1093 //! Create a new component instance with environment variables specified
1094 /*! 
1095 *  CORBA method: Creates a new servant instance of a component.
1096 *  The servant registers itself to naming service and Registry.
1097 *  \param genericRegisterName  Name of the component instance to register
1098 *                         in Registry & Name Service (without _inst_n suffix)
1099 *  \param env             dict of env variables
1100 *  \param reason          explains error when create_component_instance_env fails
1101 *  \return a loaded component
1102 */
1103 //=============================================================================
1104 Engines::EngineComponent_ptr
1105 Abstract_Engines_Container_i::create_component_instance_env(const char*genericRegisterName,
1106                                                    const Engines::FieldsDict& env,
1107                                                    CORBA::String_out reason)
1108 {
1109   std::string error;
1110   if (_library_map.count(genericRegisterName) != 0)
1111   {
1112     // It's a Python component
1113     Engines::EngineComponent_ptr compo = createPythonInstance(genericRegisterName, error);
1114     reason=CORBA::string_dup(error.c_str());
1115     return compo;
1116   }
1117
1118   std::string impl_name = std::string(LIB) + genericRegisterName + ENGINESO;
1119   if (_library_map.count(impl_name) != 0)
1120   {
1121     // It's a C++ component
1122     void* handle = _library_map[impl_name];
1123     Engines::EngineComponent_ptr compo = createInstance(genericRegisterName, handle, error);
1124     reason=CORBA::string_dup(error.c_str());
1125     return compo;
1126   }
1127
1128   impl_name = std::string(genericRegisterName) + ".exe";
1129   if (_library_map.count(impl_name) != 0)
1130   {
1131     //It's an executable component
1132     Engines::EngineComponent_ptr compo = createExecutableInstance(genericRegisterName, env, error);
1133     reason=CORBA::string_dup(error.c_str());
1134     return compo;
1135   }
1136
1137   error="load_component_Library has probably not been called for component: ";
1138   error += genericRegisterName;
1139   INFOS(error);
1140   reason=CORBA::string_dup(error.c_str());
1141   return Engines::EngineComponent::_nil() ;
1142 }
1143
1144 //=============================================================================
1145 //! Create a new component instance (Executable implementation)
1146 /*! 
1147 *  \param CompName               Name of the component instance
1148 *  \param env                    dict of env variables
1149 *  \param reason                 explains error when creation fails
1150 *  \return a loaded component
1151 *
1152 *   This component is implemented in an executable with name genericRegisterName.exe
1153 *   It must register itself in Naming Service. The container waits some time (10 s max)
1154 *   it's registration.
1155 */
1156 //=============================================================================
1157 Engines::EngineComponent_ptr
1158 Abstract_Engines_Container_i::createExecutableInstance(std::string CompName,
1159                                                       const Engines::FieldsDict& env,
1160                                                       std::string& reason)
1161 {
1162   Engines::EngineComponent_var iobject = Engines::EngineComponent::_nil() ;
1163
1164   _numInstanceMutex.lock() ; // lock on the instance number
1165   _numInstance++ ;
1166   int numInstance = _numInstance ;
1167   _numInstanceMutex.unlock() ;
1168
1169   char aNumI[12];
1170   sprintf( aNumI , "%d" , numInstance ) ;
1171   std::string instanceName = CompName + "_inst_" + aNumI ;
1172   std::string component_registerName = _containerName + "/" + instanceName;
1173
1174   //check if an entry exist in naming service
1175   CORBA::Object_var nsobj = _NS->Resolve(component_registerName.c_str());
1176   if ( !CORBA::is_nil(nsobj) )
1177   {
1178     // unregister the registered component
1179     _NS->Destroy_Name(component_registerName.c_str());
1180     //kill or shutdown it ???
1181   }
1182
1183   // first arg container ior string
1184   // second arg container name
1185   // third arg instance name
1186
1187   Engines::Container_var pCont= _this();
1188   CORBA::String_var sior =  _orb->object_to_string(pCont);
1189
1190   std::string command;
1191   command="mkdir -p ";
1192   command+=instanceName;
1193   command+=";cd ";
1194   command+=instanceName;
1195   command+=";";
1196   command+=CompName ;
1197   command+=".exe";
1198   command+=" ";
1199   command+= sior; // container ior string
1200   command+=" ";
1201   command+=_containerName; //container name
1202   command+=" ";
1203   command+=instanceName; //instance name
1204   command+=" &";
1205   MESSAGE("SALOME_Container::create_component_instance command=" << command);
1206
1207 #ifndef WIN32
1208   // use fork/execl instead of system to get finer control on env variables
1209   int status;
1210   pid_t pid = fork();
1211   if(pid == 0) // child
1212   {
1213     EffectiveOverrideEnvironment(env);
1214
1215     execl("/bin/sh", "sh", "-c", command.c_str() , (char *)0);
1216     status=-1;
1217   }
1218   else if(pid < 0)       // failed to fork
1219   {
1220     status=-1;
1221   }
1222   else            //parent
1223   {
1224     pid_t tpid;
1225     do
1226     {
1227       tpid = wait(&status);
1228     } while (tpid != pid);
1229   }
1230 #else
1231   // launch component with a system call
1232   int status=system(command.c_str());
1233 #endif
1234
1235   if (status == -1)
1236   {
1237     reason="SALOME_Container::create_component_instance system failed (system command status -1)";
1238     MESSAGE(reason);
1239     return Engines::EngineComponent::_nil();
1240   }
1241 #ifndef WIN32
1242   else if (WEXITSTATUS(status) == 217)
1243   {
1244     reason="SALOME_Container::create_component_instance system failed (system command status 217)";
1245     MESSAGE(reason);
1246     return Engines::EngineComponent::_nil();
1247   }
1248 #endif
1249   else
1250   {
1251     int count=20;
1252     if (getenv("TIMEOUT_TO_WAIT_EXE_COMPONENT") != 0)
1253     {
1254       std::string new_count_str = getenv("TIMEOUT_TO_WAIT_EXE_COMPONENT");
1255       int new_count;
1256       std::istringstream ss(new_count_str);
1257       if (!(ss >> new_count))
1258       {
1259         INFOS("[Container] TIMEOUT_TO_WAIT_EXE_COMPONENT should be an int");
1260       }
1261       else
1262         count = new_count;
1263     }
1264     INFOS("[Container] waiting " << count << " second steps exe component ");
1265     CORBA::Object_var obj = CORBA::Object::_nil() ;
1266     while ( CORBA::is_nil(obj) && count )
1267     {
1268 #ifndef WIN32
1269       sleep( 1 ) ;
1270 #else
1271       Sleep(1000);
1272 #endif
1273       count-- ;
1274       MESSAGE( count << ". Waiting for component " << CompName);
1275       obj = _NS->Resolve(component_registerName.c_str());
1276     }
1277
1278     if(CORBA::is_nil(obj))
1279     {
1280       reason="SALOME_Container::create_component_instance failed";
1281       MESSAGE(reason);
1282       return Engines::EngineComponent::_nil();
1283     }
1284     else
1285     {
1286       MESSAGE("SALOME_Container::create_component_instance successful");
1287       iobject = Engines::EngineComponent::_narrow(obj);
1288       _listInstances_map[instanceName] = iobject;
1289       return iobject._retn();
1290     }
1291   }
1292 }
1293
1294
1295 //=============================================================================
1296 //! Create a new component instance (Python implementation)
1297 /*! 
1298 *  \param CompName               Name of the component instance
1299 *  \param reason                 explains error when creation fails
1300 *  \return a loaded component
1301 */
1302 //=============================================================================
1303 Engines::EngineComponent_ptr
1304 Abstract_Engines_Container_i::createPythonInstance(std::string CompName,
1305                                           std::string& reason)
1306 {
1307   Engines::EngineComponent_var iobject = Engines::EngineComponent::_nil() ;
1308
1309   _numInstanceMutex.lock() ; // lock on the instance number
1310   _numInstance++ ;
1311   int numInstance = _numInstance ;
1312   _numInstanceMutex.unlock() ;
1313
1314   char aNumI[12];
1315   sprintf( aNumI , "%d" , numInstance ) ;
1316   std::string instanceName = CompName + "_inst_" + aNumI ;
1317   std::string component_registerName = _containerName + "/" + instanceName;
1318   std::string iors;
1319   {
1320     AutoGIL gstate;
1321     PyObject *result = PyObject_CallMethod(_pyCont,
1322                                           (char*)"create_component_instance",
1323                                           (char*)"ss",
1324                                           CompName.c_str(),
1325                                           instanceName.c_str());
1326     const char *ior;
1327     const char *error;
1328     PyArg_ParseTuple(result,"ss", &ior, &error);
1329     iors = ior;
1330     reason=error;
1331     Py_DECREF(result);
1332   }
1333
1334   if( iors!="" )
1335   {
1336     CORBA::Object_var obj = _orb->string_to_object(iors.c_str());
1337     iobject = Engines::EngineComponent::_narrow( obj ) ;
1338     _listInstances_map[instanceName] = iobject;
1339   }
1340   return iobject._retn();
1341 }
1342
1343 char *
1344 Abstract_Engines_Container_i::create_python_service_instance(const char * CompName,
1345                                                     CORBA::String_out reason)
1346 {
1347   CORBA::Object_var object = CORBA::Object::_nil();
1348
1349   _numInstanceMutex.lock() ; // lock on the instance number
1350   _numInstance++ ;
1351   int numInstance = _numInstance ;
1352   _numInstanceMutex.unlock() ;
1353
1354   char aNumI[12];
1355   sprintf( aNumI , "%d" , numInstance ) ;
1356   std::string instanceName = std::string(CompName) + "_inst_" + aNumI ;
1357   std::string component_registerName = _containerName + "/" + instanceName;
1358
1359   char * _ior = nullptr;
1360   {
1361     AutoGIL gstate;
1362     PyObject *result = PyObject_CallMethod(_pyCont,
1363                                           (char*)"create_component_instance",
1364                                           (char*)"ss",
1365                                           CompName,
1366                                           instanceName.c_str());
1367     const char *ior;
1368     const char *error;
1369     PyArg_ParseTuple(result,"ss", &ior, &error);
1370     reason = CORBA::string_dup(error);
1371     _ior = CORBA::string_dup(ior);
1372     Py_DECREF(result);
1373   }
1374   return _ior;
1375 }
1376
1377
1378 //=============================================================================
1379 //! Create a new component instance (C++ implementation)
1380 /*! 
1381 *  C++ method: create a servant instance of a component.
1382 *  \param genericRegisterName    Name of the component instance to register
1383 *                                in Registry & Name Service,
1384 *                                (without _inst_n suffix, like "COMPONENT")
1385 *  \param handle                 loaded library handle
1386 *  \param reason                 explains error when creation fails
1387 *  \return a loaded component
1388
1389 *  example with names:
1390 *    - aGenRegisterName = COMPONENT (= first argument)
1391 *    - _containerName = /Containers/cli76ce/FactoryServer
1392 *    - factoryName = COMPONENTEngine_factory
1393 *    - component_registerBase = /Containers/cli76ce/FactoryServer/COMPONENT
1394 *    - instanceName = COMPONENT_inst_1
1395 *    - component_registerName = /Containers/cli76ce/FactoryServer/COMPONENT_inst_1
1396 */
1397 //=============================================================================
1398 Engines::EngineComponent_ptr
1399 Abstract_Engines_Container_i::createInstance(std::string genericRegisterName,
1400                                     void *handle,
1401                                     std::string& reason)
1402 {
1403   // --- find the factory
1404
1405   std::string aGenRegisterName = genericRegisterName;
1406   std::string factory_name = aGenRegisterName + std::string("Engine_factory");
1407   SCRUTE(factory_name) ;
1408
1409   typedef PortableServer::ObjectId* (*FACTORY_FUNCTION) (CORBA::ORB_ptr,
1410                                                          PortableServer::POA_ptr, 
1411                                                          PortableServer::ObjectId *, 
1412                                                          const char *, 
1413                                                          const char *) ;
1414
1415 #ifndef WIN32
1416   FACTORY_FUNCTION Component_factory = (FACTORY_FUNCTION)dlsym( handle, factory_name.c_str() );
1417 #else
1418   FACTORY_FUNCTION Component_factory = (FACTORY_FUNCTION)GetProcAddress( (HINSTANCE)handle, factory_name.c_str() );
1419 #endif
1420
1421   if ( !Component_factory )
1422   {
1423     MESSAGE( "Can't resolve symbol: " + factory_name );
1424 #ifndef WIN32
1425     reason=dlerror();
1426     MESSAGE(reason);
1427 #endif
1428     return Engines::EngineComponent::_nil() ;
1429   }
1430
1431   // --- create instance
1432
1433   Engines::EngineComponent_var iobject = Engines::EngineComponent::_nil() ;
1434
1435   try
1436   {
1437     _numInstanceMutex.lock() ; // lock on the instance number
1438     _numInstance++ ;
1439     int numInstance = _numInstance ;
1440     _numInstanceMutex.unlock() ;
1441
1442     char aNumI[12];
1443     sprintf( aNumI , "%d" , numInstance ) ;
1444     std::string instanceName = aGenRegisterName + "_inst_" + aNumI ;
1445     std::string component_registerName =
1446       _containerName + "/" + instanceName;
1447
1448     // --- Instantiate required CORBA object
1449
1450     PortableServer::ObjectId *id ; //not owner, do not delete (nore use var)
1451     id = (Component_factory) ( _orb, _poa, _id, instanceName.c_str(),
1452                                                 aGenRegisterName.c_str() ) ;
1453     if (id == NULL)
1454     {
1455       reason="Can't get ObjectId from factory";
1456       INFOS(reason);
1457       return iobject._retn();
1458     }
1459
1460     // --- get reference from id
1461
1462     CORBA::Object_var obj = _poa->id_to_reference(*id);
1463     iobject = Engines::EngineComponent::_narrow( obj ) ;
1464
1465     _numInstanceMutex.lock() ; // lock to be alone (stl container write)
1466     _listInstances_map[instanceName] = iobject;
1467     _cntInstances_map[aGenRegisterName] += 1;
1468     _numInstanceMutex.unlock() ;
1469     SCRUTE(aGenRegisterName);
1470     SCRUTE(_cntInstances_map[aGenRegisterName]);
1471
1472     // --- register the engine under the name
1473     //     containerName(.dir)/instanceName(.object)
1474
1475     _NS->Register( iobject , component_registerName.c_str() ) ;
1476     MESSAGE( component_registerName.c_str() << " bound" ) ;
1477   }
1478   catch (...)
1479   {
1480     reason="Container_i::createInstance exception caught";
1481     INFOS(reason) ;
1482   }
1483   return iobject._retn();
1484 }
1485
1486 //=============================================================================
1487 //! Find an existing (in the container) component instance
1488 /*!
1489 *  CORBA method: Finds a servant instance of a component
1490 *  \param registeredName  Name of the component in Registry or Name Service,
1491 *                         without instance suffix number
1492 *  \return the first found instance
1493 */
1494 //=============================================================================
1495 Engines::EngineComponent_ptr
1496 Abstract_Engines_Container_i::find_component_instance( const char* registeredName)
1497 {
1498   Engines::EngineComponent_var anEngine = Engines::EngineComponent::_nil();
1499   std::map<std::string,Engines::EngineComponent_var>::iterator itm =_listInstances_map.begin();
1500   while (itm != _listInstances_map.end())
1501   {
1502     std::string instance = (*itm).first;
1503     SCRUTE(instance);
1504     if (instance.find(registeredName) == 0)
1505     {
1506       anEngine = (*itm).second;
1507       return anEngine._retn();
1508     }
1509     itm++;
1510   }
1511   return anEngine._retn();
1512 }
1513
1514 //=============================================================================
1515 //! Remove the component instance from container
1516 /*!
1517 *  CORBA method: Stops the component servant, and deletes all related objects
1518 *  \param component_i     Component to be removed
1519 */
1520 //=============================================================================
1521
1522 void Abstract_Engines_Container_i::remove_impl(Engines::EngineComponent_ptr component_i)
1523 {
1524   ASSERT(! CORBA::is_nil(component_i));
1525   std::string instanceName = component_i->instanceName() ;
1526   MESSAGE("unload component " << instanceName);
1527   _numInstanceMutex.lock() ; // lock to be alone (stl container write)
1528   _listInstances_map.erase(instanceName);
1529   _numInstanceMutex.unlock() ;
1530   component_i->destroy() ;
1531   _NS->Destroy_Name(instanceName.c_str());
1532 }
1533
1534 //=============================================================================
1535 //! Unload component libraries from the container
1536 /*!
1537 *  CORBA method: Discharges unused libraries from the container.
1538 */
1539 //=============================================================================
1540 void Abstract_Engines_Container_i::finalize_removal()
1541 {
1542   MESSAGE("finalize unload : dlclose");
1543   _numInstanceMutex.lock(); // lock to be alone
1544   // (see decInstanceCnt, load_component_Library)
1545   std::map<std::string, void *>::iterator ith;
1546   for (ith = _toRemove_map.begin(); ith != _toRemove_map.end(); ith++)
1547   {
1548     void *handle = (*ith).second;
1549     std::string impl_name= (*ith).first;
1550     if (handle)
1551     {
1552       SCRUTE(handle);
1553       SCRUTE(impl_name);
1554       //        dlclose(handle);                // SALOME unstable after ...
1555       //        _library_map.erase(impl_name);
1556     }
1557   }
1558   _toRemove_map.clear();
1559   _numInstanceMutex.unlock();
1560 }
1561
1562 //=============================================================================
1563 //! Decrement component instance reference count
1564 /*!
1565 *
1566 */
1567 //=============================================================================
1568 void Abstract_Engines_Container_i::decInstanceCnt(std::string genericRegisterName)
1569 {
1570   if(_cntInstances_map.count(genericRegisterName)==0)
1571     return;
1572   std::string aGenRegisterName =genericRegisterName;
1573   MESSAGE("Engines_Container_i::decInstanceCnt " << aGenRegisterName);
1574   ASSERT(_cntInstances_map[aGenRegisterName] > 0);
1575   _numInstanceMutex.lock(); // lock to be alone
1576   // (see finalize_removal, load_component_Library)
1577   _cntInstances_map[aGenRegisterName] -= 1;
1578   SCRUTE(_cntInstances_map[aGenRegisterName]);
1579   if (_cntInstances_map[aGenRegisterName] == 0)
1580   {
1581     std::string impl_name =
1582       Engines_Component_i::GetDynLibraryName(aGenRegisterName.c_str());
1583     SCRUTE(impl_name);
1584     void* handle = _library_map[impl_name];
1585     ASSERT(handle);
1586     _toRemove_map[impl_name] = handle;
1587   }
1588   _numInstanceMutex.unlock();
1589 }
1590
1591 //=============================================================================
1592 //! Find or create a new component instance
1593 /*!
1594 *  CORBA method: find or create an instance of the component (servant),
1595 *  load a new component class (dynamic library) if required,
1596 *
1597 *  ---- FOR COMPATIBILITY WITH 2.2 ----
1598 *
1599 *  ---- USE ONLY FOR MULTISTUDY INSTANCES ! --------
1600 *
1601 *  The servant registers itself to naming service and Registry.
1602 *  \param genericRegisterName  Name of the component to register
1603 *                              in Registry & Name Service
1604 *  \param componentName       Name of the constructed library of the component
1605 *  \return a loaded component
1606 */
1607 //=============================================================================
1608
1609 Engines::EngineComponent_ptr
1610 Abstract_Engines_Container_i::load_impl( const char* genericRegisterName,
1611                                          const char* /*componentName*/ )
1612 {
1613   char* reason;
1614   std::string impl_name = std::string(LIB) + genericRegisterName + ENGINESO;
1615   Engines::EngineComponent_var iobject = Engines::EngineComponent::_nil() ;
1616   if (load_component_Library(genericRegisterName,reason))
1617     iobject = find_or_create_instance(genericRegisterName, impl_name);
1618   CORBA::string_free(reason);
1619   return iobject._retn();
1620 }
1621
1622 Engines::EmbeddedNamingService_ptr Abstract_Engines_Container_i::get_embedded_NS_if_ssl()
1623 {
1624   SALOME_Embedded_NamingService_Client *nsc(dynamic_cast<SALOME_Embedded_NamingService_Client *>(this->_NS));
1625   if(nsc)
1626   {
1627     Engines::EmbeddedNamingService_var obj = nsc->GetObject();
1628     return Engines::EmbeddedNamingService::_duplicate(obj);
1629   }
1630   else
1631   {
1632     SALOME_Fake_NamingService *fns(dynamic_cast<SALOME_Fake_NamingService *>(this->_NS));
1633     if(fns)
1634     {
1635       Engines::EmbeddedNamingService_var ret = GetEmbeddedNamingService();
1636       return ret._retn();
1637     }
1638     else
1639       return Engines::EmbeddedNamingService::_nil();
1640   } 
1641 }
1642
1643 //=============================================================================
1644 //! Finds an already existing component instance or create a new instance
1645 /*!
1646 *  C++ method: Finds an already existing servant instance of a component, or
1647 *              create an instance.
1648 *  ---- USE ONLY FOR MULTISTUDY INSTANCES ! --------
1649 *  \param genericRegisterName    Name of the component instance to register
1650 *                                in Registry & Name Service,
1651 *                                (without _inst_n suffix, like "COMPONENT")
1652 *  \param componentLibraryName   like "libCOMPONENTEngine.so"
1653 *  \return a loaded component
1654 *
1655 *  example with names:
1656 *    - aGenRegisterName = COMPONENT (= first argument)
1657 *    - impl_name = libCOMPONENTEngine.so (= second argument)
1658 *    - _containerName = /Containers/cli76ce/FactoryServer
1659 *    - factoryName = COMPONENTEngine_factory
1660 *    - component_registerBase = /Containers/cli76ce/FactoryServer/COMPONENT
1661 *    - instanceName = COMPONENT_inst_1
1662 *    - component_registerName = /Containers/cli76ce/FactoryServer/COMPONENT_inst_1
1663 */
1664 //=============================================================================
1665
1666 Engines::EngineComponent_ptr
1667 Abstract_Engines_Container_i::find_or_create_instance(std::string genericRegisterName,
1668                                                       std::string componentLibraryName)
1669 {
1670   std::string aGenRegisterName = genericRegisterName;
1671   std::string impl_name = componentLibraryName;
1672   if (_library_map.count(impl_name) == 0)
1673   {
1674     INFOS("shared library " << impl_name <<" must be loaded before creating instance");
1675     return Engines::EngineComponent::_nil() ;
1676   }
1677   else
1678   {
1679     // --- find a registered instance in naming service, or create
1680
1681     void* handle = _library_map[impl_name];
1682     std::string component_registerBase =
1683       _containerName + "/" + aGenRegisterName;
1684     Engines::EngineComponent_var iobject = Engines::EngineComponent::_nil() ;
1685     std::string reason;
1686     try
1687     {
1688       CORBA::Object_var obj =
1689         _NS->ResolveFirst( component_registerBase.c_str());
1690       if ( CORBA::is_nil( obj ) )
1691       {
1692         iobject = createInstance(genericRegisterName,
1693                                  handle,
1694                                  reason);
1695       }
1696       else
1697       {
1698         iobject = Engines::EngineComponent::_narrow( obj ) ;
1699       }
1700     }
1701     catch (...)
1702     {
1703       INFOS( "Container_i::load_impl caught" ) ;
1704     }
1705     return iobject._retn();
1706   }
1707 }
1708
1709 //=============================================================================
1710 //! Indicate if container is a python one
1711 /*! 
1712 *  Retrieves only with container naming convention if it is a python container
1713 */
1714 //=============================================================================
1715 bool Abstract_Engines_Container_i::isPythonContainer(const char* ContainerName)
1716 {
1717   bool ret=false;
1718   size_t len=strlen(ContainerName);
1719   if(len>=2)
1720     if(strcmp(ContainerName+len-2,"Py")==0)
1721       ret=true;
1722   return ret;
1723 }
1724
1725 //=============================================================================
1726 //! Kill the container
1727 /*!
1728 *  CORBA method: Kill the container process with exit(0).
1729 *  To remove :  never returns !
1730 */
1731 //=============================================================================
1732 bool Abstract_Engines_Container_i::Kill_impl()
1733 {
1734   MESSAGE("Engines_Container_i::Kill() pid "<< getpid() << " containerName "
1735     << _containerName.c_str() << " machineName "
1736     << Kernel_Utils::GetHostname().c_str());
1737   INFOS("===============================================================");
1738   INFOS("= REMOVE calls to Kill_impl in C++ container                  =");
1739   INFOS("===============================================================");
1740   //_exit( 0 ) ;
1741   ASSERT(0);
1742   return false;
1743 }
1744
1745 //=============================================================================
1746 /*! 
1747 *  
1748 */
1749 //=============================================================================
1750 void ActSigIntHandler()
1751 {
1752 #ifndef WIN32
1753   struct sigaction SigIntAct ;
1754   SigIntAct.sa_sigaction = &SigIntHandler ;
1755   sigemptyset(&SigIntAct.sa_mask);
1756   SigIntAct.sa_flags = SA_SIGINFO ;
1757 #endif
1758
1759   // DEBUG 03.02.2005 : the first parameter of sigaction is not a mask of signals
1760   // (SIGINT | SIGUSR1) :
1761   // it must be only one signal ===> one call for SIGINT 
1762   // and an other one for SIGUSR1
1763
1764 #ifndef WIN32
1765   if ( sigaction( SIGINT , &SigIntAct, NULL ) ) 
1766   {
1767     perror("SALOME_Container main ") ;
1768     exit(0) ;
1769   }
1770   if ( sigaction( SIGUSR1 , &SigIntAct, NULL ) )
1771   {
1772     perror("SALOME_Container main ") ;
1773     exit(0) ;
1774   }
1775   if ( sigaction( SIGUSR2 , &SigIntAct, NULL ) )
1776   {
1777     perror("SALOME_Container main ") ;
1778     exit(0) ;
1779   }
1780
1781   //PAL9042 JR : during the execution of a Signal Handler (and of methods called through Signal Handlers)
1782   //             use of streams (and so on) should never be used because :
1783   //             streams of C++ are naturally thread-safe and use pthread_mutex_lock ===>
1784   //             A stream operation may be interrupted by a signal and if the Handler use stream we
1785   //             may have a "Dead-Lock" ===HangUp
1786   //==INFOS is commented
1787   //  INFOS(pthread_self() << "SigIntHandler activated") ;
1788
1789 #else  
1790   signal( SIGINT, SigIntHandler );
1791 // legacy code required to supervisor. Commented in order to avoid problems on Windows 
1792 //  signal( SIGUSR1, SigIntHandler );
1793 #endif
1794
1795 }
1796
1797 void SetCpuUsed() ;
1798 void CallCancelThread() ;
1799
1800 #ifndef WIN32
1801 void SigIntHandler(int /*what*/ ,
1802                    siginfo_t * siginfo ,
1803                    void * /*toto*/ ) 
1804 {
1805   //PAL9042 JR : during the execution of a Signal Handler (and of methods called through Signal Handlers)
1806   //             use of streams (and so on) should never be used because :
1807   //             streams of C++ are naturally thread-safe and use pthread_mutex_lock ===>
1808   //             A stream operation may be interrupted by a signal and if the Handler use stream we
1809   //             may have a "Dead-Lock" ===HangUp
1810   //==MESSAGE is commented
1811   //  MESSAGE(pthread_self() << "SigIntHandler what     " << what << std::endl
1812   //          << "              si_signo " << siginfo->si_signo << std::endl
1813   //          << "              si_code  " << siginfo->si_code << std::endl
1814   //          << "              si_pid   " << siginfo->si_pid) ;
1815
1816   if ( _Sleeping )
1817   {
1818     _Sleeping = false ;
1819     //     MESSAGE("SigIntHandler END sleeping.") ;
1820     return ;
1821   }
1822   else
1823   {
1824     ActSigIntHandler() ;
1825     if ( siginfo->si_signo == SIGUSR1 )
1826     {
1827       SetCpuUsed() ;
1828     }
1829     else if ( siginfo->si_signo == SIGUSR2 )
1830     {
1831       CallCancelThread() ;
1832     }
1833     else 
1834     {
1835       _Sleeping = true ;
1836       //      MESSAGE("SigIntHandler BEGIN sleeping.") ;
1837       int count = 0 ;
1838       while( _Sleeping )
1839       {
1840         sleep( 1 ) ;
1841         count += 1 ;
1842       }
1843       //      MESSAGE("SigIntHandler LEAVE sleeping after " << count << " s.") ;
1844     }
1845     return ;
1846   }
1847 }
1848 #else // Case WIN32
1849 void SigIntHandler( int what )
1850 {
1851 #ifndef WIN32
1852   MESSAGE( pthread_self() << "SigIntHandler what     " << what << std::endl );
1853 #else
1854   MESSAGE( "SigIntHandler what     " << what << std::endl );
1855 #endif
1856   if ( _Sleeping )
1857   {
1858     _Sleeping = false ;
1859     MESSAGE("SigIntHandler END sleeping.") ;
1860     return ;
1861   }
1862   else
1863   {
1864     ActSigIntHandler() ;
1865     if ( what == SIGUSR1 )
1866     {
1867       SetCpuUsed() ;
1868     }
1869     else
1870     {
1871       _Sleeping = true ;
1872       MESSAGE("SigIntHandler BEGIN sleeping.") ;
1873       int count = 0 ;
1874       while( _Sleeping ) 
1875       {
1876         Sleep( 1000 ) ;
1877         count += 1 ;
1878       }
1879       MESSAGE("SigIntHandler LEAVE sleeping after " << count << " s.") ;
1880     }
1881     return ;
1882   }
1883 }
1884 #endif
1885
1886 //=============================================================================
1887 //! Get or create a file reference object associated to a local file (to transfer it)
1888 /*!
1889 *  CORBA method: get or create a fileRef object associated to a local file
1890 *  (a file on the computer on which runs the container server), which stores
1891 *  a list of (machine, localFileName) corresponding to copies already done.
1892 *
1893 *  \param  origFileName absolute path for a local file to copy on other
1894 *          computers
1895 *  \return a fileRef object associated to the file.
1896 */
1897 //=============================================================================
1898 Engines::fileRef_ptr
1899 Abstract_Engines_Container_i::createFileRef(const char* origFileName)
1900 {
1901   std::string origName(origFileName);
1902   Engines::fileRef_var theFileRef = Engines::fileRef::_nil();
1903
1904   if (origName[0] != '/')
1905   {
1906     INFOS("path of file to copy must be an absolute path beginning with '/'");
1907     return Engines::fileRef::_nil();
1908   }
1909
1910   if (CORBA::is_nil(_fileRef_map[origName]))
1911   {
1912     CORBA::Object_var obj=_poa->id_to_reference(*_id);
1913     Engines::Container_var pCont = Engines::Container::_narrow(obj);
1914     fileRef_i* aFileRef = new fileRef_i(pCont, origFileName);
1915     theFileRef = Engines::fileRef::_narrow(aFileRef->_this());
1916     _numInstanceMutex.lock() ; // lock to be alone (stl container write)
1917     _fileRef_map[origName] = theFileRef;
1918     _numInstanceMutex.unlock() ;
1919   }
1920
1921   theFileRef =  Engines::fileRef::_duplicate(_fileRef_map[origName]);
1922   ASSERT(! CORBA::is_nil(theFileRef));
1923   return theFileRef._retn();
1924 }
1925
1926 //=============================================================================
1927 //! Get a fileTransfer reference
1928 /*!
1929 *  CORBA method:
1930 *  \return a reference to the fileTransfer object
1931 */
1932 //=============================================================================
1933 Engines::fileTransfer_ptr
1934 Abstract_Engines_Container_i::getFileTransfer()
1935 {
1936   Engines::fileTransfer_var aFileTransfer
1937     = Engines::fileTransfer::_duplicate(_fileTransfer);
1938   return aFileTransfer._retn();
1939 }
1940
1941 //=============================================================================
1942 //! Create a Salome file
1943 //=============================================================================
1944 Engines::Salome_file_ptr
1945 Abstract_Engines_Container_i::createSalome_file(const char* origFileName)
1946 {
1947   std::string origName(origFileName);
1948   if (CORBA::is_nil(_Salome_file_map[origName]))
1949   {
1950     Salome_file_i* aSalome_file = new Salome_file_i();
1951     aSalome_file->setContainer(Engines::Container::_duplicate(this->_this()));
1952     try
1953     {
1954       aSalome_file->setLocalFile(origFileName);
1955       aSalome_file->recvFiles();
1956     }
1957     catch (const SALOME::SALOME_Exception& /*e*/) //!< TODO: unused variable
1958     {
1959       return Engines::Salome_file::_nil();
1960     }
1961
1962     Engines::Salome_file_var theSalome_file = Engines::Salome_file::_nil();
1963     theSalome_file = Engines::Salome_file::_narrow(aSalome_file->_this());
1964     _numInstanceMutex.lock() ; // lock to be alone (stl container write)
1965     _Salome_file_map[origName] = theSalome_file;
1966     _numInstanceMutex.unlock() ;
1967   }
1968
1969   Engines::Salome_file_ptr theSalome_file =
1970     Engines::Salome_file::_duplicate(_Salome_file_map[origName]);
1971   ASSERT(!CORBA::is_nil(theSalome_file));
1972   return theSalome_file;
1973 }
1974
1975 //=============================================================================
1976 /*! \brief copy a file from a remote host (container) to the local host
1977  * \param container the remote container
1978  * \param remoteFile the file to copy locally from the remote host into localFile
1979  * \param localFile the local file
1980  */
1981 //=============================================================================
1982 void Abstract_Engines_Container_i::copyFile(Engines::Container_ptr container, const char* remoteFile, const char* localFile)
1983 {
1984   Engines::fileTransfer_var fileTransfer = container->getFileTransfer();
1985
1986   FILE* fp;
1987   if ((fp = fopen(localFile,"wb")) == NULL)
1988   {
1989     INFOS("file " << localFile << " cannot be open for writing");
1990     return;
1991   }
1992
1993   CORBA::Long fileId = fileTransfer->open(remoteFile);
1994   if (fileId > 0)
1995   {
1996     Engines::fileBlock* aBlock;
1997     int toFollow = 1;
1998     int ctr=0;
1999     while (toFollow)
2000     {
2001       ctr++;
2002       //SCRUTE(ctr);
2003       aBlock = fileTransfer->getBlock(fileId);
2004       toFollow = aBlock->length();
2005       //SCRUTE(toFollow);
2006       CORBA::Octet *buf = aBlock->get_buffer();
2007       fwrite(buf, sizeof(CORBA::Octet), toFollow, fp);
2008       delete aBlock;
2009     }
2010     fclose(fp);
2011     MESSAGE("end of transfer");
2012     fileTransfer->close(fileId);
2013   }
2014   else
2015   {
2016     INFOS("open reference file for copy impossible");
2017   }
2018 }
2019
2020 //=============================================================================
2021 /*! \brief create a PyNode object to execute remote python code
2022  * \param nodeName the name of the node
2023  * \param code the python code to load
2024  * \return the PyNode
2025  */
2026 //=============================================================================
2027 Engines::PyNode_ptr Abstract_Engines_Container_i::createPyNode(const char* nodeName, const char* code)
2028 {
2029   Engines::PyNode_var node= Engines::PyNode::_nil();
2030   long ierr(-1);
2031   std::string astr;
2032   {
2033     AutoGIL gstate;
2034     PyObject *res = PyObject_CallMethod(_pyCont,
2035       (char*)"create_pynode",
2036       (char*)"ss",
2037       nodeName,
2038       code);
2039     if(res==NULL)
2040     {
2041       //internal error
2042       PyErr_Print();
2043       SALOME::ExceptionStruct es;
2044       es.type = SALOME::INTERNAL_ERROR;
2045       es.text = "can not create a python node";
2046       throw SALOME::SALOME_Exception(es);
2047     }
2048     ierr=PyLong_AsLong(PyTuple_GetItem(res,0));
2049     PyObject* result=PyTuple_GetItem(res,1);
2050     astr = PyUnicode_AsUTF8(result);
2051     Py_DECREF(res);
2052   }
2053   if(ierr==0)
2054   {
2055     Utils_Locker lck(&_mutexForDftPy);
2056     CORBA::Object_var obj=_orb->string_to_object(astr.c_str());
2057     node=Engines::PyNode::_narrow(obj);
2058     std::map<std::string,Engines::PyNode_var>::iterator it(_dftPyNode.find(nodeName));
2059     if(it==_dftPyNode.end())
2060     {
2061       _dftPyNode[nodeName]=node;
2062     }
2063     else
2064     {
2065       Engines::PyNode_var oldNode((*it).second);
2066       if(!CORBA::is_nil(oldNode))
2067         oldNode->UnRegister();
2068       (*it).second=node;
2069     }
2070     if(!CORBA::is_nil(node))
2071       node->Register();
2072     return node._retn();
2073   }
2074   else
2075   {
2076     SALOME::ExceptionStruct es;
2077     es.type = SALOME::INTERNAL_ERROR;
2078     es.text = astr.c_str();
2079     throw SALOME::SALOME_Exception(es);
2080   }
2081 }
2082
2083 //=============================================================================
2084 /*! \brief Retrieves the last created PyNode instance with createPyNode.
2085  *
2086  */
2087 //=============================================================================
2088 Engines::PyNode_ptr Abstract_Engines_Container_i::getDefaultPyNode(const char *nodeName)
2089 {
2090   Utils_Locker lck(&_mutexForDftPy);
2091   std::map<std::string,Engines::PyNode_var>::iterator it(_dftPyNode.find(nodeName));
2092   if(it==_dftPyNode.end())
2093     return Engines::PyNode::_nil();
2094   else
2095   {
2096     Engines::PyNode_var tmpVar((*it).second);
2097     if(!CORBA::is_nil(tmpVar))
2098       return Engines::PyNode::_duplicate(tmpVar);
2099     else
2100       return Engines::PyNode::_nil();
2101   }
2102 }
2103
2104 //=============================================================================
2105 /*! \brief create a PyScriptNode object to execute remote python code
2106  * \param nodeName the name of the node
2107  * \param code the python code to load
2108  * \return the PyScriptNode
2109  */
2110 //=============================================================================
2111 Engines::PyScriptNode_ptr Abstract_Engines_Container_i::createPyScriptNode(const char* nodeName, const char* code)
2112 {
2113   Engines::PyScriptNode_var node= Engines::PyScriptNode::_nil();
2114   long ierr(-1);
2115   std::string astr;
2116   {
2117     AutoGIL gstate;
2118     PyObject *res = PyObject_CallMethod(_pyCont,
2119       (char*)"create_pyscriptnode",
2120       (char*)"ss",
2121       nodeName,
2122       code);
2123     if(res==NULL)
2124     {
2125       //internal error
2126       PyErr_Print();
2127       SALOME::ExceptionStruct es;
2128       es.type = SALOME::INTERNAL_ERROR;
2129       es.text = "can not create a python node";
2130       throw SALOME::SALOME_Exception(es);
2131     }
2132     ierr=PyLong_AsLong(PyTuple_GetItem(res,0));
2133     PyObject* result=PyTuple_GetItem(res,1);
2134     astr = PyUnicode_AsUTF8(result);
2135     Py_DECREF(res);
2136   }
2137
2138   if(ierr==0)
2139   {
2140     Utils_Locker lck(&_mutexForDftPy);
2141     CORBA::Object_var obj=_orb->string_to_object(astr.c_str());
2142     node=Engines::PyScriptNode::_narrow(obj);
2143     std::map<std::string,Engines::PyScriptNode_var>::iterator it(_dftPyScriptNode.find(nodeName));
2144     if(it==_dftPyScriptNode.end())
2145     {
2146       _dftPyScriptNode[nodeName]=node;
2147     }
2148     else
2149     {
2150       Engines::PyScriptNode_var oldNode((*it).second);
2151       if(!CORBA::is_nil(oldNode))
2152         oldNode->UnRegister();
2153       (*it).second=node;
2154     }
2155     return node._retn();
2156   }
2157   else
2158   {
2159     SALOME::ExceptionStruct es;
2160     es.type = SALOME::INTERNAL_ERROR;
2161     es.text = astr.c_str();
2162     throw SALOME::SALOME_Exception(es);
2163   }
2164 }
2165
2166 void Abstract_Engines_Container_i::removePyScriptNode(const char *nodeName)
2167 {
2168   std::map<std::string,Engines::PyScriptNode_var>::iterator it(_dftPyScriptNode.find(nodeName));
2169   if(it==_dftPyScriptNode.end())
2170     {
2171       std::ostringstream oss; oss << "Engines_Container_i::removePyScriptNode : node \"" << nodeName << "\" is not map !";
2172       SALOME::ExceptionStruct es;
2173       es.type = SALOME::INTERNAL_ERROR;
2174       es.text = oss.str().c_str();
2175       throw SALOME::SALOME_Exception(es);
2176     }
2177   (*it).second->UnRegister();
2178   _dftPyScriptNode.erase(it);
2179 }
2180
2181 void Abstract_Engines_Container_i::cleanAllPyScripts()
2182 {
2183   for(std::map<std::string,Engines::PyNode_var>::iterator it=_dftPyNode.begin();it!=_dftPyNode.end();it++)
2184     {
2185       Engines::PyNode_var tmpVar((*it).second);
2186       if(!CORBA::is_nil(tmpVar))
2187         tmpVar->UnRegister();
2188     }
2189   _dftPyNode.clear();
2190   for(std::map<std::string,Engines::PyScriptNode_var>::iterator it=_dftPyScriptNode.begin();it!=_dftPyScriptNode.end();it++)
2191     {
2192       Engines::PyScriptNode_var tmpVar((*it).second);
2193       if(!CORBA::is_nil(tmpVar))
2194         tmpVar->UnRegister();
2195     }
2196   _dftPyScriptNode.clear();
2197 }
2198
2199 //=============================================================================
2200 /*! \brief Retrieves the last created PyScriptNode instance with createPyScriptNode.
2201  *
2202  */
2203 //=============================================================================
2204 Engines::PyScriptNode_ptr Abstract_Engines_Container_i::getDefaultPyScriptNode(const char *nodeName)
2205 {
2206   Utils_Locker lck(&_mutexForDftPy);
2207   std::map<std::string,Engines::PyScriptNode_var>::iterator it(_dftPyScriptNode.find(nodeName));
2208   if(it==_dftPyScriptNode.end())
2209     return Engines::PyScriptNode::_nil();
2210   else
2211   {
2212     Engines::PyScriptNode_var tmpVar((*it).second);
2213     if(!CORBA::is_nil(tmpVar))
2214       return Engines::PyScriptNode::_duplicate(tmpVar);
2215     else
2216       return Engines::PyScriptNode::_nil();
2217   }
2218 }
2219
2220 //=============================================================================
2221 /* int checkifexecutable(const char *filename)
2222 *
2223 * Return non-zero if the name is an executable file, and
2224 * zero if it is not executable, or if it does not exist.
2225 */
2226 //=============================================================================
2227 int checkifexecutable(const std::string& filename)
2228 {
2229   int result;
2230   struct stat statinfo;
2231
2232   result = stat(filename.c_str(), &statinfo);
2233   if (result < 0) return 0;
2234   if (!S_ISREG(statinfo.st_mode)) return 0;
2235
2236 #ifdef WIN32
2237   return 1;
2238 #else
2239   if (statinfo.st_uid == geteuid()) return statinfo.st_mode & S_IXUSR;
2240   if (statinfo.st_gid == getegid()) return statinfo.st_mode & S_IXGRP;
2241   return statinfo.st_mode & S_IXOTH;
2242 #endif
2243 }
2244
2245
2246 //=============================================================================
2247 /*! \brief Find a file by searching in a path
2248  *  \param filename file name to search
2249  *  \param path path to search in
2250  *  \param pth the complete file path if found
2251  *  \return 1 if found 0 if not 
2252 */
2253 //=============================================================================
2254 int findpathof(const std::string& path, std::string& pth, const std::string& filename)
2255 {
2256   if ( path.size() == 0 ) return 0;
2257
2258   std::string::size_type offset = 0;
2259   std::string::size_type pos = 0;
2260   int found = 0;
2261   struct stat statinfo;
2262
2263   while(!found)
2264   {
2265     pos = path.find( SEP, offset );
2266     pth = path.substr( offset, pos - offset );
2267     if ( pth.size() > 0 )
2268     {
2269       if( pth[pth.size()-1] != SLASH ) pth += SLASH;
2270       pth += filename;
2271       int result=stat(pth.c_str(), &statinfo);
2272       if(result == 0) found=1;
2273     }
2274     if (pos == std::string::npos) break;
2275     offset = pos+1;
2276   }
2277   return found;
2278 }
2279
2280 void Abstract_Engines_Container_i::registerTemporaryFile( const std::string& fileName )
2281 {
2282   _tmp_files.remove( fileName );
2283   _tmp_files.push_back( fileName );
2284 }
2285
2286 void Abstract_Engines_Container_i::unregisterTemporaryFile( const std::string& fileName )
2287 {
2288   _tmp_files.remove( fileName );
2289 }
2290
2291 void Abstract_Engines_Container_i::clearTemporaryFiles()
2292 {
2293   std::list<std::string>::const_iterator it;
2294   for ( it = _tmp_files.begin(); it != _tmp_files.end(); ++it ) {
2295 #if defined(WIN32) && defined(UNICODE)
2296         std::wstring aFile = Kernel_Utils::utf8_decode_s(*it);
2297         std::wstring command = (GetFileAttributes(aFile.c_str()) == FILE_ATTRIBUTE_DIRECTORY) ? L"rd /Q \"" : L"del /F /Q \"";
2298         command += aFile;
2299         command += L"\" 2>NUL";
2300         _wsystem(command.c_str());
2301 #else
2302 #if defined(WIN32)
2303         std::string aFile = *it;
2304         std::string command = (GetFileAttributes(aFile.c_str()) == FILE_ATTRIBUTE_DIRECTORY) ? "rd /Q \"" : "del /F /Q \"";
2305         command += aFile;
2306         command += "\" 2>NUL";
2307 #else
2308         std::string command = "rm -rf ";
2309         command += *it;
2310 #endif
2311         system(command.c_str());
2312 #endif
2313   }
2314   _tmp_files.clear();
2315 }
2316
2317 static Engines_Container_SSL_i *_container_singleton_ssl = nullptr;
2318
2319 static Engines::Container_var _container_ref_singleton_ssl;
2320
2321 Engines_Container_SSL_i *KERNEL::getContainerSA()
2322 {
2323   if(!_container_singleton_ssl)
2324   {
2325     CORBA::ORB_var orb = KERNEL::GetRefToORB();
2326     CORBA::Object_var obj = orb->resolve_initial_references("RootPOA");
2327     PortableServer::POA_var poa = PortableServer::POA::_narrow(obj);
2328     PortableServer::POAManager_var pman = poa->the_POAManager();
2329     CORBA::PolicyList policies;
2330     policies.length(0);
2331     //
2332     char *argv[4] = {"Container","FactoryServer","toto",nullptr};
2333     SALOME_Fake_NamingService ns;
2334     _container_singleton_ssl = new Engines_Container_SSL_i(orb,poa,"FactoryServer",2,argv,&ns,false);
2335     PortableServer::ObjectId * cont_id = _container_singleton_ssl->getCORBAId();
2336     //
2337     CORBA::Object_var zeRef = poa->id_to_reference(*cont_id);
2338     _container_ref_singleton_ssl = Engines::Container::_narrow(zeRef);
2339   }
2340   return _container_singleton_ssl;
2341 }
2342
2343 Engines::Container_var KERNEL::getContainerRefSA()
2344 {
2345   getContainerSA();
2346   return _container_ref_singleton_ssl;
2347 }