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