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