]> SALOME platform Git repositories - modules/kernel.git/blob - src/Container/Container_i.cxx
Salome HOME
CCAR: replace the old way to take the python global interpreter lock
[modules/kernel.git] / src / Container / Container_i.cxx
1 //  Copyright (C) 2007-2008  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.
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 //  SALOME Container : implementation of container and engine for Kernel
23 //  File   : Container_i.cxx
24 //  Author : Paul RASCLE, EDF - MARC TAJCHMAN, CEA 
25 //  Module : SALOME
26 //  $Header$
27 //#define private public
28 //
29 #include <string.h>
30 #include <stdio.h>
31 #include <time.h>
32 #ifndef WIN32
33 #include <sys/time.h>
34 #include <dlfcn.h>
35 #include <unistd.h>
36 #else
37 #include <signal.h>
38 #include <process.h>
39 #include <direct.h>
40 int SIGUSR1 = 1000;
41 #endif
42
43 #include "utilities.h"
44 #include <SALOMEconfig.h>
45 #include CORBA_SERVER_HEADER(SALOME_Component)
46 #include CORBA_SERVER_HEADER(SALOME_Exception)
47 #include <pthread.h>  // must be before Python.h !
48 #include "SALOME_Container_i.hxx"
49 #include "SALOME_Component_i.hxx"
50 #include "SALOME_FileRef_i.hxx"
51 #include "SALOME_FileTransfer_i.hxx"
52 #include "Salome_file_i.hxx"
53 #include "SALOME_NamingService.hxx"
54 #include "Basics_Utils.hxx"
55
56 #include <Python.h>
57 #include "Container_init_python.hxx"
58
59 using namespace std;
60
61 bool _Sleeping = false ;
62
63 // // Needed by multi-threaded Python --- Supervision
64 int _ArgC ;
65 char ** _ArgV ;
66
67 extern "C" {void ActSigIntHandler() ; }
68 #ifndef WIN32
69 extern "C" {void SigIntHandler(int, siginfo_t *, void *) ; }
70 #else
71 extern "C" {void SigIntHandler( int ) ; }
72 #endif
73
74 #ifdef WIN32
75 # define separator '\\'
76 #else
77 # define separator '/'
78 #endif
79
80
81 map<std::string, int> Engines_Container_i::_cntInstances_map;
82 map<std::string, void *> Engines_Container_i::_library_map;
83 map<std::string, void *> Engines_Container_i::_toRemove_map;
84 omni_mutex Engines_Container_i::_numInstanceMutex ;
85
86 static PyObject* _pyCont;
87
88 int checkifexecutable(const std::string&);
89 int findpathof(std::string&, const std::string&);
90
91 /*! \class Engines_Container_i
92  *  \brief C++ implementation of Engines::Container interface
93  *
94  */
95
96
97 //=============================================================================
98 /*! 
99 *  Default constructor, not for use
100 */
101 //=============================================================================
102
103 Engines_Container_i::Engines_Container_i () :
104 _numInstance(0),_id(0),_NS(0)
105 {
106 }
107
108 //=============================================================================
109 /*! 
110 *  Construtor to use
111 */
112 //=============================================================================
113
114 Engines_Container_i::Engines_Container_i (CORBA::ORB_ptr orb, 
115                                           PortableServer::POA_ptr poa,
116                                           char *containerName ,
117                                           int argc , char* argv[],
118                                           bool activAndRegist,
119                                           bool isServantAloneInProcess
120                                           ) :
121   _numInstance(0),_isServantAloneInProcess(isServantAloneInProcess),_id(0),_NS(0)
122 {
123   _pid = (long)getpid();
124
125   if(activAndRegist)
126     ActSigIntHandler() ;
127
128   _argc = argc ;
129   _argv = argv ;
130
131   string hostname = Kernel_Utils::GetHostname();
132 #ifndef WIN32
133   MESSAGE(hostname << " " << getpid() << 
134     " Engines_Container_i starting argc " <<
135     _argc << " Thread " << pthread_self() ) ;
136 #else
137   MESSAGE(hostname << " " << _getpid() << 
138     " Engines_Container_i starting argc " << _argc<< " Thread " << pthread_self().p ) ;
139 #endif
140
141   int i = 0 ;
142   while ( _argv[ i ] )
143   {
144     MESSAGE("           argv" << i << " " << _argv[ i ]) ;
145     i++ ;
146   }
147
148   if ( argc < 2 )
149   {
150     INFOS("SALOME_Container usage : SALOME_Container ServerName");
151     ASSERT(0) ;
152   }
153   SCRUTE(argv[1]);
154   _isSupervContainer = false;
155   if (strcmp(argv[1],"SuperVisionContainer") == 0) _isSupervContainer = true;
156
157   if (_isSupervContainer)
158   {
159     _ArgC = argc ;
160     _ArgV = argv ;
161   }
162
163   _orb = CORBA::ORB::_duplicate(orb) ;
164   _poa = PortableServer::POA::_duplicate(poa) ;
165
166   // Pour les containers paralleles: il ne faut pas enregistrer et activer
167   // le container generique, mais le container specialise
168
169   if(activAndRegist)
170   {
171     _id = _poa->activate_object(this);
172     _NS = new SALOME_NamingService();
173     _NS->init_orb( _orb ) ;
174     CORBA::Object_var obj=_poa->id_to_reference(*_id);
175     Engines::Container_var pCont 
176       = Engines::Container::_narrow(obj);
177     _remove_ref();
178
179     _containerName = _NS->BuildContainerNameForNS(containerName,
180       hostname.c_str());
181     SCRUTE(_containerName);
182     _NS->Register(pCont, _containerName.c_str());
183     MESSAGE("Engines_Container_i::Engines_Container_i : Container name "
184       << _containerName);
185
186     // Python: 
187     // import SALOME_Container
188     // pycont = SALOME_Container.SALOME_Container_i(containerIORStr)
189
190     CORBA::String_var sior =  _orb->object_to_string(pCont);
191     string myCommand="pyCont = SALOME_Container.SALOME_Container_i('";
192     myCommand += _containerName + "','";
193     myCommand += sior;
194     myCommand += "')\n";
195     SCRUTE(myCommand);
196
197     if (!_isSupervContainer)
198     {
199       PyGILState_STATE gstate = PyGILState_Ensure();
200
201 #ifdef WIN32
202       // mpv: this is temporary solution: there is a unregular crash if not
203       //Sleep(2000);
204       //
205       // first element is the path to Registry.dll, but it's wrong
206       PyRun_SimpleString("import sys\n");
207       PyRun_SimpleString("sys.path = sys.path[1:]\n");
208 #endif
209       PyRun_SimpleString("import SALOME_Container\n");
210       PyRun_SimpleString((char*)myCommand.c_str());
211       PyObject *mainmod = PyImport_AddModule("__main__");
212       PyObject *globals = PyModule_GetDict(mainmod);
213       _pyCont = PyDict_GetItemString(globals, "pyCont");
214
215       PyGILState_Release(gstate);
216     }
217
218     fileTransfer_i* aFileTransfer = new fileTransfer_i();
219     CORBA::Object_var obref=aFileTransfer->_this();
220     _fileTransfer = Engines::fileTransfer::_narrow(obref);
221     aFileTransfer->_remove_ref();
222   }
223 }
224
225 //=============================================================================
226 /*! 
227 *  Destructor
228 */
229 //=============================================================================
230
231 Engines_Container_i::~Engines_Container_i()
232 {
233   MESSAGE("Container_i::~Container_i()");
234   if(_id)
235     delete _id;
236   if(_NS)
237     delete _NS;
238 }
239
240 //=============================================================================
241 //! Get container name
242 /*! 
243 *  CORBA attribute: Container name (see constructor)
244 */
245 //=============================================================================
246
247 char* Engines_Container_i::name()
248 {
249   return CORBA::string_dup(_containerName.c_str()) ;
250 }
251
252 //=============================================================================
253 //! Get container working directory
254 /*! 
255 *  CORBA attribute: Container working directory 
256 */
257 //=============================================================================
258
259 char* Engines_Container_i::workingdir()
260 {
261   char wd[256];
262   getcwd (wd,256);
263   return CORBA::string_dup(wd) ;
264 }
265
266 //=============================================================================
267 //! Get container log file name
268 /*! 
269 *  CORBA attribute: Container log file name
270 */
271 //=============================================================================
272
273 char* Engines_Container_i::logfilename()
274 {
275   return CORBA::string_dup(_logfilename.c_str()) ;
276 }
277
278 //! Set container log file name
279 void Engines_Container_i::logfilename(const char* name)
280 {
281   _logfilename=name;
282 }
283
284 //=============================================================================
285 //! Get container host name
286 /*! 
287 *  CORBA method: Get the hostName of the Container (without domain extensions)
288 */
289 //=============================================================================
290
291 char* Engines_Container_i::getHostName()
292 {
293   string s = Kernel_Utils::GetHostname();
294   //  MESSAGE("Engines_Container_i::getHostName " << s);
295   return CORBA::string_dup(s.c_str()) ;
296 }
297
298 //=============================================================================
299 //! Get container PID
300 /*! 
301 *  CORBA method: Get the PID (process identification) of the Container
302 */
303 //=============================================================================
304
305 CORBA::Long Engines_Container_i::getPID()
306 {
307   return (CORBA::Long)getpid();
308 }
309
310 //=============================================================================
311 //! Ping the servant to check it is still alive
312 /*! 
313 *  CORBA method: check if servant is still alive
314 */
315 //=============================================================================
316
317 void Engines_Container_i::ping()
318 {
319   MESSAGE("Engines_Container_i::ping() pid "<< getpid());
320 }
321
322 //=============================================================================
323 //! Shutdown the container
324 /*! 
325 *  CORBA method, oneway: Server shutdown. 
326 *  - Container name removed from naming service,
327 *  - servant deactivation,
328 *  - orb shutdown if no other servants in the process 
329 */
330 //=============================================================================
331
332 void Engines_Container_i::Shutdown()
333 {
334   MESSAGE("Engines_Container_i::Shutdown()");
335
336   /* For each component contained in this container
337   * tell it to self-destroy
338   */
339   std::map<std::string, Engines::Component_var>::iterator itm;
340   for (itm = _listInstances_map.begin(); itm != _listInstances_map.end(); itm++)
341     {
342       try
343         {
344           itm->second->destroy();
345         }
346       catch(const CORBA::Exception& e)
347         {
348           // ignore this entry and continue
349         }
350       catch(...)
351         {
352           // ignore this entry and continue
353         }
354     }
355
356   _NS->Destroy_FullDirectory(_containerName.c_str());
357   _NS->Destroy_Name(_containerName.c_str());
358   //_remove_ref();
359   //_poa->deactivate_object(*_id);
360   if(_isServantAloneInProcess)
361   {
362     MESSAGE("Effective Shutdown of container Begins...");
363     if(!CORBA::is_nil(_orb))
364       _orb->shutdown(0);
365   }
366 }
367
368 /* int checkifexecutable(const char *filename)
369
370 * Return non-zero if the name is an executable file, and
371 * zero if it is not executable, or if it does not exist.
372 */
373
374 int checkifexecutable(const string& filename)
375 {
376   int result;
377   struct stat statinfo;
378
379   result = stat(filename.c_str(), &statinfo);
380   if (result < 0) return 0;
381   if (!S_ISREG(statinfo.st_mode)) return 0;
382
383 #ifdef WIN32
384   return 1;
385 #else
386   if (statinfo.st_uid == geteuid()) return statinfo.st_mode & S_IXUSR;
387   if (statinfo.st_gid == getegid()) return statinfo.st_mode & S_IXGRP;
388   return statinfo.st_mode & S_IXOTH;
389 #endif
390 }
391
392
393 /* int findpathof(char *pth, const char *exe)
394 *
395 * Find executable by searching the PATH environment variable.
396 *
397 * const char *exe - executable name to search for.
398 *       char *pth - the path found is stored here, space
399 *                   needs to be available.
400 *
401 * If a path is found, returns non-zero, and the path is stored
402 * in pth.  If exe is not found returns 0, with pth undefined.
403 */
404
405 int findpathof(string& pth, const string& exe)
406 {
407   string path( getenv("PATH") );
408   if ( path.size() == 0 )
409          return 0;
410        
411   char path_spr =
412 #ifdef WIN32
413                   ';';
414 #else
415                   ':';
416 #endif
417
418     char dir_spr = 
419 #ifdef WIN32
420                   '\\';
421 #else
422                   '/';
423 #endif
424     
425   int offset = 0;
426   int stop = 0;
427   int found = 0;
428   while(!stop && !found)
429   {
430     int pos = path.find( path_spr, offset );
431     if (pos == string::npos)
432       stop = 1;
433
434     pth = path.substr( offset, pos - offset );
435     if ( pth.size() > 0 )
436     {
437       if( pth[pth.size()-1] != dir_spr )
438         pth += dir_spr;
439       pth += exe;
440       found = checkifexecutable(pth.c_str());
441     }
442     offset = pos+1;
443   }
444
445
446 /*  char *searchpath;
447   char *beg, *end;
448   int stop, found;
449   int len;
450
451   if (strchr(exe, separator) != NULL) {
452 #ifndef WIN32
453     if (realpath(exe, pth) == NULL) return 0;
454 #endif
455     return  checkifexecutable(pth);
456   }
457
458   searchpath = getenv("PATH");
459   if (searchpath == NULL) return 0;
460   if (strlen(searchpath) <= 0) return 0;
461
462   string env_path(searchpath);
463
464   beg = searchpath;
465   stop = 0; found = 0;
466   do {
467     end = strchr(beg, ':');
468     if (end == NULL) {
469       stop = 1;
470       strncpy(pth, beg, PATH_MAX);
471       len = strlen(pth);
472     } else {
473       strncpy(pth, beg, end - beg);
474       pth[end - beg] = '\0';
475       len = end - beg;
476     }
477     if (pth[len - 1] != '/') strncat(pth, "/", 1);
478     strncat(pth, exe, PATH_MAX - len);
479     found = checkifexecutable(pth);
480     if (!stop) beg = end + 1;
481   } while (!stop && !found);
482 */
483   return found;
484 }
485
486
487
488 //=============================================================================
489 //! load a new component class
490 /*! 
491 *  CORBA method: load a new component class (Python or C++ implementation)
492 *  \param componentName like COMPONENT
493 *                          try to make a Python import of COMPONENT,
494 *                          then a lib open of libCOMPONENTEngine.so
495 *  \return true if dlopen successfull or already done, false otherwise
496 */
497 //=============================================================================
498
499 bool
500 Engines_Container_i::load_component_Library(const char* componentName)
501 {
502
503   string aCompName = componentName;
504
505   // --- try dlopen C++ component
506
507 #ifndef WIN32
508   string impl_name = string ("lib") + aCompName + string("Engine.so");
509 #else
510   string impl_name = aCompName + string("Engine.dll");
511 #endif
512   SCRUTE(impl_name);
513
514   _numInstanceMutex.lock(); // lock to be alone 
515   // (see decInstanceCnt, finalize_removal))
516   if (_toRemove_map.count(impl_name) != 0) _toRemove_map.erase(impl_name);
517   if (_library_map.count(impl_name) != 0)
518   {
519     MESSAGE("Library " << impl_name << " already loaded");
520     _numInstanceMutex.unlock();
521     return true;
522   }
523
524   std::string retso="";
525 #ifndef WIN32
526   void* handle;
527   handle = dlopen( impl_name.c_str() , RTLD_LAZY ) ;
528   if ( !handle )retso=dlerror();
529 #else
530   HINSTANCE handle;
531   handle = LoadLibrary( impl_name.c_str() );
532 #endif
533
534   if ( handle )
535   {
536     _library_map[impl_name] = handle;
537     _numInstanceMutex.unlock();
538     return true;
539   }
540   _numInstanceMutex.unlock();
541
542   // --- try import Python component
543
544   INFOS("try import Python component "<<componentName);
545   std::string retpy;
546   if (_isSupervContainer)
547   {
548     INFOS("Supervision Container does not support Python Component Engines");
549     return false;
550   }
551   if (_library_map.count(aCompName) != 0)
552   {
553     return true; // Python Component, already imported
554   }
555   else
556   {
557     PyGILState_STATE gstate = PyGILState_Ensure(); 
558     PyObject *result = PyObject_CallMethod(_pyCont,
559       (char*)"import_component",
560       (char*)"s",componentName);
561
562     retpy=PyString_AsString(result);
563     Py_XDECREF(result);
564     SCRUTE(retpy);
565     PyGILState_Release(gstate);
566
567     if (retpy=="") // import possible: Python component
568     {
569       _numInstanceMutex.lock() ; // lock to be alone (stl container write)
570       _library_map[aCompName] = (void *)_pyCont; // any non O value OK
571       _numInstanceMutex.unlock() ;
572       MESSAGE("import Python: "<<aCompName<<" OK");
573       return true;
574     }
575   }
576   // Try to find an executable
577   std::string executable=aCompName+".exe";
578   string path;
579   if (findpathof(path, executable)) 
580     return true;
581
582   INFOS( "Impossible to load component: " << componentName );
583   INFOS( "Can't load shared library: " << impl_name );
584   std::cerr << retso << std::endl;
585   INFOS( "Can't import Python module: " << componentName );
586   std::cerr << retpy << std::endl;
587   INFOS( "Can't execute program: " << executable );
588   return false;
589 }
590
591 //=============================================================================
592 //! Create a new component instance
593 /*! 
594 *  CORBA method: Creates a new servant instance of a component.
595 *  The servant registers itself to naming service and Registry.
596 *  \param genericRegisterName  Name of the component instance to register
597 *                         in Registry & Name Service (without _inst_n suffix)
598 *  \param studyId         0 for multiStudy instance, 
599 *                         study Id (>0) otherwise
600 *  \return a loaded component
601 */
602 //=============================================================================
603
604 Engines::Component_ptr
605 Engines_Container_i::create_component_instance(const char*genericRegisterName,
606                                                CORBA::Long studyId)
607 {
608   if (studyId < 0)
609   {
610     INFOS("studyId must be > 0 for mono study instance, =0 for multiStudy");
611     return Engines::Component::_nil() ;
612   }
613
614   Engines::Component_var iobject = Engines::Component::_nil() ;
615
616   string aCompName = genericRegisterName;
617   if (_library_map.count(aCompName) != 0) // Python component
618   {
619     if (_isSupervContainer)
620     {
621       INFOS("Supervision Container does not support Python Component Engines");
622       return Engines::Component::_nil();
623     }
624     _numInstanceMutex.lock() ; // lock on the instance number
625     _numInstance++ ;
626     int numInstance = _numInstance ;
627     _numInstanceMutex.unlock() ;
628
629     char aNumI[12];
630     sprintf( aNumI , "%d" , numInstance ) ;
631     string instanceName = aCompName + "_inst_" + aNumI ;
632     string component_registerName =
633       _containerName + "/" + instanceName;
634
635     PyGILState_STATE gstate = PyGILState_Ensure(); 
636     PyObject *result = PyObject_CallMethod(_pyCont,
637       (char*)"create_component_instance",
638       (char*)"ssl",
639       aCompName.c_str(),
640       instanceName.c_str(),
641       studyId);
642     string iors = PyString_AsString(result);
643     Py_DECREF(result);
644     SCRUTE(iors);
645     PyGILState_Release(gstate);
646
647     if( iors!="" )
648     {
649       CORBA::Object_var obj = _orb->string_to_object(iors.c_str());
650       iobject = Engines::Component::_narrow( obj ) ;
651       _listInstances_map[instanceName] = iobject;
652     }
653     return iobject._retn();
654   }
655
656   //--- try C++
657
658 #ifndef WIN32
659   string impl_name = string ("lib") + genericRegisterName +string("Engine.so");
660 #else
661   string impl_name = genericRegisterName +string("Engine.dll");
662 #endif
663   if (_library_map.count(impl_name) != 0) // C++ component
664   {
665     void* handle = _library_map[impl_name];
666     iobject = createInstance(genericRegisterName,
667       handle,
668       studyId);
669     return iobject._retn();
670   }
671
672   // If it's not a Python or a C++ component try to launch a standalone component
673   // in a sub directory
674   // This component is implemented in an executable with name genericRegisterName.exe
675   // It must register itself in Naming Service. The container waits some time (10 s max)
676   // it's registration.
677
678   _numInstanceMutex.lock() ; // lock on the instance number
679   _numInstance++ ;
680   int numInstance = _numInstance ;
681   _numInstanceMutex.unlock() ;
682
683   char aNumI[12];
684   sprintf( aNumI , "%d" , numInstance ) ;
685   string instanceName = aCompName + "_inst_" + aNumI ;
686   string component_registerName = _containerName + "/" + instanceName;
687
688   //check if an entry exist in naming service
689   CORBA::Object_var nsobj = _NS->Resolve(component_registerName.c_str());
690   if ( !CORBA::is_nil(nsobj) )
691   {
692     // unregister the registered component
693     _NS->Destroy_Name(component_registerName.c_str());
694     //kill or shutdown it ???
695   }
696
697   // first arg container ior string
698   // second arg container name
699   // third arg instance name
700
701   Engines::Container_var pCont= _this();
702   CORBA::String_var sior =  _orb->object_to_string(pCont);
703
704   std::string command;
705   command="mkdir -p ";
706   command+=instanceName;
707   command+=";cd ";
708   command+=instanceName;
709   command+=";";
710   command+=genericRegisterName ;
711   command+=".exe";
712   command+=" ";
713   command+= sior; // container ior string
714   command+=" ";
715   command+=_containerName; //container name
716   command+=" ";
717   command+=instanceName; //instance name
718   command+=" &";
719   MESSAGE("SALOME_Container::create_component_instance command=" << command);
720   // launch component with a system call
721   int status=system(command.c_str());
722
723   if (status == -1)
724   {
725     MESSAGE("SALOME_Container::create_component_instance system failed " << "(system command status -1)");
726     return Engines::Component::_nil();
727   }
728 #ifndef WIN32
729   else if (WEXITSTATUS(status) == 217)
730   {
731     MESSAGE("SALOME_Container::create_component_instance system failed " << "(system command status 217)");
732     return Engines::Component::_nil();
733   }
734 #endif
735   else
736   {
737     int count=20;
738     CORBA::Object_var obj = CORBA::Object::_nil() ;
739     while ( CORBA::is_nil(obj) && count )
740     {
741 #ifndef WIN32
742       sleep( 1 ) ;
743 #else
744       Sleep(1000);
745 #endif
746       count-- ;
747       MESSAGE( count << ". Waiting for component " << genericRegisterName);
748       obj = _NS->Resolve(component_registerName.c_str());
749     }
750
751     if(CORBA::is_nil(obj))
752     {
753       MESSAGE("SALOME_Container::create_component_instance failed");
754       return Engines::Component::_nil();
755     }
756     else
757     {
758       MESSAGE("SALOME_Container::create_component_instance successful");
759       iobject=Engines::Component::_narrow(obj);
760       _listInstances_map[instanceName] = iobject;
761       return iobject._retn();
762     }
763   }
764 }
765
766 //=============================================================================
767 //! Find an existing (in the container) component instance
768 /*! 
769 *  CORBA method: Finds a servant instance of a component
770 *  \param registeredName  Name of the component in Registry or Name Service,
771 *                         without instance suffix number
772 *  \param studyId         0 if instance is not associated to a study, 
773 *                         >0 otherwise (== study id)
774 *  \return the first instance found with same studyId
775 */
776 //=============================================================================
777
778 Engines::Component_ptr
779 Engines_Container_i::find_component_instance( const char* registeredName,
780                                              CORBA::Long studyId)
781 {
782   Engines::Component_var anEngine = Engines::Component::_nil();
783   map<string,Engines::Component_var>::iterator itm =_listInstances_map.begin();
784   while (itm != _listInstances_map.end())
785   {
786     string instance = (*itm).first;
787     SCRUTE(instance);
788     if (instance.find(registeredName) == 0)
789     {
790       anEngine = (*itm).second;
791       if (studyId == anEngine->getStudyId())
792       {
793         return anEngine._retn();
794       }
795     }
796     itm++;
797   }
798   return anEngine._retn();  
799 }
800
801 //=============================================================================
802 //! Find or create a new component instance
803 /*! 
804 *  CORBA method: find or create an instance of the component (servant),
805 *  load a new component class (dynamic library) if required,
806 *
807 *  ---- FOR COMPATIBILITY WITH 2.2 ---- 
808 *
809 *  ---- USE ONLY FOR MULTISTUDY INSTANCES ! --------
810 *
811 *  The servant registers itself to naming service and Registry.
812 *  \param genericRegisterName  Name of the component to register
813 *                              in Registry & Name Service
814 *  \param componentName       Name of the constructed library of the component
815 *  \return a loaded component
816 */
817 //=============================================================================
818
819 Engines::Component_ptr
820 Engines_Container_i::load_impl( const char* genericRegisterName,
821                                const char* componentName )
822 {
823   string impl_name = string ("lib") + genericRegisterName +string("Engine.so");
824   Engines::Component_var iobject = Engines::Component::_nil() ;
825   if (load_component_Library(genericRegisterName))
826     iobject = find_or_create_instance(genericRegisterName, impl_name);
827   return iobject._retn();
828 }
829
830
831 //=============================================================================
832 //! Remove the component instance from container
833 /*! 
834 *  CORBA method: Stops the component servant, and deletes all related objects
835 *  \param component_i     Component to be removed
836 */
837 //=============================================================================
838
839 void Engines_Container_i::remove_impl(Engines::Component_ptr component_i)
840 {
841   ASSERT(! CORBA::is_nil(component_i));
842   string instanceName = component_i->instanceName() ;
843   MESSAGE("unload component " << instanceName);
844   _numInstanceMutex.lock() ; // lock to be alone (stl container write)
845   _listInstances_map.erase(instanceName);
846   _numInstanceMutex.unlock() ;
847   component_i->destroy() ;
848   _NS->Destroy_Name(instanceName.c_str());
849 }
850
851 //=============================================================================
852 //! Unload component libraries from the container
853 /*! 
854 *  CORBA method: Discharges unused libraries from the container.
855 */
856 //=============================================================================
857
858 void Engines_Container_i::finalize_removal()
859 {
860   MESSAGE("finalize unload : dlclose");
861   _numInstanceMutex.lock(); // lock to be alone
862   // (see decInstanceCnt, load_component_Library)
863   map<string, void *>::iterator ith;
864   for (ith = _toRemove_map.begin(); ith != _toRemove_map.end(); ith++)
865   {
866     void *handle = (*ith).second;
867     string impl_name= (*ith).first;
868     if (handle)
869     {
870       SCRUTE(handle);
871       SCRUTE(impl_name);
872       //        dlclose(handle);                // SALOME unstable after ...
873       //        _library_map.erase(impl_name);
874     }
875   }
876   _toRemove_map.clear();
877   _numInstanceMutex.unlock();
878 }
879
880 //=============================================================================
881 //! Kill the container
882 /*! 
883 *  CORBA method: Kill the container process with exit(0).
884 *  To remove :  never returns !
885 */
886 //=============================================================================
887
888 bool Engines_Container_i::Kill_impl()
889 {
890   MESSAGE("Engines_Container_i::Kill() pid "<< getpid() << " containerName "
891     << _containerName.c_str() << " machineName "
892     << Kernel_Utils::GetHostname().c_str());
893   INFOS("===============================================================");
894   INFOS("= REMOVE calls to Kill_impl in C++ container                  =");
895   INFOS("===============================================================");
896   //exit( 0 ) ;
897   ASSERT(0);
898   return false;
899 }
900
901 //=============================================================================
902 //! Get or create a file reference object associated to a local file (to transfer it)
903 /*! 
904 *  CORBA method: get or create a fileRef object associated to a local file
905 *  (a file on the computer on which runs the container server), which stores
906 *  a list of (machine, localFileName) corresponding to copies already done.
907
908 *  \param  origFileName absolute path for a local file to copy on other
909 *          computers
910 *  \return a fileRef object associated to the file.
911 */
912 //=============================================================================
913
914 Engines::fileRef_ptr
915 Engines_Container_i::createFileRef(const char* origFileName)
916 {
917   string origName(origFileName);
918   Engines::fileRef_var theFileRef = Engines::fileRef::_nil();
919
920   if (origName[0] != '/')
921   {
922     INFOS("path of file to copy must be an absolute path begining with '/'");
923     return Engines::fileRef::_nil();
924   }
925
926   if (CORBA::is_nil(_fileRef_map[origName]))
927   {
928     CORBA::Object_var obj=_poa->id_to_reference(*_id);
929     Engines::Container_var pCont = Engines::Container::_narrow(obj);
930     fileRef_i* aFileRef = new fileRef_i(pCont, origFileName);
931     theFileRef = Engines::fileRef::_narrow(aFileRef->_this());
932     _numInstanceMutex.lock() ; // lock to be alone (stl container write)
933     _fileRef_map[origName] = theFileRef;
934     _numInstanceMutex.unlock() ;
935   }
936
937   theFileRef =  Engines::fileRef::_duplicate(_fileRef_map[origName]);
938   ASSERT(! CORBA::is_nil(theFileRef));
939   return theFileRef._retn();
940 }
941
942 //=============================================================================
943 //! Get a fileTransfer reference
944 /*! 
945 *  CORBA method:
946 *  \return a reference to the fileTransfer object
947 */
948 //=============================================================================
949
950 Engines::fileTransfer_ptr
951 Engines_Container_i::getFileTransfer()
952 {
953   Engines::fileTransfer_var aFileTransfer
954     = Engines::fileTransfer::_duplicate(_fileTransfer);
955   return aFileTransfer._retn();
956 }
957
958
959 //! Create a Salome file
960 Engines::Salome_file_ptr 
961 Engines_Container_i::createSalome_file(const char* origFileName) 
962 {
963   string origName(origFileName);
964   if (CORBA::is_nil(_Salome_file_map[origName]))
965   {
966     Salome_file_i* aSalome_file = new Salome_file_i();
967     aSalome_file->setContainer(Engines::Container::_duplicate(this->_this()));
968     try 
969     {
970       aSalome_file->setLocalFile(origFileName);
971       aSalome_file->recvFiles();
972     }
973     catch (const SALOME::SALOME_Exception& e)
974     {
975       return Engines::Salome_file::_nil();
976     }
977
978     Engines::Salome_file_var theSalome_file = Engines::Salome_file::_nil();
979     theSalome_file = Engines::Salome_file::_narrow(aSalome_file->_this());
980     _numInstanceMutex.lock() ; // lock to be alone (stl container write)
981     _Salome_file_map[origName] = theSalome_file;
982     _numInstanceMutex.unlock() ;
983   }
984
985   Engines::Salome_file_ptr theSalome_file =  
986     Engines::Salome_file::_duplicate(_Salome_file_map[origName]);
987   ASSERT(!CORBA::is_nil(theSalome_file));
988   return theSalome_file;
989 }
990 //=============================================================================
991 //! Finds an already existing component instance or create a new instance
992 /*! 
993 *  C++ method: Finds an already existing servant instance of a component, or
994 *              create an instance.
995 *  ---- USE ONLY FOR MULTISTUDY INSTANCES ! --------
996 *  \param genericRegisterName    Name of the component instance to register
997 *                                in Registry & Name Service,
998 *                                (without _inst_n suffix, like "COMPONENT")
999 *  \param componentLibraryName   like "libCOMPONENTEngine.so"
1000 *  \return a loaded component
1001
1002 *  example with names:
1003 *    - aGenRegisterName = COMPONENT (= first argument)
1004 *    - impl_name = libCOMPONENTEngine.so (= second argument)
1005 *    - _containerName = /Containers/cli76ce/FactoryServer
1006 *    - factoryName = COMPONENTEngine_factory
1007 *    - component_registerBase = /Containers/cli76ce/FactoryServer/COMPONENT
1008 *    - instanceName = COMPONENT_inst_1
1009 *    - component_registerName = /Containers/cli76ce/FactoryServer/COMPONENT_inst_1
1010 */
1011 //=============================================================================
1012
1013 Engines::Component_ptr
1014 Engines_Container_i::find_or_create_instance(std::string genericRegisterName,
1015                                              std::string componentLibraryName)
1016 {
1017   string aGenRegisterName = genericRegisterName;
1018   string impl_name = componentLibraryName;
1019   if (_library_map.count(impl_name) == 0) 
1020   {
1021     INFOS("shared library " << impl_name <<" must be loaded before creating instance");
1022     return Engines::Component::_nil() ;
1023   }
1024   else
1025   {
1026     // --- find a registered instance in naming service, or create
1027
1028     void* handle = _library_map[impl_name];
1029     string component_registerBase =
1030       _containerName + "/" + aGenRegisterName;
1031     Engines::Component_var iobject = Engines::Component::_nil() ;
1032     try
1033     {
1034       CORBA::Object_var obj =
1035         _NS->ResolveFirst( component_registerBase.c_str());
1036       if ( CORBA::is_nil( obj ) )
1037       {
1038         iobject = createInstance(genericRegisterName,
1039           handle,
1040           0); // force multiStudy instance here !
1041       }
1042       else
1043       { 
1044         iobject = Engines::Component::_narrow( obj ) ;
1045         Engines_Component_i *servant =
1046           dynamic_cast<Engines_Component_i*>
1047           (_poa->reference_to_servant(iobject));
1048         ASSERT(servant)
1049           int studyId = servant->getStudyId();
1050         ASSERT (studyId >= 0);
1051         if (studyId == 0) // multiStudy instance, OK
1052         {
1053           // No ReBind !
1054           MESSAGE(component_registerBase.c_str()<<" already bound");
1055         }
1056         else // monoStudy instance: NOK
1057         {
1058           iobject = Engines::Component::_nil();
1059           INFOS("load_impl & find_component_instance methods "
1060             << "NOT SUITABLE for mono study components");
1061         }
1062       }
1063     }
1064     catch (...)
1065     {
1066       INFOS( "Container_i::load_impl catched" ) ;
1067     }
1068     return iobject._retn();
1069   }
1070 }
1071
1072 //=============================================================================
1073 //! Create a new component instance 
1074 /*! 
1075 *  C++ method: create a servant instance of a component.
1076 *  \param genericRegisterName    Name of the component instance to register
1077 *                                in Registry & Name Service,
1078 *                                (without _inst_n suffix, like "COMPONENT")
1079 *  \param handle                 loaded library handle
1080 *  \param studyId                0 for multiStudy instance, 
1081 *                                study Id (>0) otherwise
1082 *  \return a loaded component
1083
1084 *  example with names:
1085 *    - aGenRegisterName = COMPONENT (= first argument)
1086 *    - _containerName = /Containers/cli76ce/FactoryServer
1087 *    - factoryName = COMPONENTEngine_factory
1088 *    - component_registerBase = /Containers/cli76ce/FactoryServer/COMPONENT
1089 *    - instanceName = COMPONENT_inst_1
1090 *    - component_registerName = /Containers/cli76ce/FactoryServer/COMPONENT_inst_1
1091 */
1092 //=============================================================================
1093
1094 Engines::Component_ptr
1095 Engines_Container_i::createInstance(std::string genericRegisterName,
1096                                     void *handle,
1097                                     int studyId)
1098 {
1099   // --- find the factory
1100
1101   string aGenRegisterName = genericRegisterName;
1102   string factory_name = aGenRegisterName + string("Engine_factory");
1103   SCRUTE(factory_name) ;
1104
1105   typedef  PortableServer::ObjectId * (*FACTORY_FUNCTION)
1106     (CORBA::ORB_ptr,
1107     PortableServer::POA_ptr, 
1108     PortableServer::ObjectId *, 
1109     const char *, 
1110     const char *) ;
1111
1112 #ifndef WIN32
1113   FACTORY_FUNCTION Component_factory = (FACTORY_FUNCTION)dlsym( handle, factory_name.c_str() );
1114 #else
1115   FACTORY_FUNCTION Component_factory = (FACTORY_FUNCTION)GetProcAddress( (HINSTANCE)handle, factory_name.c_str() );
1116 #endif
1117
1118   if ( !Component_factory )
1119   {
1120     INFOS( "Can't resolve symbol: " + factory_name );
1121 #ifndef WIN32
1122     SCRUTE( dlerror() );
1123 #endif
1124     return Engines::Component::_nil() ;
1125   }
1126
1127   // --- create instance
1128
1129   Engines::Component_var iobject = Engines::Component::_nil() ;
1130
1131   try
1132   {
1133     _numInstanceMutex.lock() ; // lock on the instance number
1134     _numInstance++ ;
1135     int numInstance = _numInstance ;
1136     _numInstanceMutex.unlock() ;
1137
1138     char aNumI[12];
1139     sprintf( aNumI , "%d" , numInstance ) ;
1140     string instanceName = aGenRegisterName + "_inst_" + aNumI ;
1141     string component_registerName =
1142       _containerName + "/" + instanceName;
1143
1144     // --- Instanciate required CORBA object
1145
1146     PortableServer::ObjectId *id ; //not owner, do not delete (nore use var)
1147     id = (Component_factory) ( _orb, _poa, _id, instanceName.c_str(),
1148       aGenRegisterName.c_str() ) ;
1149     if (id == NULL)
1150       return iobject._retn();
1151
1152     // --- get reference & servant from id
1153
1154     CORBA::Object_var obj = _poa->id_to_reference(*id);
1155     iobject = Engines::Component::_narrow( obj ) ;
1156
1157     Engines_Component_i *servant =
1158       dynamic_cast<Engines_Component_i*>(_poa->reference_to_servant(iobject));
1159     ASSERT(servant);
1160     //SCRUTE(servant->pd_refCount);
1161     servant->_remove_ref(); // compensate previous id_to_reference 
1162     //SCRUTE(servant->pd_refCount);
1163     _numInstanceMutex.lock() ; // lock to be alone (stl container write)
1164     _listInstances_map[instanceName] = iobject;
1165     _cntInstances_map[aGenRegisterName] += 1;
1166     _numInstanceMutex.unlock() ;
1167     SCRUTE(aGenRegisterName);
1168     SCRUTE(_cntInstances_map[aGenRegisterName]);
1169     //SCRUTE(servant->pd_refCount);
1170 #if defined(_DEBUG_) || defined(_DEBUG)
1171     bool ret_studyId = servant->setStudyId(studyId);
1172     ASSERT(ret_studyId);
1173 #else
1174     servant->setStudyId(studyId);
1175 #endif
1176
1177     // --- register the engine under the name
1178     //     containerName(.dir)/instanceName(.object)
1179
1180     _NS->Register( iobject , component_registerName.c_str() ) ;
1181     MESSAGE( component_registerName.c_str() << " bound" ) ;
1182   }
1183   catch (...)
1184   {
1185     INFOS( "Container_i::createInstance exception catched" ) ;
1186   }
1187   return iobject._retn();
1188 }
1189
1190 //=============================================================================
1191 //! Decrement component instance reference count
1192 /*! 
1193 *
1194 */
1195 //=============================================================================
1196
1197 void Engines_Container_i::decInstanceCnt(std::string genericRegisterName)
1198 {
1199   if(_cntInstances_map.count(genericRegisterName)==0)
1200     return;
1201   string aGenRegisterName =genericRegisterName;
1202   MESSAGE("Engines_Container_i::decInstanceCnt " << aGenRegisterName);
1203   ASSERT(_cntInstances_map[aGenRegisterName] > 0); 
1204   _numInstanceMutex.lock(); // lock to be alone
1205   // (see finalize_removal, load_component_Library)
1206   _cntInstances_map[aGenRegisterName] -= 1;
1207   SCRUTE(_cntInstances_map[aGenRegisterName]);
1208   if (_cntInstances_map[aGenRegisterName] == 0)
1209   {
1210     string impl_name =
1211       Engines_Component_i::GetDynLibraryName(aGenRegisterName.c_str());
1212     SCRUTE(impl_name);
1213     void* handle = _library_map[impl_name];
1214     ASSERT(handle);
1215     _toRemove_map[impl_name] = handle;
1216   }
1217   _numInstanceMutex.unlock();
1218 }
1219
1220 //=============================================================================
1221 //! Indicate if container is a python one
1222 /*! 
1223 *  Retrieves only with container naming convention if it is a python container
1224 */
1225 //=============================================================================
1226
1227 bool Engines_Container_i::isPythonContainer(const char* ContainerName)
1228 {
1229   bool ret=false;
1230   int len=strlen(ContainerName);
1231   if(len>=2)
1232     if(strcmp(ContainerName+len-2,"Py")==0)
1233       ret=true;
1234   return ret;
1235 }
1236
1237 //=============================================================================
1238 /*! 
1239 *  
1240 */
1241 //=============================================================================
1242
1243 void ActSigIntHandler()
1244 {
1245 #ifndef WIN32
1246   struct sigaction SigIntAct ;
1247   SigIntAct.sa_sigaction = &SigIntHandler ;
1248   SigIntAct.sa_flags = SA_SIGINFO ;
1249 #endif
1250
1251   // DEBUG 03.02.2005 : the first parameter of sigaction is not a mask of signals
1252   // (SIGINT | SIGUSR1) :
1253   // it must be only one signal ===> one call for SIGINT 
1254   // and an other one for SIGUSR1
1255
1256 #ifndef WIN32
1257   if ( sigaction( SIGINT , &SigIntAct, NULL ) ) 
1258   {
1259     perror("SALOME_Container main ") ;
1260     exit(0) ;
1261   }
1262   if ( sigaction( SIGUSR1 , &SigIntAct, NULL ) )
1263   {
1264     perror("SALOME_Container main ") ;
1265     exit(0) ;
1266   }
1267   if ( sigaction( SIGUSR2 , &SigIntAct, NULL ) )
1268   {
1269     perror("SALOME_Container main ") ;
1270     exit(0) ;
1271   }
1272
1273   //PAL9042 JR : during the execution of a Signal Handler (and of methods called through Signal Handlers)
1274   //             use of streams (and so on) should never be used because :
1275   //             streams of C++ are naturally thread-safe and use pthread_mutex_lock ===>
1276   //             A stream operation may be interrupted by a signal and if the Handler use stream we
1277   //             may have a "Dead-Lock" ===HangUp
1278   //==INFOS is commented
1279   //  INFOS(pthread_self() << "SigIntHandler activated") ;
1280
1281 #else  
1282   signal( SIGINT, SigIntHandler );
1283   signal( SIGUSR1, SigIntHandler );
1284 #endif
1285
1286 }
1287
1288 void SetCpuUsed() ;
1289 void CallCancelThread() ;
1290
1291 #ifndef WIN32
1292 void SigIntHandler(int what ,
1293                    siginfo_t * siginfo ,
1294                    void * toto ) 
1295 {
1296   //PAL9042 JR : during the execution of a Signal Handler (and of methods called through Signal Handlers)
1297   //             use of streams (and so on) should never be used because :
1298   //             streams of C++ are naturally thread-safe and use pthread_mutex_lock ===>
1299   //             A stream operation may be interrupted by a signal and if the Handler use stream we
1300   //             may have a "Dead-Lock" ===HangUp
1301   //==MESSAGE is commented
1302   //  MESSAGE(pthread_self() << "SigIntHandler what     " << what << endl
1303   //          << "              si_signo " << siginfo->si_signo << endl
1304   //          << "              si_code  " << siginfo->si_code << endl
1305   //          << "              si_pid   " << siginfo->si_pid) ;
1306
1307   if ( _Sleeping )
1308   {
1309     _Sleeping = false ;
1310     //     MESSAGE("SigIntHandler END sleeping.") ;
1311     return ;
1312   }
1313   else
1314   {
1315     ActSigIntHandler() ;
1316     if ( siginfo->si_signo == SIGUSR1 )
1317     {
1318       SetCpuUsed() ;
1319     }
1320     else if ( siginfo->si_signo == SIGUSR2 )
1321     {
1322       CallCancelThread() ;
1323     }
1324     else 
1325     {
1326       _Sleeping = true ;
1327       //      MESSAGE("SigIntHandler BEGIN sleeping.") ;
1328       int count = 0 ;
1329       while( _Sleeping )
1330       {
1331         sleep( 1 ) ;
1332         count += 1 ;
1333       }
1334       //      MESSAGE("SigIntHandler LEAVE sleeping after " << count << " s.") ;
1335     }
1336     return ;
1337   }
1338 }
1339 #else // Case WIN32
1340 void SigIntHandler( int what )
1341 {
1342 #ifndef WIN32
1343   MESSAGE( pthread_self() << "SigIntHandler what     " << what << endl );
1344 #else
1345   MESSAGE( "SigIntHandler what     " << what << endl );
1346 #endif
1347   if ( _Sleeping )
1348   {
1349     _Sleeping = false ;
1350     MESSAGE("SigIntHandler END sleeping.") ;
1351     return ;
1352   }
1353   else
1354   {
1355     ActSigIntHandler() ;
1356     if ( what == SIGUSR1 )
1357     {
1358       SetCpuUsed() ;
1359     }
1360     else
1361     {
1362       _Sleeping = true ;
1363       MESSAGE("SigIntHandler BEGIN sleeping.") ;
1364       int count = 0 ;
1365       while( _Sleeping ) 
1366       {
1367         Sleep( 1000 ) ;
1368         count += 1 ;
1369       }
1370       MESSAGE("SigIntHandler LEAVE sleeping after " << count << " s.") ;
1371     }
1372     return ;
1373   }
1374 }
1375 #endif
1376
1377 /*! \brief copy a file from a remote host (container) to the local host
1378  * \param container the remote container
1379  * \param remoteFile the file to copy locally from the remote host into localFile
1380  * \param localFile the local file
1381  */
1382 void Engines_Container_i::copyFile(Engines::Container_ptr container, const char* remoteFile, const char* localFile)
1383 {
1384   Engines::fileTransfer_var fileTransfer = container->getFileTransfer();
1385
1386   FILE* fp;
1387   if ((fp = fopen(localFile,"wb")) == NULL)
1388     {
1389       INFOS("file " << localFile << " cannot be open for writing");
1390       return;
1391     }
1392
1393   CORBA::Long fileId = fileTransfer->open(remoteFile);
1394   if (fileId > 0)
1395     {
1396       Engines::fileBlock* aBlock;
1397       int toFollow = 1;
1398       int ctr=0;
1399       while (toFollow)
1400         {
1401           ctr++;
1402           SCRUTE(ctr);
1403           aBlock = fileTransfer->getBlock(fileId);
1404           toFollow = aBlock->length();
1405           SCRUTE(toFollow);
1406           CORBA::Octet *buf = aBlock->get_buffer();
1407           fwrite(buf, sizeof(CORBA::Octet), toFollow, fp);
1408           delete aBlock;
1409         }
1410       fclose(fp);
1411       MESSAGE("end of transfer");
1412       fileTransfer->close(fileId);
1413     }
1414   else
1415     {
1416       INFOS("open reference file for copy impossible");
1417     }
1418 }
1419