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