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