Salome HOME
e36089f5e2493ec8ea9ac850cd2cfcdcaca35441
[modules/kernel.git] / src / Container / Container_i.cxx
1 //  SALOME Container : implementation of container and engine for Kernel
2 //
3 //  Copyright (C) 2003  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 //  CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS 
5 // 
6 //  This library is free software; you can redistribute it and/or 
7 //  modify it under the terms of the GNU Lesser General Public 
8 //  License as published by the Free Software Foundation; either 
9 //  version 2.1 of the License. 
10 // 
11 //  This library is distributed in the hope that it will be useful, 
12 //  but WITHOUT ANY WARRANTY; without even the implied warranty of 
13 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU 
14 //  Lesser General Public License for more details. 
15 // 
16 //  You should have received a copy of the GNU Lesser General Public 
17 //  License along with this library; if not, write to the Free Software 
18 //  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA 
19 // 
20 //  See http://www.opencascade.org/SALOME/ or email : webmaster.salome@opencascade.org 
21 //
22 //
23 //
24 //  File   : Container_i.cxx
25 //  Author : Paul RASCLE, EDF - MARC TAJCHMAN, CEA 
26 //  Module : SALOME
27 //  $Header$
28
29 #include <SALOMEconfig.h>
30 #include CORBA_SERVER_HEADER(SALOME_Component)
31 #include "SALOME_Container_i.hxx"
32 #include "SALOME_NamingService.hxx"
33 #include "Utils_SINGLETON.hxx"
34 #include "OpUtil.hxx"
35 #include <stdio.h>
36 #include <dlfcn.h>
37 #include <unistd.h>
38
39 #include "utilities.h"
40 using namespace std;
41
42 bool _Sleeping = false ;
43
44 // Needed by multi-threaded Python
45 int _ArgC ;
46 char ** _ArgV ;
47
48
49 // Containers with name FactoryServer are started via rsh in LifeCycleCORBA
50 // Other Containers are started via start_impl of FactoryServer
51
52 extern "C" {void ActSigIntHandler() ; }
53 extern "C" {void SigIntHandler(int, siginfo_t *, void *) ; }
54
55 Engines_Container_i::Engines_Container_i () :
56  _numInstance(0)
57 {
58 }
59
60 Engines_Container_i::Engines_Container_i (CORBA::ORB_ptr orb, 
61                                           PortableServer::POA_ptr poa,
62                                           char *containerName ,
63                                           int argc , char* argv[],
64                                           bool regist,
65                                           bool activ ) :
66  _numInstance(0)
67 {
68   _pid = (long)getpid();
69
70   if(regist)
71     ActSigIntHandler() ;
72
73   _ArgC = argc ;
74   _ArgV = argv ;
75
76   _argc = argc ;
77   _argv = argv ;
78   int i = strlen( _argv[ 0 ] ) - 1 ;
79   while ( i >= 0 ) {
80     if ( _argv[ 0 ][ i ] == '/' ) {
81       _argv[ 0 ][ i+1 ] = '\0' ;
82       break ;
83     }
84     i -= 1 ;
85   }
86   string hostname = GetHostname();
87   MESSAGE(hostname << " " << getpid() << " Engines_Container_i starting argc "
88           << _argc << " Thread " << pthread_self() ) ;
89   i = 0 ;
90   while ( _argv[ i ] ) {
91     MESSAGE("           argv" << i << " " << _argv[ i ]) ;
92     i++ ;
93   }
94   if ( argc != 4 ) {
95     MESSAGE("SALOME_Container usage : SALOME_Container ServerName -ORBInitRef NameService=corbaname::hostname:tcpipPortNumber") ;
96 //    exit(0) ;
97   }
98
99   SCRUTE(hostname);
100
101   _containerName = "/Containers/";
102   if (strlen(containerName)== 0)
103     {
104       _containerName += hostname;
105     }
106   else
107     {
108       _containerName += hostname;
109       _containerName += "/" ;
110       _containerName += containerName;
111     }
112
113   _orb = CORBA::ORB::_duplicate(orb) ;
114   _poa = PortableServer::POA::_duplicate(poa) ;
115   // Pour les containers paralleles: il ne faut pas activer le container generique, mais le container specialise
116   if(activ){
117     MESSAGE("activate object");
118     _id = _poa->activate_object(this);
119   }
120
121   // Pour les containers paralleles: il ne faut pas enregistrer le container generique, mais le container specialise
122   if(regist){
123     //   _NS = new SALOME_NamingService(_orb);
124     _NS = SINGLETON_<SALOME_NamingService>::Instance() ;
125     ASSERT(SINGLETON_<SALOME_NamingService>::IsAlreadyExisting()) ;
126     _NS->init_orb( orb ) ;
127
128     Engines::Container_ptr pCont 
129       = Engines::Container::_narrow(_this());
130     SCRUTE(_containerName);
131     _NS->Register(pCont, _containerName.c_str()); 
132   }
133 }
134
135 Engines_Container_i::~Engines_Container_i()
136 {
137   MESSAGE("Container_i::~Container_i()");
138 }
139
140 char* Engines_Container_i::name()
141 {
142    return CORBA::string_dup(_containerName.c_str()) ;
143 }
144
145 char* Engines_Container_i::machineName()
146 {
147   string s = GetHostname();
148   MESSAGE("Engines_Container_i::machineName " << s);
149    return CORBA::string_dup(s.c_str()) ;
150 }
151
152 void Engines_Container_i::ping()
153 {
154   MESSAGE("Engines_Container_i::ping() pid "<< getpid());
155 }
156
157 //! Kill current container
158 bool Engines_Container_i::Kill_impl() {
159   MESSAGE("Engines_Container_i::Kill() pid "<< getpid() << " containerName "
160           << _containerName.c_str() << " machineName "
161           << GetHostname().c_str());
162   exit( 0 ) ;
163 }
164
165 //! Launch a new container from the current container
166 Engines::Container_ptr Engines_Container_i::start_impl(
167                                       const char* ContainerName ) {
168   MESSAGE("start_impl argc " << _argc << " ContainerName " << ContainerName
169           << hex << this << dec) ;
170   _numInstanceMutex.lock() ; // lock on the instance number
171
172   CORBA::Object_var obj = Engines::Container::_nil() ;
173   bool nilvar = true ;
174   try {
175     string cont("/Containers/");
176     cont += machineName() ;
177     cont += "/" ;
178     cont += ContainerName;
179     INFOS(machineName() << " start_impl unknown container " << cont.c_str()
180           << " try to Resolve" );
181     obj = _NS->Resolve( cont.c_str() );
182     nilvar = CORBA::is_nil( obj ) ;
183     if ( nilvar ) {
184       INFOS(machineName() << " start_impl unknown container "
185             << ContainerName);
186     }
187   }
188   catch (ServiceUnreachable&) {
189     INFOS(machineName() << "Caught exception: Naming Service Unreachable");
190   }
191   catch (...) {
192     INFOS(machineName() << "Caught unknown exception.");
193   }
194   if ( !nilvar ) {
195     _numInstanceMutex.unlock() ;
196     MESSAGE("start_impl container found without new launch") ;
197     return Engines::Container::_narrow(obj);
198   }
199   int i = 0 ;
200   while ( _argv[ i ] ) {
201     MESSAGE("           argv" << i << " " << _argv[ i ]) ;
202     i++ ;
203   }
204   string shstr = string(getenv("KERNEL_ROOT_DIR")) + "/bin/salome/SALOME_Container ";
205 //   string shstr( "./runSession SALOME_Container " ) ;
206   shstr += ContainerName ;
207   if ( _argc == 4 ) {
208     shstr += " " ;
209     shstr += _argv[ 2 ] ;
210     shstr += " " ;
211     shstr += _argv[ 3 ] ;
212   }
213
214   // asv : 16.11.04 : creation of log file in /tmp/logs/$USER dir. 
215   // "/tmp/logs/$USER" was created by  runSalome.py -> orbmodule.py.
216   string tempfilename = "/tmp/logs/";
217   tempfilename += getenv( "USER" ) ;
218   tempfilename += "/" ;
219   tempfilename += ContainerName ;
220   tempfilename += ".log" ;
221   FILE* f = fopen ( tempfilename.c_str(), "a" );
222   if ( f ) { // check if file can be opened for writing
223     fclose( f );
224     shstr += " > " ;
225     shstr += tempfilename;
226     shstr += " 2>&1 &" ;
227   }
228   else { // if file can't be opened - use a guaranteed temp file name
229     char* tmpFileName = tempnam( NULL, ContainerName );
230     shstr += " > ";
231     shstr += tmpFileName;
232     shstr += " 2>&1 &";
233     free( tmpFileName );    
234   }
235
236   MESSAGE("system(" << shstr << ")") ;
237   int status = system( shstr.c_str() ) ;
238   if (status == -1) {
239     INFOS("Engines_Container_i::start_impl SALOME_Container failed (system command status -1)") ;
240   }
241   else if (status == 217) {
242     INFOS("Engines_Container_i::start_impl SALOME_Container failed (system command status 217)") ;
243   }
244   INFOS(machineName() << " Engines_Container_i::start_impl SALOME_Container launch done");
245
246 //   pid_t pid = fork() ;
247 //   if ( pid == 0 ) {
248 //     string anExe( _argv[ 0 ] ) ;
249 //     anExe += "runSession" ;
250 //     char * args[ 6 ] ;
251 //     args[ 0 ] = "runSession" ;
252 //     args[ 1 ] = "SALOME_Container" ;
253 //     args[ 2 ] = strdup( ContainerName ) ;
254 //     args[ 3 ] = strdup( _argv[ 2 ] ) ;
255 //     args[ 4 ] = strdup( _argv[ 3 ] ) ;
256 //     args[ 5 ] = NULL ;
257 //     MESSAGE("execl(" << anExe.c_str() << " , " << args[ 0 ] << " , "
258 //                      << args[ 1 ] << " , " << args[ 2 ] << " , " << args[ 3 ]
259 //                      << " , " << args[ 4 ] << ")") ;
260 //     int status = execv( anExe.c_str() , args ) ;
261 //     if (status == -1) {
262 //       INFOS("Engines_Container_i::start_impl execl failed (system command status -1)") ;
263 //       perror( "Engines_Container_i::start_impl execl error ") ;
264 //     }
265 //     else {
266 //       INFOS(machineName() << " Engines_Container_i::start_impl execl done");
267 //     }
268 //     exit(0) ;
269 //   }
270
271   obj = Engines::Container::_nil() ;
272   try {
273     string cont("/Containers/");
274     cont += machineName() ;
275     cont += "/" ;
276     cont += ContainerName;
277     nilvar = true ;
278     int count = 20 ;
279     while ( nilvar && count >= 0) {
280       sleep( 1 ) ;
281       obj = _NS->Resolve(cont.c_str());
282       nilvar = CORBA::is_nil( obj ) ;
283       if ( nilvar ) {
284         INFOS(count << ". " << machineName()
285               << " start_impl unknown container " << cont.c_str());
286         count -= 1 ;
287       }
288     }
289     _numInstanceMutex.unlock() ;
290     if ( !nilvar ) {
291       MESSAGE("start_impl container found after new launch of SALOME_Container") ;
292     }
293     return Engines::Container::_narrow(obj);
294   }
295   catch (ServiceUnreachable&) {
296     INFOS(machineName() << "Caught exception: Naming Service Unreachable");
297   }
298   catch (...) {
299     INFOS(machineName() << "Caught unknown exception.");
300   }
301   _numInstanceMutex.unlock() ;
302   MESSAGE("start_impl container not found after new launch of SALOME_Container") ;
303   return Engines::Container::_nil() ;
304 }
305
306 Engines::Component_ptr Engines_Container_i::load_impl( const char* nameToRegister,
307                                                        const char* componentName ) {
308
309   _numInstanceMutex.lock() ; // lock on the instance number
310   BEGIN_OF( "Container_i::load_impl " << componentName ) ;
311   _numInstance++ ;
312   char _aNumI[12];
313   sprintf( _aNumI , "%d" , _numInstance ) ;
314
315   string _impl_name = componentName;
316   string _nameToRegister = nameToRegister;
317   string instanceName = _nameToRegister + "_inst_" + _aNumI ;
318   //SCRUTE(instanceName);
319
320   //string absolute_impl_name = _library_path + "lib" + _impl_name + ".so";
321   string absolute_impl_name( _impl_name ) ;
322   SCRUTE(absolute_impl_name);
323   void* handle;
324   handle = dlopen( absolute_impl_name.c_str() , RTLD_LAZY ) ;
325   if ( !handle ) {
326     INFOS("Can't load shared library : " << absolute_impl_name);
327     INFOS("error dlopen: " << dlerror());
328     _numInstanceMutex.unlock() ;
329     return Engines::Component::_nil() ;
330   }
331   
332   string factory_name = _nameToRegister + string("Engine_factory");
333   //  SCRUTE(factory_name) ;
334
335   typedef  PortableServer::ObjectId * (*FACTORY_FUNCTION)
336                             (CORBA::ORB_ptr,
337                              PortableServer::POA_ptr, 
338                              PortableServer::ObjectId *, 
339                              const char *, 
340                              const char *) ; 
341   FACTORY_FUNCTION Component_factory = (FACTORY_FUNCTION) dlsym(handle, factory_name.c_str());
342
343   char *error ;
344   if ( (error = dlerror() ) != NULL) {
345       INFOS("Can't resolve symbol: " + factory_name);
346       SCRUTE(error);
347       _numInstanceMutex.unlock() ;
348       return Engines::Component::_nil() ;
349     }
350
351   string component_registerName = _containerName + "/" + _nameToRegister;
352   Engines::Component_var iobject = Engines::Component::_nil() ;
353   try {
354     CORBA::Object_var obj = _NS->Resolve( component_registerName.c_str() ) ;
355     if ( CORBA::is_nil( obj ) ) {
356 // Instanciate required CORBA object
357       PortableServer::ObjectId * id ;
358       id = (Component_factory) ( _orb, _poa, _id, instanceName.c_str() ,
359                                  _nameToRegister.c_str() ) ;
360   // get reference from id
361       obj = _poa->id_to_reference(*id);
362       iobject = Engines::Component::_narrow( obj ) ;
363
364 //  _numInstanceMutex.lock() ; // lock on the add on handle_map (necessary ?)
365   // register the engine under the name containerName.dir/nameToRegister.object
366       _NS->Register( iobject , component_registerName.c_str() ) ;
367       MESSAGE( "Container_i::load_impl " << component_registerName.c_str() << " bound" ) ;
368     }
369     else { // JR : No ReBind !!!
370       MESSAGE( "Container_i::load_impl " << component_registerName.c_str() << " already bound" ) ;
371       iobject = Engines::Component::_narrow( obj ) ;
372     }
373   }
374   catch (...) {
375     INFOS( "Container_i::load_impl catched" ) ;
376   }
377
378 //Jr  _numInstanceMutex.lock() ; // lock on the add on handle_map (necessary ?)
379   handle_map[instanceName] = handle;
380   END_OF("Container_i::load_impl");
381   _numInstanceMutex.unlock() ;
382   return Engines::Component::_duplicate(iobject);
383 }
384
385 void Engines_Container_i::remove_impl(Engines::Component_ptr component_i)
386 {
387   ASSERT(! CORBA::is_nil(component_i));
388   string instanceName = component_i->instanceName() ;
389   MESSAGE("unload component " << instanceName);
390   component_i->destroy() ;
391   MESSAGE("test key handle_map");
392   _numInstanceMutex.lock() ; // lock on the remove on handle_map
393   if (handle_map[instanceName]) // if key does not exist, created & initialized null
394     {
395       remove_map[instanceName] = handle_map[instanceName] ;
396     }
397   else MESSAGE("pas d'entree handle_map");
398   handle_map.erase(instanceName) ;   
399   _numInstanceMutex.unlock() ;
400   MESSAGE("contenu handle_map");
401   map<string, void *>::iterator im ;
402   for (im = handle_map.begin() ; im != handle_map.end() ; im ++)
403     {
404       MESSAGE("reste " << (*im).first);
405     }
406 }
407
408 void Engines_Container_i::finalize_removal()
409 {
410   MESSAGE("finalize unload : dlclose");
411   map<string, void *>::iterator im ;
412   _numInstanceMutex.lock() ; // lock on the explore remove_map & dlclose
413   for (im = remove_map.begin() ; im != remove_map.end() ; im ++)
414     {
415       void * handle = (*im).second ;
416       dlclose(handle) ;
417       MESSAGE("dlclose " << (*im).first);
418     }
419   remove_map.clear() ;  
420   _numInstanceMutex.unlock() ;
421   MESSAGE("remove_map.clear()");
422 }
423
424 void ActSigIntHandler() {
425   struct sigaction SigIntAct ;
426   SigIntAct.sa_sigaction = &SigIntHandler ;
427   SigIntAct.sa_flags = SA_SIGINFO ;
428   if ( sigaction( SIGINT | SIGUSR1 , &SigIntAct, NULL ) ) {
429     perror("SALOME_Container main ") ;
430     exit(0) ;
431   }
432   else {
433     INFOS(pthread_self() << "SigIntHandler activated") ;
434   }
435 }
436
437 void SetCpuUsed() ;
438
439 void SigIntHandler(int what , siginfo_t * siginfo ,
440                                         void * toto ) {
441   MESSAGE(pthread_self() << "SigIntHandler what     " << what << endl
442           << "              si_signo " << siginfo->si_signo << endl
443           << "              si_code  " << siginfo->si_code << endl
444           << "              si_pid   " << siginfo->si_pid) ;
445   if ( _Sleeping ) {
446     _Sleeping = false ;
447     MESSAGE("SigIntHandler END sleeping.") ;
448     return ;
449   }
450   else {
451     ActSigIntHandler() ;
452     if ( siginfo->si_signo == SIGUSR1 ) {
453       SetCpuUsed() ;
454     }
455     else {
456       _Sleeping = true ;
457       MESSAGE("SigIntHandler BEGIN sleeping.") ;
458       int count = 0 ;
459       while( _Sleeping ) {
460         sleep( 1 ) ;
461         count += 1 ;
462       }
463       MESSAGE("SigIntHandler LEAVE sleeping after " << count << " s.") ;
464     }
465     return ;
466   }
467 }
468
469 // Get the PID of the Container
470
471 long Engines_Container_i::getPID() {
472     return (long)getpid();
473 }
474
475 // Get the hostName of the Container
476
477 char* Engines_Container_i::getHostName() {
478     return((char*)(GetHostname().c_str()));
479 }