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