Salome HOME
Kernel evolution for salome gui without neither NS nor other servers.
[modules/kernel.git] / src / Container / Container_i.cxx
1 // Copyright (C) 2007-2020  CEA/DEN, EDF R&D, 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 #ifndef WIN32
35 #include <sys/time.h>
36 #include <dlfcn.h>
37 #include <unistd.h>
38 #include <sys/wait.h>
39 #else
40 #include <signal.h>
41 #include <process.h>
42 #include <direct.h>
43 int SIGUSR1 = 1000;
44 #endif
45
46 #include "utilities.h"
47 #include <SALOMEconfig.h>
48 #include CORBA_SERVER_HEADER(SALOME_Component)
49 #include CORBA_SERVER_HEADER(SALOME_Exception)
50 #include <pthread.h>  // must be before Python.h !
51 #include "SALOME_Container_i.hxx"
52 #include "SALOME_Component_i.hxx"
53 #include "SALOME_FileRef_i.hxx"
54 #include "SALOME_FileTransfer_i.hxx"
55 #include "Salome_file_i.hxx"
56 #include "SALOME_NamingService.hxx"
57 #include "SALOME_Fake_NamingService.hxx"
58 #include "Basics_Utils.hxx"
59
60 #ifdef _XOPEN_SOURCE
61 #undef _XOPEN_SOURCE
62 #endif
63
64 #include <Python.h>
65 #include "Container_init_python.hxx"
66
67 bool _Sleeping = false ;
68
69 // // Needed by multi-threaded Python --- Supervision
70 int _ArgC ;
71 char ** _ArgV ;
72
73 extern "C" {void ActSigIntHandler() ; }
74 #ifndef WIN32
75 extern "C" {void SigIntHandler(int, siginfo_t *, void *) ; }
76 #else
77 extern "C" {void SigIntHandler( int ) ; }
78 #endif
79
80 #ifndef WIN32
81 #define LIB "lib"
82 #ifdef __APPLE__
83 #define ENGINESO "Engine.dylib"
84 #else
85 #define ENGINESO "Engine.so"
86 #endif
87 #else
88 #define LIB ""
89 #define ENGINESO "Engine.dll"
90 #endif
91
92 #ifdef WIN32
93 #define SEP ';'
94 #define SLASH '\\'
95 #else
96 #define SEP ':'
97 #define SLASH '/'
98 #endif
99
100 std::map<std::string, int> Engines_Container_i::_cntInstances_map;
101 std::map<std::string, void *> Engines_Container_i::_library_map;
102 std::map<std::string, void *> Engines_Container_i::_toRemove_map;
103 omni_mutex Engines_Container_i::_numInstanceMutex ;
104
105 static PyObject* _pyCont;
106
107 int checkifexecutable(const std::string&);
108 int findpathof(const std::string& path, std::string&, const std::string&);
109
110 /*! \class Engines_Container_i
111  *  \brief C++ implementation of Engines::Container interface
112  *
113  */
114
115
116 //=============================================================================
117 /*! 
118 *  Default constructor, not for use
119 */
120 //=============================================================================
121
122 Engines_Container_i::Engines_Container_i () :
123   _NS(0),_id(0),_numInstance(0)
124 {
125 }
126
127 //=============================================================================
128 /*! 
129 *  Constructor to use
130 */
131 //=============================================================================
132
133 Engines_Container_i::Engines_Container_i (CORBA::ORB_ptr orb, 
134                                           PortableServer::POA_ptr poa,
135                                           char *containerName ,
136                                           int argc , char* argv[],
137                                           SALOME_NamingService_Abstract *ns,
138                                           bool isServantAloneInProcess
139                                           ) :
140   _NS(0),_id(0),_numInstance(0),_isServantAloneInProcess(isServantAloneInProcess)
141 {
142   _pid = (long)getpid();
143
144   if(ns)
145     ActSigIntHandler() ;
146
147   _argc = argc ;
148   _argv = argv ;
149
150   std::string hostname = Kernel_Utils::GetHostname();
151 #ifndef WIN32
152   MESSAGE(hostname << " " << getpid() << 
153     " Engines_Container_i starting argc " <<
154     _argc << " Thread " << pthread_self() ) ;
155 #else
156   MESSAGE(hostname << " " << _getpid() << 
157     " Engines_Container_i starting argc " << _argc<< " Thread " << pthread_self().p ) ;
158 #endif
159
160   int i = 0 ;
161   while ( _argv[ i ] )
162   {
163     MESSAGE("           argv" << i << " " << _argv[ i ]) ;
164     i++ ;
165   }
166
167   if ( argc < 2 )
168   {
169     INFOS("SALOME_Container usage : SALOME_Container ServerName");
170     ASSERT(0) ;
171   }
172   SCRUTE(argv[1]);
173   _isSupervContainer = false;
174
175   _orb = CORBA::ORB::_duplicate(orb) ;
176   _poa = PortableServer::POA::_duplicate(poa) ;
177
178   // Pour les containers paralleles: il ne faut pas enregistrer et activer
179   // le container generique, mais le container specialise
180
181   {
182     _id = _poa->activate_object(this);
183     _NS = ns==nullptr ? new SALOME_NamingService : ns->clone();
184     _NS->init_orb( _orb ) ;
185     CORBA::Object_var obj=_poa->id_to_reference(*_id);
186     Engines::Container_var pCont 
187       = Engines::Container::_narrow(obj);
188     _remove_ref();
189
190     _containerName = _NS->BuildContainerNameForNS(containerName,
191       hostname.c_str());
192     SCRUTE(_containerName);
193     _NS->Register(pCont, _containerName.c_str());
194     MESSAGE("Engines_Container_i::Engines_Container_i : Container name "
195       << _containerName);
196
197     // Python: 
198     // import SALOME_Container
199     // pycont = SALOME_Container.SALOME_Container_i(containerIORStr)
200
201     CORBA::String_var sior =  _orb->object_to_string(pCont);
202     std::string myCommand="pyCont = SALOME_Container.SALOME_Container_i('";
203     myCommand += _containerName + "','";
204     myCommand += sior;
205     myCommand += "')\n";
206     SCRUTE(myCommand);
207
208     //[RNV]: Comment the PyEval_AcquireLock() and PyEval_ReleaseLock() because this 
209     //approach leads to the deadlock of the main thread of the application on Windows platform
210     //in case if cppContainer runs in the standalone mode. The problem with the PyThreadState 
211     //described by ABN seems not reproduced, to be checked carefully later...
212     PyGILState_STATE gstate = PyGILState_Ensure();
213     
214     //// [ABN]: using the PyGILState* API here is unstable. omniORB logic is invoked
215     //// by the Python code executed below, and in some (random) cases, the Python code
216     //// execution ends with a PyThreadState which was not the one we have here.
217     //// (TODO: understand why ...)
218     //// To be on the safe side we get and load the thread state ourselves:    
219     //PyEval_AcquireLock();  // get GIL
220     //PyThreadState * mainThreadState = PyThreadState_Get();
221     //PyThreadState_Swap(mainThreadState);
222
223 #ifdef WIN32
224     // mpv: this is temporary solution: there is a unregular crash if not
225     //Sleep(2000);
226     //
227     // first element is the path to Registry.dll, but it's wrong
228     PyRun_SimpleString("import sys\n");
229     PyRun_SimpleString("sys.path = sys.path[1:]\n");
230 #endif
231     PyRun_SimpleString("import SALOME_Container\n");
232     PyRun_SimpleString((char*)myCommand.c_str());
233     PyObject *mainmod = PyImport_AddModule("__main__");
234     PyObject *globals = PyModule_GetDict(mainmod);
235     _pyCont = PyDict_GetItemString(globals, "pyCont");
236
237     //PyThreadState_Swap(NULL);
238     //PyEval_ReleaseLock();
239     PyGILState_Release(gstate);
240
241     fileTransfer_i* aFileTransfer = new fileTransfer_i();
242     CORBA::Object_var obref=aFileTransfer->_this();
243     _fileTransfer = Engines::fileTransfer::_narrow(obref);
244     aFileTransfer->_remove_ref();
245   }
246 }
247
248 //=============================================================================
249 /*! 
250 *  Destructor
251 */
252 //=============================================================================
253
254 Engines_Container_i::~Engines_Container_i()
255 {
256   MESSAGE("Container_i::~Container_i()");
257   if(_id)
258     delete _id;
259   if(_NS)
260     delete _NS;
261   cleanAllPyScripts();
262 }
263
264 //=============================================================================
265 //! Get container name
266 /*! 
267 *  CORBA attribute: Container name (see constructor)
268 */
269 //=============================================================================
270
271 char* Engines_Container_i::name()
272 {
273   return CORBA::string_dup(_containerName.c_str()) ;
274 }
275
276 //=============================================================================
277 //! Get container working directory
278 /*! 
279 *  CORBA attribute: Container working directory 
280 */
281 //=============================================================================
282
283 char* Engines_Container_i::workingdir()
284 {
285   char wd[256];
286   getcwd (wd,256);
287   return CORBA::string_dup(wd) ;
288 }
289
290 //=============================================================================
291 //! Get container log file name
292 /*! 
293 *  CORBA attribute: Container log file name
294 */
295 //=============================================================================
296
297 char* Engines_Container_i::logfilename()
298 {
299   return CORBA::string_dup(_logfilename.c_str()) ;
300 }
301
302 //! Set container log file name
303 void Engines_Container_i::logfilename(const char* name)
304 {
305   _logfilename=name;
306 }
307
308 //=============================================================================
309 //! Get container host name
310 /*! 
311 *  CORBA method: Get the hostName of the Container (without domain extensions)
312 */
313 //=============================================================================
314
315 char* Engines_Container_i::getHostName()
316 {
317   std::string s = Kernel_Utils::GetHostname();
318   //  MESSAGE("Engines_Container_i::getHostName " << s);
319   return CORBA::string_dup(s.c_str()) ;
320 }
321
322 //=============================================================================
323 //! Get container PID
324 /*! 
325 *  CORBA method: Get the PID (process identification) of the Container
326 */
327 //=============================================================================
328
329 CORBA::Long Engines_Container_i::getPID()
330 {
331   return (CORBA::Long)getpid();
332 }
333
334 //=============================================================================
335 //! Ping the servant to check it is still alive
336 /*! 
337 *  CORBA method: check if servant is still alive
338 */
339 //=============================================================================
340 void Engines_Container_i::ping()
341 {
342   MESSAGE("Engines_Container_i::ping() pid "<< getpid());
343 }
344
345 //=============================================================================
346 //! Shutdown the container
347 /*! 
348 *  CORBA method, oneway: Server shutdown. 
349 *  - Container name removed from naming service,
350 *  - servant deactivation,
351 *  - orb shutdown if no other servants in the process 
352 */
353 //=============================================================================
354 void Engines_Container_i::Shutdown()
355 {
356   MESSAGE("Engines_Container_i::Shutdown()");
357
358   // Clear registered temporary files
359   clearTemporaryFiles();
360
361   /* For each component contained in this container
362   * tell it to self-destroy
363   */
364   std::map<std::string, Engines::EngineComponent_var>::iterator itm;
365   for (itm = _listInstances_map.begin(); itm != _listInstances_map.end(); itm++)
366   {
367     try
368     {
369       itm->second->destroy();
370     }
371     catch(const CORBA::Exception&)
372     {
373       // ignore this entry and continue
374     }
375     catch(...)
376     {
377       // ignore this entry and continue
378     }
379   }
380   _listInstances_map.clear();
381
382   _NS->Destroy_FullDirectory(_containerName.c_str());
383   _NS->Destroy_Name(_containerName.c_str());
384   if(_isServantAloneInProcess)
385   {
386     MESSAGE("Effective Shutdown of container Begins...");
387     if(!CORBA::is_nil(_orb))
388       _orb->shutdown(0);
389   }
390 }
391
392 //=============================================================================
393 //! load a component implementation
394 /*! 
395 *  CORBA method
396 *  \param componentName         component name
397 *  \param reason                explains error when load fails
398 *  \return true if dlopen successful or already done, false otherwise
399 */
400 //=============================================================================
401 bool
402 Engines_Container_i::load_component_Library(const char* componentName, CORBA::String_out reason)
403 {
404
405   //=================================================================
406   // --- C++ implementation section 
407   //=================================================================
408   std::string retso;
409   if(load_component_CppImplementation(componentName,retso))
410   {
411     reason=CORBA::string_dup("");
412     return true;
413   }
414   else if(retso != "ImplementationNotFound")
415   {
416     reason=CORBA::string_dup(retso.c_str());
417     return false;
418   }
419
420   retso="Component ";
421   retso+=componentName;
422   retso+=": Can't find C++ implementation ";
423   retso+=std::string(LIB) + componentName + ENGINESO;
424
425   //=================================================================
426   // --- Python implementation section 
427   //=================================================================
428   std::string retpy;
429   if(load_component_PythonImplementation(componentName,retpy))
430   {
431     reason=CORBA::string_dup("");
432     return true;
433   }
434   else if(retpy != "ImplementationNotFound")
435   {
436     reason=CORBA::string_dup(retpy.c_str());
437     return false;
438   }
439   
440   retpy="Component ";
441   retpy+=componentName;
442   retpy+=": Can't find python implementation ";
443   retpy+=componentName;
444   retpy+="(.py)";
445
446   //=================================================================
447   // -- Executable implementation section
448   //=================================================================
449   std::string retex;
450   if(load_component_ExecutableImplementation(componentName,retex))
451   {
452     reason=CORBA::string_dup("");
453     return true;
454   }
455   else if(retex != "ImplementationNotFound")
456   {
457     reason=CORBA::string_dup(retex.c_str());
458     return false;
459   }
460
461   retex="Component ";
462   retex+=componentName;
463   retex+=": Can't find executable implementation ";
464   retex+=componentName;
465   retex+=".exe";
466
467   std::string ret="Component implementation not found: ";
468   ret += componentName ;
469   ret += '\n' ;
470   ret += retso+ '\n' ;
471   ret += retpy+ '\n' ;
472   ret += retex+ '\n' ;
473
474   std::cerr << ret << std::endl;
475   reason=CORBA::string_dup(ret.c_str());
476
477   return false;
478 }
479
480 //=============================================================================
481 //! try to load a C++ component implementation
482 /*! 
483 *  C++ method: 
484 *  \param componentName      the name of the component (COMPONENT, for example)
485 *  \param reason             explains error when load fails
486 *  \return true if loading is successful or already done, false otherwise
487 */
488 //=============================================================================
489 bool
490 Engines_Container_i::load_component_CppImplementation(const char* componentName, std::string& reason)
491 {
492   std::string aCompName(componentName);
493   std::string impl_name = std::string(LIB) + aCompName + ENGINESO;
494   SCRUTE(impl_name);
495
496   _numInstanceMutex.lock(); // lock to be alone
497   // (see decInstanceCnt, finalize_removal))
498   if (_toRemove_map.count(impl_name) != 0) _toRemove_map.erase(impl_name);
499   if (_library_map.count(impl_name) != 0)
500   {
501     MESSAGE("Library " << impl_name << " already loaded");
502     _numInstanceMutex.unlock();
503     reason="";
504     return true;
505   }
506   _numInstanceMutex.unlock();
507
508 #ifndef WIN32
509   void* handle;
510   handle = dlopen( impl_name.c_str() , RTLD_NOW | RTLD_GLOBAL ) ;
511   if ( !handle )
512   {
513     //not loadable. Try to find the lib file in LD_LIBRARY_PATH
514     std::string path;
515 #ifdef __APPLE__
516       char* p=getenv("DYLD_LIBRARY_PATH");
517 #else
518       char* p=getenv("LD_LIBRARY_PATH");
519 #endif
520       if(p)path=p;
521       path=path+SEP+"/usr/lib"+SEP+"/lib";
522
523       std::string pth;
524       if(findpathof(path, pth, impl_name))
525         {
526           //found but not loadable
527           reason="Component ";
528           reason+=aCompName;
529           reason+=": C++ implementation found ";
530           reason+=pth;
531           reason+=" but it is not loadable. Error:\n";
532           reason+=dlerror();
533           std::cerr << reason << std::endl;
534           return false;
535         }
536       else
537         {
538           //not found
539           //continue with other implementation
540           reason="ImplementationNotFound";
541           return false;
542     }
543   }
544 #else
545   HINSTANCE handle;
546 #ifdef UNICODE
547   std::wstring libToLoad = Kernel_Utils::utf8_decode_s( impl_name );
548 #else
549   std::string libToLoad = impl_name;
550 #endif
551   handle = LoadLibrary(libToLoad.c_str() );
552   if ( !handle )
553   {
554     reason="ImplementationNotFound";
555   }
556 #endif
557
558   if ( handle )
559   {
560     _numInstanceMutex.lock();
561     _library_map[impl_name] = handle;
562     _numInstanceMutex.unlock();
563     reason="";
564     return true;
565   }
566
567   return false;
568
569 }
570 //=============================================================================
571 //! try to load a Python component implementation
572 /*! 
573 *  C++ method: 
574 *  \param componentName         name of the component
575 *  \param reason                explains error when load fails
576 *  \return true if loading is successful or already done, false otherwise
577 */
578 //=============================================================================
579 bool
580 Engines_Container_i::load_component_PythonImplementation(const char* componentName, std::string& reason)
581 {
582   std::string aCompName(componentName);
583
584   _numInstanceMutex.lock() ; // lock to be alone (stl container write)
585   if (_library_map.count(aCompName) != 0)
586   {
587     _numInstanceMutex.unlock() ;
588     reason="";
589     return true; // Python Component, already imported
590   }
591   _numInstanceMutex.unlock() ;
592
593   PyGILState_STATE gstate = PyGILState_Ensure();
594   PyObject *result = PyObject_CallMethod(_pyCont,
595                                          (char*)"import_component",
596                                          (char*)"s",componentName);
597
598   reason=PyUnicode_AsUTF8(result);
599   Py_XDECREF(result);
600   SCRUTE(reason);
601   PyGILState_Release(gstate);
602
603   if (reason=="")
604   {
605     //Python component has been loaded (import componentName)
606     _numInstanceMutex.lock() ; // lock to be alone (stl container write)
607     _library_map[aCompName] = (void *)_pyCont; // any non O value OK
608     _numInstanceMutex.unlock() ;
609     MESSAGE("import Python: "<< aCompName <<" OK");
610     return true;
611   }
612   else if(reason=="ImplementationNotFound")
613   {
614     //Python implementation has not been found. Continue with other implementation
615     reason="ImplementationNotFound";
616   }
617   else
618   {
619     //Python implementation has been found but loading has failed
620     std::cerr << reason << std::endl;
621   }
622   return false;
623
624 }
625 //=============================================================================
626 //! try to load a Executable component implementation
627 /*! 
628 *  C++ method: 
629 *  \param componentName        name of the component
630 *  \param reason               explains error when load fails
631 *  \return true if loading is successful or already done, false otherwise
632 */
633 //=============================================================================
634 bool
635 Engines_Container_i::load_component_ExecutableImplementation(const char* componentName, std::string& reason)
636 {
637   std::string aCompName(componentName);
638   std::string executable=aCompName+".exe";
639
640   std::string path;
641   std::string pth;
642
643   char* p=getenv("PATH");
644   if(p)path=p;
645
646   if (findpathof(path, pth, executable))
647   {
648     if(checkifexecutable(pth))
649     {
650       _numInstanceMutex.lock() ; // lock to be alone (stl container write)
651       _library_map[executable] = (void *)1; // any non O value OK
652       _numInstanceMutex.unlock() ;
653       MESSAGE("import executable: "<< pth <<" OK");
654       reason="";
655       return true;
656     }
657     reason="Component ";
658     reason+=aCompName;
659     reason+=": implementation found ";
660     reason+=pth;
661     reason+=" but it is not executable";
662     std::cerr << reason << std::endl;
663   }
664   else
665   {
666     reason="ImplementationNotFound";
667   }
668   return false;
669 }
670
671 //=============================================================================
672 //! Create a new component instance
673 /*! 
674 *  CORBA method: Creates a new servant instance of a component.
675 *  The servant registers itself to naming service and Registry.
676 *  \param genericRegisterName  Name of the component instance to register
677 *                         in Registry & Name Service (without _inst_n suffix)
678 *  \return a loaded component
679 */
680 //=============================================================================
681 Engines::EngineComponent_ptr
682 Engines_Container_i::create_component_instance(const char*genericRegisterName)
683 {
684   Engines::FieldsDict_var env = new Engines::FieldsDict;
685   char* reason;
686   Engines::EngineComponent_ptr compo =
687     create_component_instance_env(genericRegisterName, env, reason);
688   CORBA::string_free(reason);
689   return compo;
690 }
691
692 //=============================================================================
693 //! Create a new component instance with environment variables specified
694 /*! 
695 *  CORBA method: Creates a new servant instance of a component.
696 *  The servant registers itself to naming service and Registry.
697 *  \param genericRegisterName  Name of the component instance to register
698 *                         in Registry & Name Service (without _inst_n suffix)
699 *  \param env             dict of env variables
700 *  \param reason          explains error when create_component_instance_env fails
701 *  \return a loaded component
702 */
703 //=============================================================================
704 Engines::EngineComponent_ptr
705 Engines_Container_i::create_component_instance_env(const char*genericRegisterName,
706                                                    const Engines::FieldsDict& env,
707                                                    CORBA::String_out reason)
708 {
709   std::string error;
710   if (_library_map.count(genericRegisterName) != 0)
711   {
712     // It's a Python component
713     Engines::EngineComponent_ptr compo = createPythonInstance(genericRegisterName, error);
714     reason=CORBA::string_dup(error.c_str());
715     return compo;
716   }
717
718   std::string impl_name = std::string(LIB) + genericRegisterName + ENGINESO;
719   if (_library_map.count(impl_name) != 0)
720   {
721     // It's a C++ component
722     void* handle = _library_map[impl_name];
723     Engines::EngineComponent_ptr compo = createInstance(genericRegisterName, handle, error);
724     reason=CORBA::string_dup(error.c_str());
725     return compo;
726   }
727
728   impl_name = std::string(genericRegisterName) + ".exe";
729   if (_library_map.count(impl_name) != 0)
730   {
731     //It's an executable component
732     Engines::EngineComponent_ptr compo = createExecutableInstance(genericRegisterName, env, error);
733     reason=CORBA::string_dup(error.c_str());
734     return compo;
735   }
736
737   error="load_component_Library has probably not been called for component: ";
738   error += genericRegisterName;
739   INFOS(error);
740   reason=CORBA::string_dup(error.c_str());
741   return Engines::EngineComponent::_nil() ;
742 }
743
744 //=============================================================================
745 //! Create a new component instance (Executable implementation)
746 /*! 
747 *  \param CompName               Name of the component instance
748 *  \param env                    dict of env variables
749 *  \param reason                 explains error when creation fails
750 *  \return a loaded component
751 *
752 *   This component is implemented in an executable with name genericRegisterName.exe
753 *   It must register itself in Naming Service. The container waits some time (10 s max)
754 *   it's registration.
755 */
756 //=============================================================================
757 Engines::EngineComponent_ptr
758 Engines_Container_i::createExecutableInstance(std::string CompName,
759                                               const Engines::FieldsDict& env,
760                                               std::string& reason)
761 {
762   Engines::EngineComponent_var iobject = Engines::EngineComponent::_nil() ;
763
764   _numInstanceMutex.lock() ; // lock on the instance number
765   _numInstance++ ;
766   int numInstance = _numInstance ;
767   _numInstanceMutex.unlock() ;
768
769   char aNumI[12];
770   sprintf( aNumI , "%d" , numInstance ) ;
771   std::string instanceName = CompName + "_inst_" + aNumI ;
772   std::string component_registerName = _containerName + "/" + instanceName;
773
774   //check if an entry exist in naming service
775   CORBA::Object_var nsobj = _NS->Resolve(component_registerName.c_str());
776   if ( !CORBA::is_nil(nsobj) )
777   {
778     // unregister the registered component
779     _NS->Destroy_Name(component_registerName.c_str());
780     //kill or shutdown it ???
781   }
782
783   // first arg container ior string
784   // second arg container name
785   // third arg instance name
786
787   Engines::Container_var pCont= _this();
788   CORBA::String_var sior =  _orb->object_to_string(pCont);
789
790   std::string command;
791   command="mkdir -p ";
792   command+=instanceName;
793   command+=";cd ";
794   command+=instanceName;
795   command+=";";
796   command+=CompName ;
797   command+=".exe";
798   command+=" ";
799   command+= sior; // container ior string
800   command+=" ";
801   command+=_containerName; //container name
802   command+=" ";
803   command+=instanceName; //instance name
804   command+=" &";
805   MESSAGE("SALOME_Container::create_component_instance command=" << command);
806
807 #ifndef WIN32
808   // use fork/execl instead of system to get finer control on env variables
809   int status;
810   pid_t pid = fork();
811   if(pid == 0) // child
812   {
813     for (CORBA::ULong i=0; i < env.length(); i++)
814     {
815       if (env[i].value.type()->kind() == CORBA::tk_string)
816       {
817         const char* value;
818         env[i].value >>= value;
819         std::string s(env[i].key);
820         s+='=';
821         s+=value;
822         putenv(strdup(s.c_str()));
823       }
824     }
825
826     execl("/bin/sh", "sh", "-c", command.c_str() , (char *)0);
827     status=-1;
828   }
829   else if(pid < 0)       // failed to fork
830   {
831     status=-1;
832   }
833   else            //parent
834   {
835     pid_t tpid;
836     do
837     {
838       tpid = wait(&status);
839     } while (tpid != pid);
840   }
841 #else
842   // launch component with a system call
843   int status=system(command.c_str());
844 #endif
845
846   if (status == -1)
847   {
848     reason="SALOME_Container::create_component_instance system failed (system command status -1)";
849     MESSAGE(reason);
850     return Engines::EngineComponent::_nil();
851   }
852 #ifndef WIN32
853   else if (WEXITSTATUS(status) == 217)
854   {
855     reason="SALOME_Container::create_component_instance system failed (system command status 217)";
856     MESSAGE(reason);
857     return Engines::EngineComponent::_nil();
858   }
859 #endif
860   else
861   {
862     int count=20;
863     if (getenv("TIMEOUT_TO_WAIT_EXE_COMPONENT") != 0)
864     {
865       std::string new_count_str = getenv("TIMEOUT_TO_WAIT_EXE_COMPONENT");
866       int new_count;
867       std::istringstream ss(new_count_str);
868       if (!(ss >> new_count))
869       {
870         INFOS("[Container] TIMEOUT_TO_WAIT_EXE_COMPONENT should be an int");
871       }
872       else
873         count = new_count;
874     }
875     INFOS("[Container] waiting " << count << " second steps exe component ");
876     CORBA::Object_var obj = CORBA::Object::_nil() ;
877     while ( CORBA::is_nil(obj) && count )
878     {
879 #ifndef WIN32
880       sleep( 1 ) ;
881 #else
882       Sleep(1000);
883 #endif
884       count-- ;
885       MESSAGE( count << ". Waiting for component " << CompName);
886       obj = _NS->Resolve(component_registerName.c_str());
887     }
888
889     if(CORBA::is_nil(obj))
890     {
891       reason="SALOME_Container::create_component_instance failed";
892       MESSAGE(reason);
893       return Engines::EngineComponent::_nil();
894     }
895     else
896     {
897       MESSAGE("SALOME_Container::create_component_instance successful");
898       iobject = Engines::EngineComponent::_narrow(obj);
899       _listInstances_map[instanceName] = iobject;
900       return iobject._retn();
901     }
902   }
903 }
904
905
906 //=============================================================================
907 //! Create a new component instance (Python implementation)
908 /*! 
909 *  \param CompName               Name of the component instance
910 *  \param reason                 explains error when creation fails
911 *  \return a loaded component
912 */
913 //=============================================================================
914 Engines::EngineComponent_ptr
915 Engines_Container_i::createPythonInstance(std::string CompName,
916                                           std::string& reason)
917 {
918   Engines::EngineComponent_var iobject = Engines::EngineComponent::_nil() ;
919
920   _numInstanceMutex.lock() ; // lock on the instance number
921   _numInstance++ ;
922   int numInstance = _numInstance ;
923   _numInstanceMutex.unlock() ;
924
925   char aNumI[12];
926   sprintf( aNumI , "%d" , numInstance ) ;
927   std::string instanceName = CompName + "_inst_" + aNumI ;
928   std::string component_registerName = _containerName + "/" + instanceName;
929
930   PyGILState_STATE gstate = PyGILState_Ensure();
931   PyObject *result = PyObject_CallMethod(_pyCont,
932                                          (char*)"create_component_instance",
933                                          (char*)"ss",
934                                          CompName.c_str(),
935                                          instanceName.c_str());
936   const char *ior;
937   const char *error;
938   PyArg_ParseTuple(result,"ss", &ior, &error);
939   std::string iors = ior;
940   reason=error;
941   Py_DECREF(result);
942   PyGILState_Release(gstate);
943
944   if( iors!="" )
945   {
946     CORBA::Object_var obj = _orb->string_to_object(iors.c_str());
947     iobject = Engines::EngineComponent::_narrow( obj ) ;
948     _listInstances_map[instanceName] = iobject;
949   }
950   return iobject._retn();
951 }
952
953 char *
954 Engines_Container_i::create_python_service_instance(const char * CompName,
955                                                     CORBA::String_out reason)
956 {
957   CORBA::Object_var object = CORBA::Object::_nil();
958
959   _numInstanceMutex.lock() ; // lock on the instance number
960   _numInstance++ ;
961   int numInstance = _numInstance ;
962   _numInstanceMutex.unlock() ;
963
964   char aNumI[12];
965   sprintf( aNumI , "%d" , numInstance ) ;
966   std::string instanceName = std::string(CompName) + "_inst_" + aNumI ;
967   std::string component_registerName = _containerName + "/" + instanceName;
968
969   PyGILState_STATE gstate = PyGILState_Ensure();
970   PyObject *result = PyObject_CallMethod(_pyCont,
971                                          (char*)"create_component_instance",
972                                          (char*)"ss",
973                                          CompName,
974                                          instanceName.c_str());
975   const char *ior;
976   const char *error;
977   PyArg_ParseTuple(result,"ss", &ior, &error);
978   reason = CORBA::string_dup(error);
979   char * _ior = CORBA::string_dup(ior);
980   Py_DECREF(result);
981   PyGILState_Release(gstate);
982
983   return _ior;
984 }
985
986
987 //=============================================================================
988 //! Create a new component instance (C++ implementation)
989 /*! 
990 *  C++ method: create a servant instance of a component.
991 *  \param genericRegisterName    Name of the component instance to register
992 *                                in Registry & Name Service,
993 *                                (without _inst_n suffix, like "COMPONENT")
994 *  \param handle                 loaded library handle
995 *  \param reason                 explains error when creation fails
996 *  \return a loaded component
997
998 *  example with names:
999 *    - aGenRegisterName = COMPONENT (= first argument)
1000 *    - _containerName = /Containers/cli76ce/FactoryServer
1001 *    - factoryName = COMPONENTEngine_factory
1002 *    - component_registerBase = /Containers/cli76ce/FactoryServer/COMPONENT
1003 *    - instanceName = COMPONENT_inst_1
1004 *    - component_registerName = /Containers/cli76ce/FactoryServer/COMPONENT_inst_1
1005 */
1006 //=============================================================================
1007 Engines::EngineComponent_ptr
1008 Engines_Container_i::createInstance(std::string genericRegisterName,
1009                                     void *handle,
1010                                     std::string& reason)
1011 {
1012   // --- find the factory
1013
1014   std::string aGenRegisterName = genericRegisterName;
1015   std::string factory_name = aGenRegisterName + std::string("Engine_factory");
1016   SCRUTE(factory_name) ;
1017
1018   typedef PortableServer::ObjectId* (*FACTORY_FUNCTION) (CORBA::ORB_ptr,
1019                                                          PortableServer::POA_ptr, 
1020                                                          PortableServer::ObjectId *, 
1021                                                          const char *, 
1022                                                          const char *) ;
1023
1024 #ifndef WIN32
1025   FACTORY_FUNCTION Component_factory = (FACTORY_FUNCTION)dlsym( handle, factory_name.c_str() );
1026 #else
1027   FACTORY_FUNCTION Component_factory = (FACTORY_FUNCTION)GetProcAddress( (HINSTANCE)handle, factory_name.c_str() );
1028 #endif
1029
1030   if ( !Component_factory )
1031   {
1032     MESSAGE( "Can't resolve symbol: " + factory_name );
1033 #ifndef WIN32
1034     reason=dlerror();
1035     MESSAGE(reason);
1036 #endif
1037     return Engines::EngineComponent::_nil() ;
1038   }
1039
1040   // --- create instance
1041
1042   Engines::EngineComponent_var iobject = Engines::EngineComponent::_nil() ;
1043
1044   try
1045   {
1046     _numInstanceMutex.lock() ; // lock on the instance number
1047     _numInstance++ ;
1048     int numInstance = _numInstance ;
1049     _numInstanceMutex.unlock() ;
1050
1051     char aNumI[12];
1052     sprintf( aNumI , "%d" , numInstance ) ;
1053     std::string instanceName = aGenRegisterName + "_inst_" + aNumI ;
1054     std::string component_registerName =
1055       _containerName + "/" + instanceName;
1056
1057     // --- Instantiate required CORBA object
1058
1059     PortableServer::ObjectId *id ; //not owner, do not delete (nore use var)
1060     id = (Component_factory) ( _orb, _poa, _id, instanceName.c_str(),
1061                                                 aGenRegisterName.c_str() ) ;
1062     if (id == NULL)
1063     {
1064       reason="Can't get ObjectId from factory";
1065       INFOS(reason);
1066       return iobject._retn();
1067     }
1068
1069     // --- get reference from id
1070
1071     CORBA::Object_var obj = _poa->id_to_reference(*id);
1072     iobject = Engines::EngineComponent::_narrow( obj ) ;
1073
1074     _numInstanceMutex.lock() ; // lock to be alone (stl container write)
1075     _listInstances_map[instanceName] = iobject;
1076     _cntInstances_map[aGenRegisterName] += 1;
1077     _numInstanceMutex.unlock() ;
1078     SCRUTE(aGenRegisterName);
1079     SCRUTE(_cntInstances_map[aGenRegisterName]);
1080
1081     // --- register the engine under the name
1082     //     containerName(.dir)/instanceName(.object)
1083
1084     _NS->Register( iobject , component_registerName.c_str() ) ;
1085     MESSAGE( component_registerName.c_str() << " bound" ) ;
1086   }
1087   catch (...)
1088   {
1089     reason="Container_i::createInstance exception caught";
1090     INFOS(reason) ;
1091   }
1092   return iobject._retn();
1093 }
1094
1095 //=============================================================================
1096 //! Find an existing (in the container) component instance
1097 /*!
1098 *  CORBA method: Finds a servant instance of a component
1099 *  \param registeredName  Name of the component in Registry or Name Service,
1100 *                         without instance suffix number
1101 *  \return the first found instance
1102 */
1103 //=============================================================================
1104 Engines::EngineComponent_ptr
1105 Engines_Container_i::find_component_instance( const char* registeredName)
1106 {
1107   Engines::EngineComponent_var anEngine = Engines::EngineComponent::_nil();
1108   std::map<std::string,Engines::EngineComponent_var>::iterator itm =_listInstances_map.begin();
1109   while (itm != _listInstances_map.end())
1110   {
1111     std::string instance = (*itm).first;
1112     SCRUTE(instance);
1113     if (instance.find(registeredName) == 0)
1114     {
1115       anEngine = (*itm).second;
1116       return anEngine._retn();
1117     }
1118     itm++;
1119   }
1120   return anEngine._retn();
1121 }
1122
1123 //=============================================================================
1124 //! Remove the component instance from container
1125 /*!
1126 *  CORBA method: Stops the component servant, and deletes all related objects
1127 *  \param component_i     Component to be removed
1128 */
1129 //=============================================================================
1130
1131 void Engines_Container_i::remove_impl(Engines::EngineComponent_ptr component_i)
1132 {
1133   ASSERT(! CORBA::is_nil(component_i));
1134   std::string instanceName = component_i->instanceName() ;
1135   MESSAGE("unload component " << instanceName);
1136   _numInstanceMutex.lock() ; // lock to be alone (stl container write)
1137   _listInstances_map.erase(instanceName);
1138   _numInstanceMutex.unlock() ;
1139   component_i->destroy() ;
1140   _NS->Destroy_Name(instanceName.c_str());
1141 }
1142
1143 //=============================================================================
1144 //! Unload component libraries from the container
1145 /*!
1146 *  CORBA method: Discharges unused libraries from the container.
1147 */
1148 //=============================================================================
1149 void Engines_Container_i::finalize_removal()
1150 {
1151   MESSAGE("finalize unload : dlclose");
1152   _numInstanceMutex.lock(); // lock to be alone
1153   // (see decInstanceCnt, load_component_Library)
1154   std::map<std::string, void *>::iterator ith;
1155   for (ith = _toRemove_map.begin(); ith != _toRemove_map.end(); ith++)
1156   {
1157     void *handle = (*ith).second;
1158     std::string impl_name= (*ith).first;
1159     if (handle)
1160     {
1161       SCRUTE(handle);
1162       SCRUTE(impl_name);
1163       //        dlclose(handle);                // SALOME unstable after ...
1164       //        _library_map.erase(impl_name);
1165     }
1166   }
1167   _toRemove_map.clear();
1168   _numInstanceMutex.unlock();
1169 }
1170
1171 //=============================================================================
1172 //! Decrement component instance reference count
1173 /*!
1174 *
1175 */
1176 //=============================================================================
1177 void Engines_Container_i::decInstanceCnt(std::string genericRegisterName)
1178 {
1179   if(_cntInstances_map.count(genericRegisterName)==0)
1180     return;
1181   std::string aGenRegisterName =genericRegisterName;
1182   MESSAGE("Engines_Container_i::decInstanceCnt " << aGenRegisterName);
1183   ASSERT(_cntInstances_map[aGenRegisterName] > 0);
1184   _numInstanceMutex.lock(); // lock to be alone
1185   // (see finalize_removal, load_component_Library)
1186   _cntInstances_map[aGenRegisterName] -= 1;
1187   SCRUTE(_cntInstances_map[aGenRegisterName]);
1188   if (_cntInstances_map[aGenRegisterName] == 0)
1189   {
1190     std::string impl_name =
1191       Engines_Component_i::GetDynLibraryName(aGenRegisterName.c_str());
1192     SCRUTE(impl_name);
1193     void* handle = _library_map[impl_name];
1194     ASSERT(handle);
1195     _toRemove_map[impl_name] = handle;
1196   }
1197   _numInstanceMutex.unlock();
1198 }
1199
1200 //=============================================================================
1201 //! Find or create a new component instance
1202 /*!
1203 *  CORBA method: find or create an instance of the component (servant),
1204 *  load a new component class (dynamic library) if required,
1205 *
1206 *  ---- FOR COMPATIBILITY WITH 2.2 ----
1207 *
1208 *  ---- USE ONLY FOR MULTISTUDY INSTANCES ! --------
1209 *
1210 *  The servant registers itself to naming service and Registry.
1211 *  \param genericRegisterName  Name of the component to register
1212 *                              in Registry & Name Service
1213 *  \param componentName       Name of the constructed library of the component
1214 *  \return a loaded component
1215 */
1216 //=============================================================================
1217
1218 Engines::EngineComponent_ptr
1219 Engines_Container_i::load_impl( const char* genericRegisterName,
1220                                 const char* /*componentName*/ )
1221 {
1222   char* reason;
1223   std::string impl_name = std::string(LIB) + genericRegisterName + ENGINESO;
1224   Engines::EngineComponent_var iobject = Engines::EngineComponent::_nil() ;
1225   if (load_component_Library(genericRegisterName,reason))
1226     iobject = find_or_create_instance(genericRegisterName, impl_name);
1227   CORBA::string_free(reason);
1228   return iobject._retn();
1229 }
1230
1231 //=============================================================================
1232 //! Finds an already existing component instance or create a new instance
1233 /*!
1234 *  C++ method: Finds an already existing servant instance of a component, or
1235 *              create an instance.
1236 *  ---- USE ONLY FOR MULTISTUDY INSTANCES ! --------
1237 *  \param genericRegisterName    Name of the component instance to register
1238 *                                in Registry & Name Service,
1239 *                                (without _inst_n suffix, like "COMPONENT")
1240 *  \param componentLibraryName   like "libCOMPONENTEngine.so"
1241 *  \return a loaded component
1242 *
1243 *  example with names:
1244 *    - aGenRegisterName = COMPONENT (= first argument)
1245 *    - impl_name = libCOMPONENTEngine.so (= second argument)
1246 *    - _containerName = /Containers/cli76ce/FactoryServer
1247 *    - factoryName = COMPONENTEngine_factory
1248 *    - component_registerBase = /Containers/cli76ce/FactoryServer/COMPONENT
1249 *    - instanceName = COMPONENT_inst_1
1250 *    - component_registerName = /Containers/cli76ce/FactoryServer/COMPONENT_inst_1
1251 */
1252 //=============================================================================
1253
1254 Engines::EngineComponent_ptr
1255 Engines_Container_i::find_or_create_instance(std::string genericRegisterName,
1256                                              std::string componentLibraryName)
1257 {
1258   std::string aGenRegisterName = genericRegisterName;
1259   std::string impl_name = componentLibraryName;
1260   if (_library_map.count(impl_name) == 0)
1261   {
1262     INFOS("shared library " << impl_name <<" must be loaded before creating instance");
1263     return Engines::EngineComponent::_nil() ;
1264   }
1265   else
1266   {
1267     // --- find a registered instance in naming service, or create
1268
1269     void* handle = _library_map[impl_name];
1270     std::string component_registerBase =
1271       _containerName + "/" + aGenRegisterName;
1272     Engines::EngineComponent_var iobject = Engines::EngineComponent::_nil() ;
1273     std::string reason;
1274     try
1275     {
1276       CORBA::Object_var obj =
1277         _NS->ResolveFirst( component_registerBase.c_str());
1278       if ( CORBA::is_nil( obj ) )
1279       {
1280         iobject = createInstance(genericRegisterName,
1281                                  handle,
1282                                  reason);
1283       }
1284       else
1285       {
1286         iobject = Engines::EngineComponent::_narrow( obj ) ;
1287       }
1288     }
1289     catch (...)
1290     {
1291       INFOS( "Container_i::load_impl caught" ) ;
1292     }
1293     return iobject._retn();
1294   }
1295 }
1296
1297 //=============================================================================
1298 //! Indicate if container is a python one
1299 /*! 
1300 *  Retrieves only with container naming convention if it is a python container
1301 */
1302 //=============================================================================
1303 bool Engines_Container_i::isPythonContainer(const char* ContainerName)
1304 {
1305   bool ret=false;
1306   size_t len=strlen(ContainerName);
1307   if(len>=2)
1308     if(strcmp(ContainerName+len-2,"Py")==0)
1309       ret=true;
1310   return ret;
1311 }
1312
1313 //=============================================================================
1314 //! Kill the container
1315 /*!
1316 *  CORBA method: Kill the container process with exit(0).
1317 *  To remove :  never returns !
1318 */
1319 //=============================================================================
1320 bool Engines_Container_i::Kill_impl()
1321 {
1322   MESSAGE("Engines_Container_i::Kill() pid "<< getpid() << " containerName "
1323     << _containerName.c_str() << " machineName "
1324     << Kernel_Utils::GetHostname().c_str());
1325   INFOS("===============================================================");
1326   INFOS("= REMOVE calls to Kill_impl in C++ container                  =");
1327   INFOS("===============================================================");
1328   //_exit( 0 ) ;
1329   ASSERT(0);
1330   return false;
1331 }
1332
1333 //=============================================================================
1334 /*! 
1335 *  
1336 */
1337 //=============================================================================
1338 void ActSigIntHandler()
1339 {
1340 #ifndef WIN32
1341   struct sigaction SigIntAct ;
1342   SigIntAct.sa_sigaction = &SigIntHandler ;
1343   sigemptyset(&SigIntAct.sa_mask);
1344   SigIntAct.sa_flags = SA_SIGINFO ;
1345 #endif
1346
1347   // DEBUG 03.02.2005 : the first parameter of sigaction is not a mask of signals
1348   // (SIGINT | SIGUSR1) :
1349   // it must be only one signal ===> one call for SIGINT 
1350   // and an other one for SIGUSR1
1351
1352 #ifndef WIN32
1353   if ( sigaction( SIGINT , &SigIntAct, NULL ) ) 
1354   {
1355     perror("SALOME_Container main ") ;
1356     exit(0) ;
1357   }
1358   if ( sigaction( SIGUSR1 , &SigIntAct, NULL ) )
1359   {
1360     perror("SALOME_Container main ") ;
1361     exit(0) ;
1362   }
1363   if ( sigaction( SIGUSR2 , &SigIntAct, NULL ) )
1364   {
1365     perror("SALOME_Container main ") ;
1366     exit(0) ;
1367   }
1368
1369   //PAL9042 JR : during the execution of a Signal Handler (and of methods called through Signal Handlers)
1370   //             use of streams (and so on) should never be used because :
1371   //             streams of C++ are naturally thread-safe and use pthread_mutex_lock ===>
1372   //             A stream operation may be interrupted by a signal and if the Handler use stream we
1373   //             may have a "Dead-Lock" ===HangUp
1374   //==INFOS is commented
1375   //  INFOS(pthread_self() << "SigIntHandler activated") ;
1376
1377 #else  
1378   signal( SIGINT, SigIntHandler );
1379 // legacy code required to supervisor. Commented in order to avoid problems on Windows 
1380 //  signal( SIGUSR1, SigIntHandler );
1381 #endif
1382
1383 }
1384
1385 void SetCpuUsed() ;
1386 void CallCancelThread() ;
1387
1388 #ifndef WIN32
1389 void SigIntHandler(int /*what*/ ,
1390                    siginfo_t * siginfo ,
1391                    void * /*toto*/ ) 
1392 {
1393   //PAL9042 JR : during the execution of a Signal Handler (and of methods called through Signal Handlers)
1394   //             use of streams (and so on) should never be used because :
1395   //             streams of C++ are naturally thread-safe and use pthread_mutex_lock ===>
1396   //             A stream operation may be interrupted by a signal and if the Handler use stream we
1397   //             may have a "Dead-Lock" ===HangUp
1398   //==MESSAGE is commented
1399   //  MESSAGE(pthread_self() << "SigIntHandler what     " << what << std::endl
1400   //          << "              si_signo " << siginfo->si_signo << std::endl
1401   //          << "              si_code  " << siginfo->si_code << std::endl
1402   //          << "              si_pid   " << siginfo->si_pid) ;
1403
1404   if ( _Sleeping )
1405   {
1406     _Sleeping = false ;
1407     //     MESSAGE("SigIntHandler END sleeping.") ;
1408     return ;
1409   }
1410   else
1411   {
1412     ActSigIntHandler() ;
1413     if ( siginfo->si_signo == SIGUSR1 )
1414     {
1415       SetCpuUsed() ;
1416     }
1417     else if ( siginfo->si_signo == SIGUSR2 )
1418     {
1419       CallCancelThread() ;
1420     }
1421     else 
1422     {
1423       _Sleeping = true ;
1424       //      MESSAGE("SigIntHandler BEGIN sleeping.") ;
1425       int count = 0 ;
1426       while( _Sleeping )
1427       {
1428         sleep( 1 ) ;
1429         count += 1 ;
1430       }
1431       //      MESSAGE("SigIntHandler LEAVE sleeping after " << count << " s.") ;
1432     }
1433     return ;
1434   }
1435 }
1436 #else // Case WIN32
1437 void SigIntHandler( int what )
1438 {
1439 #ifndef WIN32
1440   MESSAGE( pthread_self() << "SigIntHandler what     " << what << std::endl );
1441 #else
1442   MESSAGE( "SigIntHandler what     " << what << std::endl );
1443 #endif
1444   if ( _Sleeping )
1445   {
1446     _Sleeping = false ;
1447     MESSAGE("SigIntHandler END sleeping.") ;
1448     return ;
1449   }
1450   else
1451   {
1452     ActSigIntHandler() ;
1453     if ( what == SIGUSR1 )
1454     {
1455       SetCpuUsed() ;
1456     }
1457     else
1458     {
1459       _Sleeping = true ;
1460       MESSAGE("SigIntHandler BEGIN sleeping.") ;
1461       int count = 0 ;
1462       while( _Sleeping ) 
1463       {
1464         Sleep( 1000 ) ;
1465         count += 1 ;
1466       }
1467       MESSAGE("SigIntHandler LEAVE sleeping after " << count << " s.") ;
1468     }
1469     return ;
1470   }
1471 }
1472 #endif
1473
1474 //=============================================================================
1475 //! Get or create a file reference object associated to a local file (to transfer it)
1476 /*!
1477 *  CORBA method: get or create a fileRef object associated to a local file
1478 *  (a file on the computer on which runs the container server), which stores
1479 *  a list of (machine, localFileName) corresponding to copies already done.
1480 *
1481 *  \param  origFileName absolute path for a local file to copy on other
1482 *          computers
1483 *  \return a fileRef object associated to the file.
1484 */
1485 //=============================================================================
1486 Engines::fileRef_ptr
1487 Engines_Container_i::createFileRef(const char* origFileName)
1488 {
1489   std::string origName(origFileName);
1490   Engines::fileRef_var theFileRef = Engines::fileRef::_nil();
1491
1492   if (origName[0] != '/')
1493   {
1494     INFOS("path of file to copy must be an absolute path beginning with '/'");
1495     return Engines::fileRef::_nil();
1496   }
1497
1498   if (CORBA::is_nil(_fileRef_map[origName]))
1499   {
1500     CORBA::Object_var obj=_poa->id_to_reference(*_id);
1501     Engines::Container_var pCont = Engines::Container::_narrow(obj);
1502     fileRef_i* aFileRef = new fileRef_i(pCont, origFileName);
1503     theFileRef = Engines::fileRef::_narrow(aFileRef->_this());
1504     _numInstanceMutex.lock() ; // lock to be alone (stl container write)
1505     _fileRef_map[origName] = theFileRef;
1506     _numInstanceMutex.unlock() ;
1507   }
1508
1509   theFileRef =  Engines::fileRef::_duplicate(_fileRef_map[origName]);
1510   ASSERT(! CORBA::is_nil(theFileRef));
1511   return theFileRef._retn();
1512 }
1513
1514 //=============================================================================
1515 //! Get a fileTransfer reference
1516 /*!
1517 *  CORBA method:
1518 *  \return a reference to the fileTransfer object
1519 */
1520 //=============================================================================
1521 Engines::fileTransfer_ptr
1522 Engines_Container_i::getFileTransfer()
1523 {
1524   Engines::fileTransfer_var aFileTransfer
1525     = Engines::fileTransfer::_duplicate(_fileTransfer);
1526   return aFileTransfer._retn();
1527 }
1528
1529 //=============================================================================
1530 //! Create a Salome file
1531 //=============================================================================
1532 Engines::Salome_file_ptr
1533 Engines_Container_i::createSalome_file(const char* origFileName)
1534 {
1535   std::string origName(origFileName);
1536   if (CORBA::is_nil(_Salome_file_map[origName]))
1537   {
1538     Salome_file_i* aSalome_file = new Salome_file_i();
1539     aSalome_file->setContainer(Engines::Container::_duplicate(this->_this()));
1540     try
1541     {
1542       aSalome_file->setLocalFile(origFileName);
1543       aSalome_file->recvFiles();
1544     }
1545     catch (const SALOME::SALOME_Exception& /*e*/) //!< TODO: unused variable
1546     {
1547       return Engines::Salome_file::_nil();
1548     }
1549
1550     Engines::Salome_file_var theSalome_file = Engines::Salome_file::_nil();
1551     theSalome_file = Engines::Salome_file::_narrow(aSalome_file->_this());
1552     _numInstanceMutex.lock() ; // lock to be alone (stl container write)
1553     _Salome_file_map[origName] = theSalome_file;
1554     _numInstanceMutex.unlock() ;
1555   }
1556
1557   Engines::Salome_file_ptr theSalome_file =
1558     Engines::Salome_file::_duplicate(_Salome_file_map[origName]);
1559   ASSERT(!CORBA::is_nil(theSalome_file));
1560   return theSalome_file;
1561 }
1562
1563 //=============================================================================
1564 /*! \brief copy a file from a remote host (container) to the local host
1565  * \param container the remote container
1566  * \param remoteFile the file to copy locally from the remote host into localFile
1567  * \param localFile the local file
1568  */
1569 //=============================================================================
1570 void Engines_Container_i::copyFile(Engines::Container_ptr container, const char* remoteFile, const char* localFile)
1571 {
1572   Engines::fileTransfer_var fileTransfer = container->getFileTransfer();
1573
1574   FILE* fp;
1575   if ((fp = fopen(localFile,"wb")) == NULL)
1576   {
1577     INFOS("file " << localFile << " cannot be open for writing");
1578     return;
1579   }
1580
1581   CORBA::Long fileId = fileTransfer->open(remoteFile);
1582   if (fileId > 0)
1583   {
1584     Engines::fileBlock* aBlock;
1585     int toFollow = 1;
1586     int ctr=0;
1587     while (toFollow)
1588     {
1589       ctr++;
1590       //SCRUTE(ctr);
1591       aBlock = fileTransfer->getBlock(fileId);
1592       toFollow = aBlock->length();
1593       //SCRUTE(toFollow);
1594       CORBA::Octet *buf = aBlock->get_buffer();
1595       fwrite(buf, sizeof(CORBA::Octet), toFollow, fp);
1596       delete aBlock;
1597     }
1598     fclose(fp);
1599     MESSAGE("end of transfer");
1600     fileTransfer->close(fileId);
1601   }
1602   else
1603   {
1604     INFOS("open reference file for copy impossible");
1605   }
1606 }
1607
1608 //=============================================================================
1609 /*! \brief create a PyNode object to execute remote python code
1610  * \param nodeName the name of the node
1611  * \param code the python code to load
1612  * \return the PyNode
1613  */
1614 //=============================================================================
1615 Engines::PyNode_ptr Engines_Container_i::createPyNode(const char* nodeName, const char* code)
1616 {
1617   Engines::PyNode_var node= Engines::PyNode::_nil();
1618
1619   PyGILState_STATE gstate = PyGILState_Ensure();
1620   PyObject *res = PyObject_CallMethod(_pyCont,
1621     (char*)"create_pynode",
1622     (char*)"ss",
1623     nodeName,
1624     code);
1625   if(res==NULL)
1626   {
1627     //internal error
1628     PyErr_Print();
1629     PyGILState_Release(gstate);
1630     SALOME::ExceptionStruct es;
1631     es.type = SALOME::INTERNAL_ERROR;
1632     es.text = "can not create a python node";
1633     throw SALOME::SALOME_Exception(es);
1634   }
1635   long ierr=PyLong_AsLong(PyTuple_GetItem(res,0));
1636   PyObject* result=PyTuple_GetItem(res,1);
1637   std::string astr=PyUnicode_AsUTF8(result);
1638   Py_DECREF(res);
1639   PyGILState_Release(gstate);
1640   if(ierr==0)
1641   {
1642     Utils_Locker lck(&_mutexForDftPy);
1643     CORBA::Object_var obj=_orb->string_to_object(astr.c_str());
1644     node=Engines::PyNode::_narrow(obj);
1645     std::map<std::string,Engines::PyNode_var>::iterator it(_dftPyNode.find(nodeName));
1646     if(it==_dftPyNode.end())
1647     {
1648       _dftPyNode[nodeName]=node;
1649     }
1650     else
1651     {
1652       Engines::PyNode_var oldNode((*it).second);
1653       if(!CORBA::is_nil(oldNode))
1654         oldNode->UnRegister();
1655       (*it).second=node;
1656     }
1657     if(!CORBA::is_nil(node))
1658       node->Register();
1659     return node._retn();
1660   }
1661   else
1662   {
1663     SALOME::ExceptionStruct es;
1664     es.type = SALOME::INTERNAL_ERROR;
1665     es.text = astr.c_str();
1666     throw SALOME::SALOME_Exception(es);
1667   }
1668 }
1669
1670 //=============================================================================
1671 /*! \brief Retrieves the last created PyNode instance with createPyNode.
1672  *
1673  */
1674 //=============================================================================
1675 Engines::PyNode_ptr  Engines_Container_i::getDefaultPyNode(const char *nodeName)
1676 {
1677   Utils_Locker lck(&_mutexForDftPy);
1678   std::map<std::string,Engines::PyNode_var>::iterator it(_dftPyNode.find(nodeName));
1679   if(it==_dftPyNode.end())
1680     return Engines::PyNode::_nil();
1681   else
1682   {
1683     Engines::PyNode_var tmpVar((*it).second);
1684     if(!CORBA::is_nil(tmpVar))
1685       return Engines::PyNode::_duplicate(tmpVar);
1686     else
1687       return Engines::PyNode::_nil();
1688   }
1689 }
1690
1691 //=============================================================================
1692 /*! \brief create a PyScriptNode object to execute remote python code
1693  * \param nodeName the name of the node
1694  * \param code the python code to load
1695  * \return the PyScriptNode
1696  */
1697 //=============================================================================
1698 Engines::PyScriptNode_ptr Engines_Container_i::createPyScriptNode(const char* nodeName, const char* code)
1699 {
1700   Engines::PyScriptNode_var node= Engines::PyScriptNode::_nil();
1701
1702   PyGILState_STATE gstate = PyGILState_Ensure();
1703   PyObject *res = PyObject_CallMethod(_pyCont,
1704     (char*)"create_pyscriptnode",
1705     (char*)"ss",
1706     nodeName,
1707     code);
1708   if(res==NULL)
1709   {
1710     //internal error
1711     PyErr_Print();
1712     PyGILState_Release(gstate);
1713     SALOME::ExceptionStruct es;
1714     es.type = SALOME::INTERNAL_ERROR;
1715     es.text = "can not create a python node";
1716     throw SALOME::SALOME_Exception(es);
1717   }
1718   long ierr=PyLong_AsLong(PyTuple_GetItem(res,0));
1719   PyObject* result=PyTuple_GetItem(res,1);
1720   std::string astr=PyUnicode_AsUTF8(result);
1721   Py_DECREF(res);
1722   PyGILState_Release(gstate);
1723
1724   if(ierr==0)
1725   {
1726     Utils_Locker lck(&_mutexForDftPy);
1727     CORBA::Object_var obj=_orb->string_to_object(astr.c_str());
1728     node=Engines::PyScriptNode::_narrow(obj);
1729     std::map<std::string,Engines::PyScriptNode_var>::iterator it(_dftPyScriptNode.find(nodeName));
1730     if(it==_dftPyScriptNode.end())
1731     {
1732       _dftPyScriptNode[nodeName]=node;
1733     }
1734     else
1735     {
1736       Engines::PyScriptNode_var oldNode((*it).second);
1737       if(!CORBA::is_nil(oldNode))
1738         oldNode->UnRegister();
1739       (*it).second=node;
1740     }
1741     return node._retn();
1742   }
1743   else
1744   {
1745     SALOME::ExceptionStruct es;
1746     es.type = SALOME::INTERNAL_ERROR;
1747     es.text = astr.c_str();
1748     throw SALOME::SALOME_Exception(es);
1749   }
1750 }
1751
1752 void Engines_Container_i::removePyScriptNode(const char *nodeName)
1753 {
1754   std::map<std::string,Engines::PyScriptNode_var>::iterator it(_dftPyScriptNode.find(nodeName));
1755   if(it==_dftPyScriptNode.end())
1756     {
1757       std::ostringstream oss; oss << "Engines_Container_i::removePyScriptNode : node \"" << nodeName << "\" is not map !";
1758       SALOME::ExceptionStruct es;
1759       es.type = SALOME::INTERNAL_ERROR;
1760       es.text = oss.str().c_str();
1761       throw SALOME::SALOME_Exception(es);
1762     }
1763   (*it).second->UnRegister();
1764   _dftPyScriptNode.erase(it);
1765 }
1766
1767 void Engines_Container_i::cleanAllPyScripts()
1768 {
1769   for(std::map<std::string,Engines::PyNode_var>::iterator it=_dftPyNode.begin();it!=_dftPyNode.end();it++)
1770     {
1771       Engines::PyNode_var tmpVar((*it).second);
1772       if(!CORBA::is_nil(tmpVar))
1773         tmpVar->UnRegister();
1774     }
1775   _dftPyNode.clear();
1776   for(std::map<std::string,Engines::PyScriptNode_var>::iterator it=_dftPyScriptNode.begin();it!=_dftPyScriptNode.end();it++)
1777     {
1778       Engines::PyScriptNode_var tmpVar((*it).second);
1779       if(!CORBA::is_nil(tmpVar))
1780         tmpVar->UnRegister();
1781     }
1782   _dftPyScriptNode.clear();
1783 }
1784
1785 //=============================================================================
1786 /*! \brief Retrieves the last created PyScriptNode instance with createPyScriptNode.
1787  *
1788  */
1789 //=============================================================================
1790 Engines::PyScriptNode_ptr Engines_Container_i::getDefaultPyScriptNode(const char *nodeName)
1791 {
1792   Utils_Locker lck(&_mutexForDftPy);
1793   std::map<std::string,Engines::PyScriptNode_var>::iterator it(_dftPyScriptNode.find(nodeName));
1794   if(it==_dftPyScriptNode.end())
1795     return Engines::PyScriptNode::_nil();
1796   else
1797   {
1798     Engines::PyScriptNode_var tmpVar((*it).second);
1799     if(!CORBA::is_nil(tmpVar))
1800       return Engines::PyScriptNode::_duplicate(tmpVar);
1801     else
1802       return Engines::PyScriptNode::_nil();
1803   }
1804 }
1805
1806 //=============================================================================
1807 /* int checkifexecutable(const char *filename)
1808 *
1809 * Return non-zero if the name is an executable file, and
1810 * zero if it is not executable, or if it does not exist.
1811 */
1812 //=============================================================================
1813 int checkifexecutable(const std::string& filename)
1814 {
1815   int result;
1816   struct stat statinfo;
1817
1818   result = stat(filename.c_str(), &statinfo);
1819   if (result < 0) return 0;
1820   if (!S_ISREG(statinfo.st_mode)) return 0;
1821
1822 #ifdef WIN32
1823   return 1;
1824 #else
1825   if (statinfo.st_uid == geteuid()) return statinfo.st_mode & S_IXUSR;
1826   if (statinfo.st_gid == getegid()) return statinfo.st_mode & S_IXGRP;
1827   return statinfo.st_mode & S_IXOTH;
1828 #endif
1829 }
1830
1831
1832 //=============================================================================
1833 /*! \brief Find a file by searching in a path
1834  *  \param filename file name to search
1835  *  \param path path to search in
1836  *  \param pth the complete file path if found
1837  *  \return 1 if found 0 if not 
1838 */
1839 //=============================================================================
1840 int findpathof(const std::string& path, std::string& pth, const std::string& filename)
1841 {
1842   if ( path.size() == 0 ) return 0;
1843
1844   std::string::size_type offset = 0;
1845   std::string::size_type pos = 0;
1846   int found = 0;
1847   struct stat statinfo;
1848
1849   while(!found)
1850   {
1851     pos = path.find( SEP, offset );
1852     pth = path.substr( offset, pos - offset );
1853     if ( pth.size() > 0 )
1854     {
1855       if( pth[pth.size()-1] != SLASH ) pth += SLASH;
1856       pth += filename;
1857       int result=stat(pth.c_str(), &statinfo);
1858       if(result == 0) found=1;
1859     }
1860     if (pos == std::string::npos) break;
1861     offset = pos+1;
1862   }
1863   return found;
1864 }
1865
1866 void Engines_Container_i::registerTemporaryFile( const std::string& fileName )
1867 {
1868   _tmp_files.remove( fileName );
1869   _tmp_files.push_back( fileName );
1870 }
1871
1872 void Engines_Container_i::unregisterTemporaryFile( const std::string& fileName )
1873 {
1874   _tmp_files.remove( fileName );
1875 }
1876
1877 void Engines_Container_i::clearTemporaryFiles()
1878 {
1879   std::list<std::string>::const_iterator it;
1880   for ( it = _tmp_files.begin(); it != _tmp_files.end(); ++it ) {
1881 #if defined(WIN32) && defined(UNICODE)
1882         std::wstring aFile = Kernel_Utils::utf8_decode_s(*it);
1883         std::wstring command = (GetFileAttributes(aFile.c_str()) == FILE_ATTRIBUTE_DIRECTORY) ? L"rd /Q \"" : L"del /F /Q \"";
1884         command += aFile;
1885         command += L"\" 2>NUL";
1886         _wsystem(command.c_str());
1887 #else
1888 #if defined(WIN32)
1889         std::string aFile = *it;
1890         std::string command = (GetFileAttributes(aFile.c_str()) == FILE_ATTRIBUTE_DIRECTORY) ? "rd /Q \"" : "del /F /Q \"";
1891         command += aFile;
1892         command += "\" 2>NUL";
1893 #else
1894         std::string command = "rm -rf ";
1895         command += *it;
1896 #endif
1897         system(command.c_str());
1898 #endif
1899   }
1900   _tmp_files.clear();
1901 }
1902
1903 static Engines_Container_i *_container_singleton_ssl = nullptr;
1904
1905 static Engines::Container_var _container_ref_singleton_ssl;
1906
1907 Engines_Container_i *KERNEL::getContainerSA()
1908 {
1909   if(!_container_singleton_ssl)
1910   {
1911     int argc(0);
1912     CORBA::ORB_var orb = CORBA::ORB_init(argc,nullptr);
1913     CORBA::Object_var obj = orb->resolve_initial_references("RootPOA");
1914     PortableServer::POA_var poa = PortableServer::POA::_narrow(obj);
1915     PortableServer::POAManager_var pman = poa->the_POAManager();
1916     CORBA::PolicyList policies;
1917     policies.length(0);
1918     //
1919     char *argv[4] = {"Container","FactoryServer","toto",nullptr};
1920     SALOME_Fake_NamingService ns;
1921     _container_singleton_ssl = new Engines_Container_i(orb,poa,"FactoryServer",2,argv,&ns,false);
1922     PortableServer::ObjectId * cont_id = _container_singleton_ssl->getCORBAId();
1923     //
1924     CORBA::Object_var zeRef = poa->id_to_reference(*cont_id);
1925     _container_ref_singleton_ssl = Engines::Container::_narrow(zeRef);
1926   }
1927   return _container_singleton_ssl;
1928 }
1929
1930 Engines::Container_var KERNEL::getContainerRefSA()
1931 {
1932   getContainerSA();
1933   return _container_ref_singleton_ssl;
1934 }