Salome HOME
Integrate missing files
[modules/kernel.git] / src / Container / Container_i.cxx
1 //  SALOME Container : implementation of container and engine for Kernel
2 //
3 //  Copyright (C) 2003  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 //
23 //
24 //  File   : Container_i.cxx
25 //  Author : Paul RASCLE, EDF - MARC TAJCHMAN, CEA 
26 //  Module : SALOME
27 //  $Header$
28
29 //#define private public
30 #include <string.h>
31 #include <stdio.h>
32 #include <time.h>
33 #ifndef WNT
34 #include <sys/time.h>
35 #include <dlfcn.h>
36 #include <unistd.h>
37 #else
38 #include <signal.h>
39 #include <process.h>
40 int SIGUSR1 = 1000;
41 #endif
42
43 #include "utilities.h"
44 #include <SALOMEconfig.h>
45 //#ifndef WNT
46 #include CORBA_SERVER_HEADER(SALOME_Component)
47 //#else
48 //#include <SALOME_Component.hh>
49 //#endif
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_NamingService.hxx"
56 #include "OpUtil.hxx"
57
58 #include <Python.h>
59 #include "Container_init_python.hxx"
60
61 using namespace std;
62
63 bool _Sleeping = false ;
64
65 // // Needed by multi-threaded Python --- Supervision
66 int _ArgC ;
67 char ** _ArgV ;
68
69
70 // Containers with name FactoryServer are started via rsh in LifeCycleCORBA
71 // Other Containers are started via start_impl of FactoryServer
72
73 extern "C" {void ActSigIntHandler() ; }
74 #ifndef WNT
75   extern "C" {void SigIntHandler(int, siginfo_t *, void *) ; }
76 #else
77   extern "C" {void SigIntHandler( int ) ; }
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 //=============================================================================
87 /*! 
88  *  Default constructor, not for use
89  */
90 //=============================================================================
91
92 Engines_Container_i::Engines_Container_i () :
93   _numInstance(0)
94 {
95 }
96
97 //=============================================================================
98 /*! 
99  *  Construtor to use
100  */
101 //=============================================================================
102
103 Engines_Container_i::Engines_Container_i (CORBA::ORB_ptr orb, 
104                                           PortableServer::POA_var poa,
105                                           char *containerName ,
106                                           int argc , char* argv[],
107                                           bool activAndRegist,
108                                           bool isServantAloneInProcess
109                                           ) :
110   _numInstance(0),_isServantAloneInProcess(isServantAloneInProcess)
111 {
112   _pid = (long)getpid();
113
114   if(activAndRegist)
115     ActSigIntHandler() ;
116
117   _argc = argc ;
118   _argv = argv ;
119
120   string hostname = GetHostname();
121   MESSAGE(hostname << " " << getpid() << " Engines_Container_i starting argc "
122           << _argc << " Thread " << pthread_self() ) ;
123
124   int i = 0 ;
125   while ( _argv[ i ] )
126     {
127       MESSAGE("           argv" << i << " " << _argv[ i ]) ;
128       i++ ;
129     }
130
131   if ( argc < 2 )
132     {
133       INFOS("SALOME_Container usage : SALOME_Container ServerName");
134       ASSERT(0) ;
135     }
136   SCRUTE(argv[1]);
137   _isSupervContainer = false;
138   if (strcmp(argv[1],"SuperVisionContainer") == 0) _isSupervContainer = true;
139
140   if (_isSupervContainer)
141     {
142       _ArgC = argc ;
143       _ArgV = argv ;
144     }
145
146   _orb = CORBA::ORB::_duplicate(orb) ;
147   _poa = PortableServer::POA::_duplicate(poa) ;
148   
149   // Pour les containers paralleles: il ne faut pas enregistrer et activer
150   // le container generique, mais le container specialise
151
152   if(activAndRegist)
153     {
154       _id = _poa->activate_object(this);
155       _NS = new SALOME_NamingService();
156       _NS->init_orb( CORBA::ORB::_duplicate(_orb) ) ;
157       CORBA::Object_var obj=_poa->id_to_reference(*_id);
158       Engines::Container_var pCont 
159         = Engines::Container::_narrow(obj);
160
161       _containerName = _NS->BuildContainerNameForNS(containerName,
162                                                     hostname.c_str());
163       SCRUTE(_containerName);
164       _NS->Register(pCont, _containerName.c_str());
165       MESSAGE("Engines_Container_i::Engines_Container_i : Container name "
166               << _containerName);
167
168       // Python: 
169       // import SALOME_Container
170       // pycont = SALOME_Container.SALOME_Container_i(containerIORStr)
171     
172       CORBA::String_var sior =  _orb->object_to_string(pCont);
173       string myCommand="pyCont = SALOME_Container.SALOME_Container_i('";
174       myCommand += _containerName + "','";
175       myCommand += sior;
176       myCommand += "')\n";
177       SCRUTE(myCommand);
178
179       if (!_isSupervContainer)
180         {
181 #ifdef WNT
182           //Py_ACQUIRE_NEW_THREAD;
183           PyEval_AcquireLock();
184           /* It should not be possible for more than one thread state
185              to be used for a thread.*/
186           PyThreadState *myTstate = PyGILState_GetThisThreadState();
187           // if no thread state defined
188           if ( !myTstate ) 
189             myTstate = PyThreadState_New(KERNEL_PYTHON::_interp);
190           PyThreadState *myoldTstate = PyThreadState_Swap(myTstate);
191 #else
192           Py_ACQUIRE_NEW_THREAD;
193 #endif
194
195 #ifdef WNT
196           // mpv: this is temporary solution: there is a unregular crash if not
197           //Sleep(2000);
198           //
199     // first element is the path to Registry.dll, but it's wrong
200           PyRun_SimpleString("import sys\n");
201           PyRun_SimpleString("sys.path = sys.path[1:]\n");
202 #endif
203           PyRun_SimpleString("import SALOME_Container\n");
204           PyRun_SimpleString((char*)myCommand.c_str());
205           Py_RELEASE_NEW_THREAD;
206         }
207
208       fileTransfer_i* aFileTransfer = new fileTransfer_i();
209       _fileTransfer = Engines::fileTransfer::_narrow(aFileTransfer->_this());
210     }
211 }
212
213 //=============================================================================
214 /*! 
215  *  Destructor
216  */
217 //=============================================================================
218
219 Engines_Container_i::~Engines_Container_i()
220 {
221   MESSAGE("Container_i::~Container_i()");
222   delete _id;
223 }
224
225 //=============================================================================
226 /*! 
227  *  CORBA attribute: Container name (see constructor)
228  */
229 //=============================================================================
230
231 char* Engines_Container_i::name()
232 {
233    return CORBA::string_dup(_containerName.c_str()) ;
234 }
235
236 //=============================================================================
237 /*! 
238  *  CORBA method: Get the hostName of the Container (without domain extensions)
239  */
240 //=============================================================================
241
242 char* Engines_Container_i::getHostName()
243 {
244   string s = GetHostname();
245   //  MESSAGE("Engines_Container_i::getHostName " << s);
246   return CORBA::string_dup(s.c_str()) ;
247 }
248
249 //=============================================================================
250 /*! 
251  *  CORBA method: Get the PID (process identification) of the Container
252  */
253 //=============================================================================
254
255 CORBA::Long Engines_Container_i::getPID()
256 {
257   return (CORBA::Long)getpid();
258 }
259
260 //=============================================================================
261 /*! 
262  *  CORBA method: check if servant is still alive
263  */
264 //=============================================================================
265
266 void Engines_Container_i::ping()
267 {
268   MESSAGE("Engines_Container_i::ping() pid "<< getpid());
269 }
270
271 //=============================================================================
272 /*! 
273  *  CORBA method, oneway: Server shutdown. 
274  *  - Container name removed from naming service,
275  *  - servant deactivation,
276  *  - orb shutdown if no other servants in the process 
277  */
278 //=============================================================================
279
280 void Engines_Container_i::Shutdown()
281 {
282   MESSAGE("Engines_Container_i::Shutdown()");
283
284   /* For each component contained in this container
285    * tell it to self-destroy
286    */
287   std::map<std::string, Engines::Component_var>::iterator itm;
288   for (itm = _listInstances_map.begin(); itm != _listInstances_map.end(); itm++)
289     itm->second->destroy();
290
291   _NS->Destroy_FullDirectory(_containerName.c_str());
292   _NS->Destroy_Name(_containerName.c_str());
293   //_remove_ref();
294   //_poa->deactivate_object(*_id);
295   if(_isServantAloneInProcess)
296     {
297       MESSAGE("Effective Shutdown of container Begins...");
298       LocalTraceBufferPool* bp1 = LocalTraceBufferPool::instance();
299       bp1->deleteInstance(bp1);
300       _orb->shutdown(0);
301     }
302 }
303
304
305 //=============================================================================
306 /*! 
307  *  CORBA method: load a new component class (Python or C++ implementation)
308  *  \param componentName like COMPONENT
309  *                          try to make a Python import of COMPONENT,
310  *                          then a lib open of libCOMPONENTEngine.so
311  *  \return true if dlopen successfull or already done, false otherwise
312  */
313 //=============================================================================
314
315 bool
316 Engines_Container_i::load_component_Library(const char* componentName)
317 {
318
319   string aCompName = componentName;
320
321   // --- try dlopen C++ component
322
323 #ifndef WNT
324   string impl_name = string ("lib") + aCompName + string("Engine.so");
325 #else
326   string impl_name = aCompName + string("Engine.dll");
327 #endif
328   SCRUTE(impl_name);
329   
330   _numInstanceMutex.lock(); // lock to be alone 
331   // (see decInstanceCnt, finalize_removal))
332   if (_toRemove_map[impl_name]) _toRemove_map.erase(impl_name);
333   if (_library_map[impl_name])
334     {
335       MESSAGE("Library " << impl_name << " already loaded");
336       _numInstanceMutex.unlock();
337       return true;
338     }
339   
340 #ifndef WNT
341   void* handle;
342   handle = dlopen( impl_name.c_str() , RTLD_LAZY ) ;
343 #else
344   HINSTANCE handle;
345   handle = LoadLibrary( impl_name.c_str() );
346 #endif
347
348   if ( handle )
349   {
350       _library_map[impl_name] = handle;
351       _numInstanceMutex.unlock();
352       return true;
353   }
354   else
355   {
356       INFOS( "Can't load shared library: " << impl_name );
357 #ifndef WNT
358       INFOS("error dlopen: " << dlerror());
359 #endif
360   }
361   _numInstanceMutex.unlock();
362
363   // --- try import Python component
364
365   INFOS("try import Python component "<<componentName);
366   if (_isSupervContainer)
367     {
368       INFOS("Supervision Container does not support Python Component Engines");
369       return false;
370     }
371   if (_library_map[aCompName])
372     {
373       return true; // Python Component, already imported
374     }
375   else
376     {
377       Py_ACQUIRE_NEW_THREAD;
378       PyObject *mainmod = PyImport_AddModule("__main__");
379       PyObject *globals = PyModule_GetDict(mainmod);
380       PyObject *pyCont = PyDict_GetItemString(globals, "pyCont");
381       PyObject *result = PyObject_CallMethod(pyCont,
382                                              "import_component",
383                                              "s",componentName);
384       int ret= PyInt_AsLong(result);
385       SCRUTE(ret);
386       Py_RELEASE_NEW_THREAD;
387   
388       if (ret) // import possible: Python component
389         {
390           _numInstanceMutex.lock() ; // lock to be alone (stl container write)
391           _library_map[aCompName] = (void *)pyCont; // any non O value OK
392           _numInstanceMutex.unlock() ;
393           MESSAGE("import Python: "<<aCompName<<" OK");
394           return true;
395         }
396     }
397   return false;
398 }
399
400 //=============================================================================
401 /*! 
402  *  CORBA method: Creates a new servant instance of a component.
403  *  The servant registers itself to naming service and Registry.
404  *  \param genericRegisterName  Name of the component instance to register
405  *                         in Registry & Name Service (without _inst_n suffix)
406  *  \param studyId         0 for multiStudy instance, 
407  *                         study Id (>0) otherwise
408  *  \return a loaded component
409  */
410 //=============================================================================
411
412 Engines::Component_ptr
413 Engines_Container_i::create_component_instance(const char*genericRegisterName,
414                                                CORBA::Long studyId)
415 {
416   if (studyId < 0)
417     {
418       INFOS("studyId must be > 0 for mono study instance, =0 for multiStudy");
419       return Engines::Component::_nil() ;
420     }
421
422   Engines::Component_var iobject = Engines::Component::_nil() ;
423
424   string aCompName = genericRegisterName;
425   if (_library_map[aCompName]) // Python component
426     {
427       if (_isSupervContainer)
428         {
429           INFOS("Supervision Container does not support Python Component Engines");
430           return Engines::Component::_nil();
431         }
432       _numInstanceMutex.lock() ; // lock on the instance number
433       _numInstance++ ;
434       int numInstance = _numInstance ;
435       _numInstanceMutex.unlock() ;
436
437       char aNumI[12];
438       sprintf( aNumI , "%d" , numInstance ) ;
439       string instanceName = aCompName + "_inst_" + aNumI ;
440       string component_registerName =
441         _containerName + "/" + instanceName;
442
443       Py_ACQUIRE_NEW_THREAD;
444       PyObject *mainmod = PyImport_AddModule("__main__");
445       PyObject *globals = PyModule_GetDict(mainmod);
446       PyObject *pyCont = PyDict_GetItemString(globals, "pyCont");
447       PyObject *result = PyObject_CallMethod(pyCont,
448                                              "create_component_instance",
449                                              "ssl",
450                                              aCompName.c_str(),
451                                              instanceName.c_str(),
452                                              studyId);
453       string iors = PyString_AsString(result);
454       SCRUTE(iors);
455       Py_RELEASE_NEW_THREAD;
456   
457       if( iors!="" )
458       {
459         CORBA::Object_var obj = _orb->string_to_object(iors.c_str());
460         iobject = Engines::Component::_narrow( obj ) ;
461       }
462       return iobject._retn();
463     }
464   
465   //--- try C++
466
467 #ifndef WNT
468   string impl_name = string ("lib") + genericRegisterName +string("Engine.so");
469 #else
470   string impl_name = genericRegisterName +string("Engine.dll");
471 #endif
472   void* handle = _library_map[impl_name];
473   if ( !handle )
474     {
475       INFOS("shared library " << impl_name <<"must be loaded before instance");
476       return Engines::Component::_nil() ;
477     }
478   else
479     {
480       iobject = createInstance(genericRegisterName,
481                                handle,
482                                studyId);
483       return iobject._retn();
484     }
485 }
486
487 //=============================================================================
488 /*! 
489  *  CORBA method: Finds a servant instance of a component
490  *  \param registeredName  Name of the component in Registry or Name Service,
491  *                         without instance suffix number
492  *  \param studyId         0 if instance is not associated to a study, 
493  *                         >0 otherwise (== study id)
494  *  \return the first instance found with same studyId
495  */
496 //=============================================================================
497
498 Engines::Component_ptr
499 Engines_Container_i::find_component_instance( const char* registeredName,
500                                               CORBA::Long studyId)
501 {
502   Engines::Component_var anEngine = Engines::Component::_nil();
503   map<string,Engines::Component_var>::iterator itm =_listInstances_map.begin();
504   while (itm != _listInstances_map.end())
505     {
506       string instance = (*itm).first;
507       SCRUTE(instance);
508       if (instance.find(registeredName) == 0)
509         {
510           anEngine = (*itm).second;
511           if (studyId == anEngine->getStudyId())
512             {
513               return anEngine._retn();
514             }
515         }
516       itm++;
517     }
518   return anEngine._retn();  
519 }
520
521 //=============================================================================
522 /*! 
523  *  CORBA method: find or create an instance of the component (servant),
524  *  load a new component class (dynamic library) if required,
525  *  ---- FOR COMPATIBILITY WITH 2.2 ---- 
526  *  ---- USE ONLY FOR MULTISTUDY INSTANCES ! --------
527  *  The servant registers itself to naming service and Registry.
528  *  \param genericRegisterName  Name of the component to register
529  *                              in Registry & Name Service
530  *  \param componentName       Name of the constructed library of the component
531  *  \return a loaded component
532  */
533 //=============================================================================
534
535 Engines::Component_ptr
536 Engines_Container_i::load_impl( const char* genericRegisterName,
537                                 const char* componentName )
538 {
539   string impl_name = string ("lib") + genericRegisterName +string("Engine.so");
540   Engines::Component_var iobject = Engines::Component::_nil() ;
541   if (load_component_Library(genericRegisterName))
542     iobject = find_or_create_instance(genericRegisterName, impl_name);
543   return iobject._retn();
544 }
545     
546
547 //=============================================================================
548 /*! 
549  *  CORBA method: Stops the component servant, and deletes all related objects
550  *  \param component_i     Component to be removed
551  */
552 //=============================================================================
553
554 void Engines_Container_i::remove_impl(Engines::Component_ptr component_i)
555 {
556   ASSERT(! CORBA::is_nil(component_i));
557   string instanceName = component_i->instanceName() ;
558   MESSAGE("unload component " << instanceName);
559   _numInstanceMutex.lock() ; // lock to be alone (stl container write)
560   _listInstances_map.erase(instanceName);
561   _numInstanceMutex.unlock() ;
562   component_i->destroy() ;
563   _NS->Destroy_Name(instanceName.c_str());
564 }
565
566 //=============================================================================
567 /*! 
568  *  CORBA method: Discharges unused libraries from the container.
569  */
570 //=============================================================================
571
572 void Engines_Container_i::finalize_removal()
573 {
574   MESSAGE("finalize unload : dlclose");
575   _numInstanceMutex.lock(); // lock to be alone
576                             // (see decInstanceCnt, load_component_Library)
577   map<string, void *>::iterator ith;
578   for (ith = _toRemove_map.begin(); ith != _toRemove_map.end(); ith++)
579     {
580       void *handle = (*ith).second;
581       string impl_name= (*ith).first;
582       if (handle)
583         {
584           SCRUTE(handle);
585           SCRUTE(impl_name);
586 //        dlclose(handle);                // SALOME unstable after ...
587 //        _library_map.erase(impl_name);
588         }
589     }
590   _toRemove_map.clear();
591   _numInstanceMutex.unlock();
592 }
593
594 //=============================================================================
595 /*! 
596  *  CORBA method: Kill the container process with exit(0).
597  *  To remove :  never returns !
598  */
599 //=============================================================================
600
601 bool Engines_Container_i::Kill_impl()
602 {
603   MESSAGE("Engines_Container_i::Kill() pid "<< getpid() << " containerName "
604           << _containerName.c_str() << " machineName "
605           << GetHostname().c_str());
606   INFOS("===============================================================");
607   INFOS("= REMOVE calls to Kill_impl in C++ container                  =");
608   INFOS("===============================================================");
609   //exit( 0 ) ;
610   ASSERT(0);
611   return false;
612 }
613
614 //=============================================================================
615 /*! 
616  *  CORBA method: get or create a fileRef object associated to a local file
617  *  (a file on the computer on which runs the container server), which stores
618  *  a list of (machine, localFileName) corresponding to copies already done.
619  * 
620  *  \param  origFileName absolute path for a local file to copy on other
621  *          computers
622  *  \return a fileRef object associated to the file.
623  */
624 //=============================================================================
625
626 Engines::fileRef_ptr
627 Engines_Container_i::createFileRef(const char* origFileName)
628 {
629   string origName(origFileName);
630   Engines::fileRef_var theFileRef = Engines::fileRef::_nil();
631
632   if (origName[0] != '/')
633     {
634       INFOS("path of file to copy must be an absolute path begining with '/'");
635       return Engines::fileRef::_nil();
636     }
637
638   if (CORBA::is_nil(_fileRef_map[origName]))
639     {
640       CORBA::Object_var obj=_poa->id_to_reference(*_id);
641       Engines::Container_var pCont = Engines::Container::_narrow(obj);
642       fileRef_i* aFileRef = new fileRef_i(pCont, origFileName);
643       theFileRef = Engines::fileRef::_narrow(aFileRef->_this());
644       _numInstanceMutex.lock() ; // lock to be alone (stl container write)
645       _fileRef_map[origName] = theFileRef;
646       _numInstanceMutex.unlock() ;
647     }
648   
649   theFileRef =  Engines::fileRef::_duplicate(_fileRef_map[origName]);
650   ASSERT(! CORBA::is_nil(theFileRef));
651   return theFileRef._retn();
652 }
653
654 //=============================================================================
655 /*! 
656  *  CORBA method:
657  *  \return a reference to the fileTransfer object
658  */
659 //=============================================================================
660
661 Engines::fileTransfer_ptr
662 Engines_Container_i::getFileTransfer()
663 {
664   Engines::fileTransfer_var aFileTransfer
665     = Engines::fileTransfer::_duplicate(_fileTransfer);
666   return aFileTransfer._retn();
667 }
668
669
670 //=============================================================================
671 /*! 
672  *  C++ method: Finds an already existing servant instance of a component, or
673  *              create an instance.
674  *  ---- USE ONLY FOR MULTISTUDY INSTANCES ! --------
675  *  \param genericRegisterName    Name of the component instance to register
676  *                                in Registry & Name Service,
677  *                                (without _inst_n suffix, like "COMPONENT")
678  *  \param componentLibraryName   like "libCOMPONENTEngine.so"
679  *  \return a loaded component
680  * 
681  *  example with names:
682  *  aGenRegisterName = COMPONENT (= first argument)
683  *  impl_name = libCOMPONENTEngine.so (= second argument)
684  *  _containerName = /Containers/cli76ce/FactoryServer
685  *  factoryName = COMPONENTEngine_factory
686  *  component_registerBase = /Containers/cli76ce/FactoryServer/COMPONENT
687  *
688  *  instanceName = COMPONENT_inst_1
689  *  component_registerName = /Containers/cli76ce/FactoryServer/COMPONENT_inst_1
690  */
691 //=============================================================================
692
693 Engines::Component_ptr
694 Engines_Container_i::find_or_create_instance(string genericRegisterName,
695                                              string componentLibraryName)
696 {
697   string aGenRegisterName = genericRegisterName;
698   string impl_name = componentLibraryName;
699   void* handle = _library_map[impl_name];
700   if ( !handle )
701     {
702       INFOS("shared library " << impl_name <<"must be loaded before instance");
703       return Engines::Component::_nil() ;
704     }
705   else
706     {
707       // --- find a registered instance in naming service, or create
708
709       string component_registerBase =
710         _containerName + "/" + aGenRegisterName;
711       Engines::Component_var iobject = Engines::Component::_nil() ;
712       try
713         {
714           CORBA::Object_var obj =
715             _NS->ResolveFirst( component_registerBase.c_str());
716           if ( CORBA::is_nil( obj ) )
717             {
718               iobject = createInstance(genericRegisterName,
719                                        handle,
720                                        0); // force multiStudy instance here !
721             }
722           else
723             { 
724               iobject = Engines::Component::_narrow( obj ) ;
725               Engines_Component_i *servant =
726                 dynamic_cast<Engines_Component_i*>
727                 (_poa->reference_to_servant(iobject));
728               ASSERT(servant)
729               int studyId = servant->getStudyId();
730               ASSERT (studyId >= 0);
731               if (studyId == 0) // multiStudy instance, OK
732                 {
733                   // No ReBind !
734                   MESSAGE(component_registerBase.c_str()<<" already bound");
735                 }
736               else // monoStudy instance: NOK
737                 {
738                   iobject = Engines::Component::_nil();
739                   INFOS("load_impl & find_component_instance methods "
740                         << "NOT SUITABLE for mono study components");
741                 }
742             }
743         }
744       catch (...)
745         {
746           INFOS( "Container_i::load_impl catched" ) ;
747         }
748       return iobject._retn();
749     }
750 }
751
752 //=============================================================================
753 /*! 
754  *  C++ method: create a servant instance of a component.
755  *  \param genericRegisterName    Name of the component instance to register
756  *                                in Registry & Name Service,
757  *                                (without _inst_n suffix, like "COMPONENT")
758  *  \param handle                 loaded library handle
759  *  \param studyId                0 for multiStudy instance, 
760  *                                study Id (>0) otherwise
761  *  \return a loaded component
762  * 
763  *  example with names:
764  *  aGenRegisterName = COMPONENT (= first argument)
765  *  _containerName = /Containers/cli76ce/FactoryServer
766  *  factoryName = COMPONENTEngine_factory
767  *  component_registerBase = /Containers/cli76ce/FactoryServer/COMPONENT
768  *  instanceName = COMPONENT_inst_1
769  *  component_registerName = /Containers/cli76ce/FactoryServer/COMPONENT_inst_1
770  */
771 //=============================================================================
772
773 Engines::Component_ptr
774 Engines_Container_i::createInstance(string genericRegisterName,
775                                     void *handle,
776                                     int studyId)
777 {
778   // --- find the factory
779
780   string aGenRegisterName = genericRegisterName;
781   string factory_name = aGenRegisterName + string("Engine_factory");
782   SCRUTE(factory_name) ;
783
784   typedef  PortableServer::ObjectId * (*FACTORY_FUNCTION)
785     (CORBA::ORB_ptr,
786      PortableServer::POA_ptr, 
787      PortableServer::ObjectId *, 
788      const char *, 
789      const char *) ;
790
791 #ifndef WNT
792   FACTORY_FUNCTION Component_factory = (FACTORY_FUNCTION)dlsym( handle, factory_name.c_str() );
793 #else
794   FACTORY_FUNCTION Component_factory = (FACTORY_FUNCTION)GetProcAddress( (HINSTANCE)handle, factory_name.c_str() );
795 #endif
796
797   if ( !Component_factory )
798   {
799       INFOS( "Can't resolve symbol: " + factory_name );
800 #ifndef WNT
801       SCRUTE( dlerror() );
802 #endif
803       return Engines::Component::_nil() ;
804   }
805
806   // --- create instance
807
808   Engines::Component_var iobject = Engines::Component::_nil() ;
809
810   try
811     {
812       _numInstanceMutex.lock() ; // lock on the instance number
813       _numInstance++ ;
814       int numInstance = _numInstance ;
815       _numInstanceMutex.unlock() ;
816
817       char aNumI[12];
818       sprintf( aNumI , "%d" , numInstance ) ;
819       string instanceName = aGenRegisterName + "_inst_" + aNumI ;
820       string component_registerName =
821         _containerName + "/" + instanceName;
822
823       // --- Instanciate required CORBA object
824
825       PortableServer::ObjectId *id ; //not owner, do not delete (nore use var)
826       id = (Component_factory) ( _orb, _poa, _id, instanceName.c_str(),
827                                  aGenRegisterName.c_str() ) ;
828       if (id == NULL)
829         return iobject._retn();
830       
831       // --- get reference & servant from id
832
833       CORBA::Object_var obj = _poa->id_to_reference(*id);
834       iobject = Engines::Component::_narrow( obj ) ;
835
836       Engines_Component_i *servant =
837         dynamic_cast<Engines_Component_i*>(_poa->reference_to_servant(iobject));
838       ASSERT(servant);
839       //SCRUTE(servant->pd_refCount);
840       servant->_remove_ref(); // compensate previous id_to_reference 
841       //SCRUTE(servant->pd_refCount);
842       _numInstanceMutex.lock() ; // lock to be alone (stl container write)
843       _listInstances_map[instanceName] = iobject;
844       _cntInstances_map[aGenRegisterName] += 1;
845       _numInstanceMutex.unlock() ;
846       SCRUTE(aGenRegisterName);
847       SCRUTE(_cntInstances_map[aGenRegisterName]);
848       //SCRUTE(servant->pd_refCount);
849       bool ret_studyId = servant->setStudyId(studyId);
850       ASSERT(ret_studyId);
851
852       // --- register the engine under the name
853       //     containerName(.dir)/instanceName(.object)
854
855       _NS->Register( iobject , component_registerName.c_str() ) ;
856       MESSAGE( component_registerName.c_str() << " bound" ) ;
857     }
858   catch (...)
859     {
860       INFOS( "Container_i::createInstance exception catched" ) ;
861     }
862   return iobject._retn();
863 }
864
865 //=============================================================================
866 /*! 
867  *
868  */
869 //=============================================================================
870
871 void Engines_Container_i::decInstanceCnt(string genericRegisterName)
872 {
873   string aGenRegisterName =genericRegisterName;
874   MESSAGE("Engines_Container_i::decInstanceCnt " << aGenRegisterName);
875   ASSERT(_cntInstances_map[aGenRegisterName] > 0); 
876   _numInstanceMutex.lock(); // lock to be alone
877                             // (see finalize_removal, load_component_Library)
878   _cntInstances_map[aGenRegisterName] -= 1;
879   SCRUTE(_cntInstances_map[aGenRegisterName]);
880   if (_cntInstances_map[aGenRegisterName] == 0)
881     {
882       string impl_name =
883         Engines_Component_i::GetDynLibraryName(aGenRegisterName.c_str());
884       SCRUTE(impl_name);
885       void* handle = _library_map[impl_name];
886       ASSERT(handle);
887       _toRemove_map[impl_name] = handle;
888     }
889   _numInstanceMutex.unlock();
890 }
891
892 //=============================================================================
893 /*! 
894  *  Retrieves only with container naming convention if it is a python container
895  */
896 //=============================================================================
897
898 bool Engines_Container_i::isPythonContainer(const char* ContainerName)
899 {
900   bool ret=false;
901   int len=strlen(ContainerName);
902   if(len>=2)
903     if(strcmp(ContainerName+len-2,"Py")==0)
904       ret=true;
905   return ret;
906 }
907
908 //=============================================================================
909 /*! 
910  *  
911  */
912 //=============================================================================
913
914 void ActSigIntHandler()
915 {
916 #ifndef WNT
917   struct sigaction SigIntAct ;
918   SigIntAct.sa_sigaction = &SigIntHandler ;
919   SigIntAct.sa_flags = SA_SIGINFO ;
920 #endif
921
922 // DEBUG 03.02.2005 : the first parameter of sigaction is not a mask of signals
923 // (SIGINT | SIGUSR1) :
924 // it must be only one signal ===> one call for SIGINT 
925 // and an other one for SIGUSR1
926
927 #ifndef WNT
928   if ( sigaction( SIGINT , &SigIntAct, NULL ) ) 
929     {
930       perror("SALOME_Container main ") ;
931       exit(0) ;
932     }
933   if ( sigaction( SIGUSR1 , &SigIntAct, NULL ) )
934     {
935       perror("SALOME_Container main ") ;
936       exit(0) ;
937     }
938   if ( sigaction( SIGUSR2 , &SigIntAct, NULL ) )
939     {
940       perror("SALOME_Container main ") ;
941       exit(0) ;
942     }
943
944   //PAL9042 JR : during the execution of a Signal Handler (and of methods called through Signal Handlers)
945   //             use of streams (and so on) should never be used because :
946   //             streams of C++ are naturally thread-safe and use pthread_mutex_lock ===>
947   //             A stream operation may be interrupted by a signal and if the Handler use stream we
948   //             may have a "Dead-Lock" ===HangUp
949   //==INFOS is commented
950   //  INFOS(pthread_self() << "SigIntHandler activated") ;
951
952 #else  
953   signal( SIGINT, SigIntHandler );
954   signal( SIGUSR1, SigIntHandler );
955 #endif
956
957 }
958
959 void SetCpuUsed() ;
960 void CallCancelThread() ;
961
962 #ifndef WNT
963 void SigIntHandler(int what ,
964                    siginfo_t * siginfo ,
965                    void * toto ) 
966 {
967   //PAL9042 JR : during the execution of a Signal Handler (and of methods called through Signal Handlers)
968   //             use of streams (and so on) should never be used because :
969   //             streams of C++ are naturally thread-safe and use pthread_mutex_lock ===>
970   //             A stream operation may be interrupted by a signal and if the Handler use stream we
971   //             may have a "Dead-Lock" ===HangUp
972   //==MESSAGE is commented
973   //  MESSAGE(pthread_self() << "SigIntHandler what     " << what << endl
974   //          << "              si_signo " << siginfo->si_signo << endl
975   //          << "              si_code  " << siginfo->si_code << endl
976   //          << "              si_pid   " << siginfo->si_pid) ;
977
978   if ( _Sleeping )
979     {
980       _Sleeping = false ;
981       //     MESSAGE("SigIntHandler END sleeping.") ;
982       return ;
983     }
984   else
985     {
986       ActSigIntHandler() ;
987       if ( siginfo->si_signo == SIGUSR1 )
988         {
989           SetCpuUsed() ;
990         }
991       else if ( siginfo->si_signo == SIGUSR2 )
992         {
993           CallCancelThread() ;
994         }
995       else 
996         {
997           _Sleeping = true ;
998           //      MESSAGE("SigIntHandler BEGIN sleeping.") ;
999           int count = 0 ;
1000           while( _Sleeping )
1001             {
1002               sleep( 1 ) ;
1003               count += 1 ;
1004             }
1005           //      MESSAGE("SigIntHandler LEAVE sleeping after " << count << " s.") ;
1006         }
1007       return ;
1008     }
1009 }
1010 #else // Case WNT
1011 void SigIntHandler( int what )
1012 {
1013   MESSAGE( pthread_self() << "SigIntHandler what     " << what << endl );
1014   if ( _Sleeping )
1015     {
1016       _Sleeping = false ;
1017       MESSAGE("SigIntHandler END sleeping.") ;
1018       return ;
1019     }
1020   else
1021     {
1022       ActSigIntHandler() ;
1023       if ( what == SIGUSR1 )
1024         {
1025           SetCpuUsed() ;
1026         }
1027       else
1028         {
1029           _Sleeping = true ;
1030           MESSAGE("SigIntHandler BEGIN sleeping.") ;
1031           int count = 0 ;
1032           while( _Sleeping ) 
1033             {
1034               Sleep( 1000 ) ;
1035               count += 1 ;
1036             }
1037           MESSAGE("SigIntHandler LEAVE sleeping after " << count << " s.") ;
1038         }
1039       return ;
1040     }
1041 }
1042 #endif