Salome HOME
updated copyright message
[modules/kernel.git] / src / ParallelContainer / SALOME_ParallelContainer_i.cxx
1 // Copyright (C) 2007-2023  CEA, EDF, 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, or (at your option) any later version.
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 //  File   : SALOME_ParallelContainer_i.cxx
23 //  Author : AndrĂ© RIBES, EDF
24
25 #include "SALOME_ParallelContainer_i.hxx"
26 #include "SALOME_Component_i.hxx"
27 #include "SALOME_FileRef_i.hxx"
28 #include "SALOME_FileTransfer_i.hxx"
29 #include "SALOME_NamingService.hxx"
30 #include "OpUtil.hxx"
31 #include "utilities.h"
32 #include "Basics_Utils.hxx"
33
34 #include <string.h>
35 #include <stdio.h>
36 #ifndef WIN32
37 #include <sys/time.h>
38 #include <dlfcn.h>
39 #include <unistd.h>
40 #else
41 #include <signal.h>
42 #include <process.h>
43 #include <direct.h>
44 int SIGUSR1 = 1000;
45 #endif
46
47 #include <paco_omni.h>
48
49 #include <Python.h>
50 #include "Container_init_python.hxx"
51
52
53 bool _Sleeping = false ;
54
55 extern "C" {void ActSigIntHandler() ; }
56 #ifndef WIN32
57 extern "C" {void SigIntHandler(int, siginfo_t *, void *) ; }
58 #else
59 extern "C" {void SigIntHandler( int ) ; }
60 #endif
61
62 /*! \class Engines_Parallel_Container_i
63  *  \brief C++ implementation of Engines::Container interface for parallel
64  *  container implemented with PaCO++
65  */
66
67 //=============================================================================
68 /*! 
69  *  Constructor
70  */
71 //=============================================================================
72
73 Engines_Parallel_Container_i::Engines_Parallel_Container_i (CORBA::ORB_ptr orb, 
74                                                             char * ior, 
75                                                             int rank,
76                                                             PortableServer::POA_ptr poa,
77                                                             std::string containerName,
78                                                             bool isServantAloneInProcess) :
79   InterfaceParallel_impl(orb,ior,rank), 
80   Engines::PACO_Container_serv(orb,ior,rank),
81   Engines::PACO_Container_base_serv(orb,ior,rank),
82   Engines::Container_serv(orb,ior,rank),
83   Engines::Container_base_serv(orb,ior,rank),
84   _numInstance(0),_isServantAloneInProcess(isServantAloneInProcess)
85 {
86   // Members init
87   _pid = getpid();
88   _hostname = Kernel_Utils::GetHostname();
89   _orb = CORBA::ORB::_duplicate(orb);
90   _poa = PortableServer::POA::_duplicate(poa);
91
92   // Add CORBA object to the poa
93   _id = _poa->activate_object(this);
94   this->_remove_ref();
95   CORBA::Object_var container_node = _poa->id_to_reference(*_id);
96
97   // Adding this servant to SALOME
98   _NS = new SALOME_NamingService();
99   _NS->init_orb(_orb);
100   _containerName = _NS->BuildContainerNameForNS(containerName.c_str(), _hostname.c_str());
101
102   // Ajout du numero de noeud
103   char node_number[12];
104   sprintf(node_number, "%d", getMyRank());
105   _containerName = _containerName + node_number;
106
107   // Init Python container part
108   CORBA::String_var sior =  _orb->object_to_string(container_node);
109   std::string myCommand="pyCont = SALOME_Container.SALOME_Container_i('";
110   myCommand += _containerName + "','";
111   myCommand += sior;
112   myCommand += "')\n";
113   Py_ACQUIRE_NEW_THREAD;
114   PyRun_SimpleString("import SALOME_Container\n");
115   PyRun_SimpleString((char*)myCommand.c_str());
116   Py_RELEASE_NEW_THREAD;
117
118   // Init FileTransfer service
119   fileTransfer_i* aFileTransfer = new fileTransfer_i();
120   _fileTransfer = aFileTransfer->_this();
121   aFileTransfer->_remove_ref();
122
123   // Some signal handlers
124   ActSigIntHandler();
125 }
126
127 //=============================================================================
128 /*! 
129  *  Destructor
130  */
131 //=============================================================================
132
133 Engines_Parallel_Container_i::~Engines_Parallel_Container_i()
134 {
135   MESSAGE("Container_i::~Container_i()");
136   if (_id)
137     delete _id;
138   if(_NS)
139     delete _NS;
140 }
141
142 //=============================================================================
143 //! Get container name
144 /*! 
145  *  CORBA attribute: Container name (see constructor)
146  */
147 //=============================================================================
148
149 char* Engines_Parallel_Container_i::name()
150 {
151   return CORBA::string_dup(_containerName.c_str()) ;
152 }
153
154 //=============================================================================
155 //! Get container working directory
156 /*! 
157  *  CORBA attribute: Container working directory 
158  */
159 //=============================================================================
160
161 char* 
162 Engines_Parallel_Container_i::workingdir()
163 {
164   char wd[256];
165   getcwd (wd,256);
166   return CORBA::string_dup(wd) ;
167 }
168
169 //=============================================================================
170 //! Get container log file name
171 /*! 
172  *  CORBA attribute: Container log file name
173  */
174 //=============================================================================
175
176 char* 
177 Engines_Parallel_Container_i::logfilename()
178 {
179   return CORBA::string_dup(_logfilename.c_str()) ;
180 }
181
182 //! Set container log file name
183 void 
184 Engines_Parallel_Container_i::logfilename(const char* name)
185 {
186   _logfilename=name;
187 }
188
189 //=============================================================================
190 //! Get container host name
191 /*! 
192  *  CORBA method: Get the hostName of the Container (without domain extensions)
193  */
194 //=============================================================================
195
196 char* Engines_Parallel_Container_i::getHostName()
197 {
198   MESSAGE("Warning: getHostName of a parallel container returns the hostname of the first servant node");
199   return CORBA::string_dup(_hostname.c_str()) ;
200 }
201
202 //=============================================================================
203 //! Get container PID
204 /*! 
205  *  CORBA method: Get the PID (process identification) of the Container
206  */
207 //=============================================================================
208
209 CORBA::Long Engines_Parallel_Container_i::getPID()
210 {
211   MESSAGE("Warning: getPID of a parallel container returns the PID of the first servant node");
212   return _pid;
213 }
214
215 //=============================================================================
216 //! Ping the servant to check it is still alive
217 /*! 
218  *  CORBA method: check if servant is still alive
219  */
220 //=============================================================================
221
222 void Engines_Parallel_Container_i::ping()
223 {
224   MESSAGE("Engines_Parallel_Container_i::ping() my pid is "<< _pid);
225 }
226
227 //=============================================================================
228 //! Shutdown the container
229 /*! 
230  *  CORBA method, oneway: Server shutdown. 
231  *  - Container name removed from naming service,
232  *  - servant deactivation,
233  *  - orb shutdown if no other servants in the process 
234  */
235 //=============================================================================
236
237 void Engines_Parallel_Container_i::Shutdown()
238 {
239   MESSAGE("Engines_Parallel_Container_i::Shutdown()");
240
241   /* For each seq component contained in this container
242   * tell it to self-destroy
243   */
244   std::map<std::string, Engines::EngineComponent_var>::iterator itm;
245   for (itm = _listInstances_map.begin(); itm != _listInstances_map.end(); itm++)
246   {
247     try
248     {
249       itm->second->destroy();
250     }
251     catch(const CORBA::Exception& e)
252     {
253       // ignore this entry and continue
254     }
255     catch(...)
256     {
257       // ignore this entry and continue
258     }
259   }
260
261   // Destroy each parallel component node...
262   std::map<std::string, PortableServer::ObjectId *>::iterator i;
263   for (i = _par_obj_inst_map.begin(); i != _par_obj_inst_map.end(); i++)
264     _poa->deactivate_object(*(i->second));
265
266   _NS->Destroy_FullDirectory(_containerName.c_str());
267   _NS->Destroy_Name(_containerName.c_str());
268
269   if(_isServantAloneInProcess)
270   {
271     MESSAGE("Effective Shutdown of container Begins...");
272     if(!CORBA::is_nil(_orb))
273       _orb->shutdown(0);
274   }
275 }
276
277
278 //=============================================================================
279 //! load a new component class
280 /*! 
281  *  CORBA method: load a new component class (Python or C++ implementation)
282  *  \param componentName like COMPONENT
283  *                          try to make a Python import of COMPONENT,
284  *                          then a lib open of libCOMPONENTEngine.so
285  *  \return true if dlopen successful or already done, false otherwise
286  */
287 //=============================================================================
288
289 bool
290 Engines_Parallel_Container_i::load_component_Library(const char* componentName, CORBA::String_out reason)
291 {
292   reason=CORBA::string_dup("");
293
294   MESSAGE("Begin of load_component_Library : " << componentName)
295   bool ret = false;
296   std::string aCompName = componentName;
297 #ifndef WIN32
298 #ifdef __APPLE__
299   std::string impl_name = string ("lib") + aCompName + string("Engine.dylib");
300 #else
301   std::string impl_name = string ("lib") + aCompName + string("Engine.so");
302 #endif
303 #else
304   std::string impl_name = aCompName + string("Engine.dll");
305 #endif
306
307   _numInstanceMutex.lock(); // lock to be alone 
308
309   // Check if already loaded or imported in the container
310   if (_toRemove_map.count(impl_name) != 0) _toRemove_map.erase(impl_name);
311   if (_library_map.count(impl_name) != 0)
312   {
313     MESSAGE("Library " << impl_name << " already loaded");
314     ret = true;
315   }
316   if (_library_map.count(aCompName) != 0)
317   {
318     MESSAGE("Python component already imported");
319     ret = true;
320   }
321
322   // --- try dlopen C++ component
323   if (!ret)
324   {
325     MESSAGE("Try to load C++ component");
326     void* handle;
327 #ifndef WIN32
328     handle = dlopen( impl_name.c_str() , RTLD_LAZY | RTLD_GLOBAL ) ;
329 #else
330     handle = dlopen( impl_name.c_str() , 0 ) ;
331 #endif
332     if ( handle )
333     {
334       _library_map[impl_name] = handle;
335       MESSAGE("Library " << impl_name << " loaded");
336       ret = true;
337     }
338     else
339     {
340       std::cerr << "Can't load shared library : " << impl_name << std::endl;
341       std::cerr << "error of dlopen: " << dlerror() << std::endl;
342     }
343   }
344
345   // --- try import Python component
346   if (!ret)
347   {
348     MESSAGE("Try to import Python component "<<componentName);
349     Py_ACQUIRE_NEW_THREAD;
350     PyObject *mainmod = PyImport_AddModule("__main__");
351     PyObject *globals = PyModule_GetDict(mainmod);
352     PyObject *pyCont = PyDict_GetItemString(globals, "pyCont");
353     PyObject *result = PyObject_CallMethod(pyCont,
354                                            (char*)"import_component",
355                                            (char*)"s",componentName);
356     std::string ret_p= PyUnicode_AsUTF8(result);
357     Py_XDECREF(result);
358     Py_RELEASE_NEW_THREAD;
359
360     if (ret_p=="") // import possible: Python component
361     {
362       _library_map[aCompName] = (void *)pyCont; // any non O value OK
363       MESSAGE("import Python: " << aCompName <<" OK");
364       ret = true;
365     }
366     else
367     {
368       std::cerr << "Error in importing Python component : " << aCompName << std::endl;
369     }
370   }
371
372   _numInstanceMutex.unlock();
373   return ret;
374 }
375
376 //=============================================================================
377 //! Create a new component instance
378 /*! 
379  *  CORBA method: Creates a new servant instance of a component.
380  *  The servant registers itself to naming service and Registry.
381  *  \param genericRegisterName  Name of the component instance to register
382  *                         in Registry & Name Service (without _inst_n suffix)
383  *  \return a loaded component
384  */
385 //=============================================================================
386 Engines::EngineComponent_ptr
387 Engines_Parallel_Container_i::create_component_instance(const char*genericRegisterName)
388 {
389   Engines::FieldsDict_var env = new Engines::FieldsDict;
390   char* reason;
391   Engines::EngineComponent_ptr compo = create_component_instance_env(genericRegisterName,env, reason);
392   CORBA::string_free(reason);
393   return compo;
394 }
395
396 //=============================================================================
397 //! Create a new component instance
398 /*! 
399  *  CORBA method: Creates a new servant instance of a component.
400  *  The servant registers itself to naming service and Registry.
401  *  \param genericRegisterName  Name of the component instance to register
402  *                         in Registry & Name Service (without _inst_n suffix)
403  *  \param env             dict of environment variables
404  *  \return a loaded component
405  */
406 //=============================================================================
407
408 Engines::EngineComponent_ptr
409 Engines_Parallel_Container_i::create_component_instance_env(const char*genericRegisterName,
410                                                             const Engines::FieldsDict& env,
411                                                             CORBA::String_out reason)
412 {
413   MESSAGE("Begin of create_component_instance in node : " << getMyRank());
414   reason=CORBA::string_dup("");
415
416   std::string aCompName = genericRegisterName;
417 #ifndef WIN32
418 #ifdef __APPLE__
419   std::string impl_name = string ("lib") + aCompName + string("Engine.dylib");
420 #else
421   std::string impl_name = string ("lib") + aCompName +string("Engine.so");
422 #endif
423 #else
424   std::string impl_name = aCompName +string("Engine.dll");
425 #endif
426
427   _numInstanceMutex.lock();
428   _numInstance++;
429
430   // Test if the component lib is loaded
431   std::string type_of_lib("Not Loaded");
432   void* handle = _library_map[impl_name];
433   if (handle)
434     type_of_lib = "cpp";
435   if (_library_map.count(aCompName) != 0 && !handle)
436     type_of_lib = "python";
437   
438   if (type_of_lib == "Not Loaded")
439   {
440     std::cerr << "Component library is not loaded or imported ! lib was : " << aCompName << std::endl;
441     _numInstanceMutex.unlock();
442     return Engines::EngineComponent::_nil();
443   }
444
445   Engines::EngineComponent_var iobject = Engines::EngineComponent::_nil();
446   if (type_of_lib == "cpp")
447     iobject = createCPPInstance(aCompName, handle);
448   else
449     iobject = createPythonInstance(aCompName);
450
451   _numInstanceMutex.unlock();
452   return iobject._retn();
453 }
454
455 //=============================================================================
456 //! Find an existing (in the container) component instance
457 /*! 
458  *  CORBA method: Finds a servant instance of a component
459  *  \param registeredName  Name of the component in Registry or Name Service,
460  *                         without instance suffix number
461  *  \return the first found instance
462  */
463 //=============================================================================
464
465 Engines::EngineComponent_ptr Engines_Parallel_Container_i::find_component_instance(const char* registeredName)
466 {
467   Engines::EngineComponent_var anEngine = Engines::EngineComponent::_nil();
468   std::map<std::string,Engines::EngineComponent_var>::iterator itm =_listInstances_map.begin();
469   while (itm != _listInstances_map.end())
470   {
471     std::string instance = (*itm).first;
472     SCRUTE(instance);
473     if (instance.find(registeredName) == 0)
474     {
475       anEngine = (*itm).second;
476       return anEngine._retn();
477     }
478     itm++;
479   }
480   return anEngine._retn();  
481 }
482
483 char* Engines_Parallel_Container_i::create_python_service_instance(const char* CompName,
484                                                                    CORBA::String_out reason)
485 {
486   // not implemented
487   reason=CORBA::string_dup("");
488   return CORBA::string_dup("");
489 }
490
491 //=============================================================================
492 //! Find or create a new component instance
493 /*! 
494  *  CORBA method: find or create an instance of the component (servant),
495  *  load a new component class (dynamic library) if required,
496  *  ---- FOR COMPATIBILITY WITH 2.2 ---- 
497  *  ---- USE ONLY FOR MULTISTUDY INSTANCES ! --------
498  *  The servant registers itself to naming service and Registry.
499  *  \param genericRegisterName  Name of the component to register
500  *                              in Registry & Name Service
501  *  \param componentName       Name of the constructed library of the component
502  *  \return a loaded component
503  */
504 //=============================================================================
505
506 Engines::EngineComponent_ptr Engines_Parallel_Container_i::load_impl( const char* genericRegisterName,
507                                                                 const char* componentName )
508 {
509   Engines::EngineComponent_var iobject = Engines::EngineComponent::_nil();
510   char* reason;
511   if (load_component_Library(genericRegisterName,reason))
512     iobject = find_or_create_instance(genericRegisterName);
513   CORBA::string_free(reason);
514   return iobject._retn();
515 }
516
517
518 //=============================================================================
519 //! Remove the component instance from container
520 /*! 
521  *  CORBA method: Stops the component servant, and deletes all related objects
522  *  \param component_i     Component to be removed
523  */
524 //=============================================================================
525
526 void Engines_Parallel_Container_i::remove_impl(Engines::EngineComponent_ptr component_i)
527 {
528   ASSERT(!CORBA::is_nil(component_i));
529   std::string instanceName = component_i->instanceName();
530   _numInstanceMutex.lock() ; // lock to be alone (stl container write)
531   // Test if the component is in this container
532   std::map<std::string, Engines::EngineComponent_var>::iterator itm;
533   itm = _listInstances_map.find(instanceName);
534   if (itm != _listInstances_map.end())
535   {
536     MESSAGE("Unloading component " << instanceName);
537     _listInstances_map.erase(instanceName);
538     component_i->destroy() ;
539     _NS->Destroy_Name(instanceName.c_str());
540   }
541   else
542     std::cerr << "WARNING !!!! component instance was not in this container !!!" << std::endl;
543   _numInstanceMutex.unlock() ;
544 }
545
546 //=============================================================================
547 //! Unload component libraries from the container
548 /*! 
549  *  CORBA method: Discharges unused libraries from the container.
550  */
551 //=============================================================================
552
553 void Engines_Parallel_Container_i::finalize_removal()
554 {
555   MESSAGE("Finalize removal : dlclose");
556   MESSAGE("WARNING FINALIZE DOES CURRENTLY NOTHING !!!");
557
558   // (see decInstanceCnt, load_component_Library)
559   //std::map<std::string, void *>::iterator ith;
560   //for (ith = _toRemove_map.begin(); ith != _toRemove_map.end(); ith++)
561   //{
562   //  void *handle = (*ith).second;
563   //  std::string impl_name= (*ith).first;
564   //  if (handle)
565   //  {
566   //    SCRUTE(handle);
567   //    SCRUTE(impl_name);
568   //    dlclose(handle);                // SALOME unstable after ...
569   //    _library_map.erase(impl_name);
570   //  }
571   //}
572
573   _numInstanceMutex.lock(); // lock to be alone
574   _toRemove_map.clear();
575   _numInstanceMutex.unlock();
576 }
577
578 //=============================================================================
579 //! Kill the container
580 /*! 
581  *  CORBA method: Kill the container process with exit(0).
582  *  To remove :  never returns !
583  */
584 //=============================================================================
585
586 bool Engines_Parallel_Container_i::Kill_impl()
587 {
588   MESSAGE("Engines_Parallel_Container_i::Kill() my pid is "<< _pid 
589           << " my containerName is " << _containerName.c_str() 
590           << " my machineName is " << _hostname.c_str());
591   INFOS("===============================================================");
592   INFOS("= REMOVE calls to Kill_impl in C++ container                  =");
593   INFOS("===============================================================");
594   //exit( 0 ) ;
595   ASSERT(0);
596   return false;
597 }
598
599 //=============================================================================
600 //! Get or create a file reference object associated to a local file (to transfer it)
601 /*! 
602  *  CORBA method: get or create a fileRef object associated to a local file
603  *  (a file on the computer on which runs the container server), which stores
604  *  a list of (machine, localFileName) corresponding to copies already done.
605  * 
606  *  \param  origFileName absolute path for a local file to copy on other
607  *          computers
608  *  \return a fileRef object associated to the file.
609  */
610 //=============================================================================
611
612 Engines::fileRef_ptr
613 Engines_Parallel_Container_i::createFileRef(const char* origFileName)
614 {
615   std::string origName(origFileName);
616   Engines::fileRef_var theFileRef = Engines::fileRef::_nil();
617
618   if (origName[0] != '/')
619   {
620     INFOS("path of file to copy must be an absolute path beginning with '/'");
621     return Engines::fileRef::_nil();
622   }
623
624   if (CORBA::is_nil(_fileRef_map[origName]))
625   {
626     CORBA::Object_var obj=_poa->id_to_reference(*_id);
627     Engines::Container_var pCont = Engines::Container::_narrow(obj);
628     fileRef_i* aFileRef = new fileRef_i(pCont, origFileName);
629     theFileRef = Engines::fileRef::_narrow(aFileRef->_this());
630     _numInstanceMutex.lock() ; // lock to be alone (stl container write)
631     _fileRef_map[origName] = theFileRef;
632     _numInstanceMutex.unlock() ;
633   }
634
635   theFileRef =  Engines::fileRef::_duplicate(_fileRef_map[origName]);
636   ASSERT(! CORBA::is_nil(theFileRef));
637   return theFileRef._retn();
638 }
639
640 //=============================================================================
641 /*! 
642  *  CORBA method:
643  *  \return a reference to the fileTransfer object
644  */
645 //=============================================================================
646
647 Engines::fileTransfer_ptr
648 Engines_Parallel_Container_i::getFileTransfer()
649 {
650   Engines::fileTransfer_var aFileTransfer
651     = Engines::fileTransfer::_duplicate(_fileTransfer);
652   return aFileTransfer._retn();
653 }
654
655
656 Engines::Salome_file_ptr 
657 Engines_Parallel_Container_i::createSalome_file(const char* origFileName) 
658 {
659   string origName(origFileName);
660   if (CORBA::is_nil(_Salome_file_map[origName]))
661   {
662     Salome_file_i* aSalome_file = new Salome_file_i();
663     try 
664     {
665       aSalome_file->setLocalFile(origFileName);
666       aSalome_file->recvFiles();
667     }
668     catch (const SALOME::SALOME_Exception& e)
669     {
670       return Engines::Salome_file::_nil();
671     }
672
673     Engines::Salome_file_var theSalome_file = Engines::Salome_file::_nil();
674     theSalome_file = Engines::Salome_file::_narrow(aSalome_file->_this());
675     _numInstanceMutex.lock() ; // lock to be alone (stl container write)
676     _Salome_file_map[origName] = theSalome_file;
677     _numInstanceMutex.unlock() ;
678   }
679
680   Engines::Salome_file_ptr theSalome_file =  
681     Engines::Salome_file::_duplicate(_Salome_file_map[origName]);
682   ASSERT(!CORBA::is_nil(theSalome_file));
683   return theSalome_file;
684 }
685
686
687 //=============================================================================
688 //! Finds an already existing component instance or create a new instance
689 /*! 
690  *  C++ method: Finds an already existing servant instance of a component, or
691  *              create an instance.
692  *  ---- USE ONLY FOR MULTISTUDY INSTANCES ! --------
693  *  \param genericRegisterName    Name of the component instance to register
694  *                                in Registry & Name Service,
695  *                                (without _inst_n suffix, like "COMPONENT")
696  *  \return a loaded component
697  * 
698  *  example with names:
699  *  aGenRegisterName = COMPONENT (= first argument)
700  *  impl_name = libCOMPONENTEngine.so (= second argument)
701  *  _containerName = /Containers/cli76ce/FactoryServer
702  *  factoryName = COMPONENTEngine_factory
703  *  component_registerBase = /Containers/cli76ce/FactoryServer/COMPONENT
704  *
705  *  instanceName = COMPONENT_inst_1
706  *  component_registerName = /Containers/cli76ce/FactoryServer/COMPONENT_inst_1
707  */
708 //=============================================================================
709
710 Engines::EngineComponent_ptr
711 Engines_Parallel_Container_i::find_or_create_instance(std::string genericRegisterName)
712 {
713   Engines::EngineComponent_var iobject = Engines::EngineComponent::_nil();
714   try
715   {
716     std::string aGenRegisterName = genericRegisterName;
717     // --- find a registered instance in naming service, or create
718     std::string component_registerBase = _containerName + "/" + aGenRegisterName;
719     CORBA::Object_var obj = _NS->ResolveFirst(component_registerBase.c_str());
720     if (CORBA::is_nil( obj ))
721     {
722       iobject = create_component_instance(genericRegisterName.c_str());
723     }
724     else
725     { 
726       iobject = Engines::EngineComponent::_narrow(obj) ;
727     }
728   }
729   catch (...)
730   {
731     INFOS( "Container_i::load_impl caught" ) ;
732   }
733   return iobject._retn();
734 }
735
736 //=============================================================================
737 //! Create a new Python component instance 
738 /*! 
739  *  C++ method: create a servant instance of a component.
740  *  \param genericRegisterName    Name of the component instance to register
741  *                                in Registry & Name Service,
742  *                                (without _inst_n suffix, like "COMPONENT")
743  *  \param handle                 loaded library handle
744  *  \return a loaded component
745  * 
746  *  example with names:
747  *  aGenRegisterName = COMPONENT (= first argument)
748  *  _containerName = /Containers/cli76ce/FactoryServer
749  *  factoryName = COMPONENTEngine_factory
750  *  component_registerBase = /Containers/cli76ce/FactoryServer/COMPONENT
751  *  instanceName = COMPONENT_inst_1
752  *  component_registerName = /Containers/cli76ce/FactoryServer/COMPONENT_inst_1
753  */
754 //=============================================================================
755 Engines::EngineComponent_ptr
756 Engines_Parallel_Container_i::createPythonInstance(std::string genericRegisterName)
757 {
758
759   Engines::EngineComponent_var iobject = Engines::EngineComponent::_nil();
760
761   int numInstance = _numInstance;
762   char aNumI[12];
763   sprintf( aNumI , "%d" , numInstance ) ;
764   std::string instanceName = genericRegisterName + "_inst_" + aNumI ;
765   std::string component_registerName = _containerName + "/" + instanceName;
766
767   Py_ACQUIRE_NEW_THREAD;
768   PyObject *mainmod = PyImport_AddModule("__main__");
769   PyObject *globals = PyModule_GetDict(mainmod);
770   PyObject *pyCont = PyDict_GetItemString(globals, "pyCont");
771   PyObject *result = PyObject_CallMethod(pyCont,
772                                          (char*)"create_component_instance",
773                                          (char*)"ss",
774                                          genericRegisterName.c_str(),
775                                          instanceName.c_str());
776   const char *ior;
777   const char *error;
778   PyArg_ParseTuple(result,"ss", &ior, &error);
779   string iors = ior;
780   Py_DECREF(result);
781   Py_RELEASE_NEW_THREAD;
782
783   if( iors!="" )
784   {
785     CORBA::Object_var obj = _orb->string_to_object(iors.c_str());
786     iobject = Engines::EngineComponent::_narrow(obj);
787     _listInstances_map[instanceName] = iobject;
788   }
789   else
790     std::cerr << "createPythonInstance ior is empty ! Error in creation" << std::endl;
791
792   return iobject._retn();
793 }
794
795 //=============================================================================
796 //! Create a new CPP component instance 
797 /*! 
798  *  C++ method: create a servant instance of a component.
799  *  \param genericRegisterName    Name of the component instance to register
800  *                                in Registry & Name Service,
801  *                                (without _inst_n suffix, like "COMPONENT")
802  *  \param handle                 loaded library handle
803  *  \return a loaded component
804  * 
805  *  example with names:
806  *  aGenRegisterName = COMPONENT (= first argument)
807  *  _containerName = /Containers/cli76ce/FactoryServer
808  *  factoryName = COMPONENTEngine_factory
809  *  component_registerBase = /Containers/cli76ce/FactoryServer/COMPONENT
810  *  instanceName = COMPONENT_inst_1
811  *  component_registerName = /Containers/cli76ce/FactoryServer/COMPONENT_inst_1
812  */
813 //=============================================================================
814 Engines::EngineComponent_ptr
815 Engines_Parallel_Container_i::createCPPInstance(std::string genericRegisterName,
816                                                 void *handle)
817 {
818   MESSAGE("Entering Engines_Parallel_Container_i::createCPPInstance");
819
820   // --- find the factory
821
822   std::string aGenRegisterName = genericRegisterName;
823   std::string factory_name = aGenRegisterName + string("Engine_factory");
824
825   typedef  PortableServer::ObjectId * (*FACTORY_FUNCTION_2)
826     (CORBA::ORB_ptr,
827      PortableServer::POA_ptr, 
828      PortableServer::ObjectId *, 
829      const char *, 
830      const char *) ;
831
832   FACTORY_FUNCTION_2 Component_factory = NULL;
833 #ifndef WIN32
834   Component_factory = (FACTORY_FUNCTION_2)dlsym( handle, factory_name.c_str() );
835 #else
836   Component_factory = (FACTORY_FUNCTION_2)GetProcAddress( (HINSTANCE)handle, factory_name.c_str() );
837 #endif
838
839   if (!Component_factory)
840   {
841     INFOS("Can't resolve symbol: " + factory_name);
842 #ifndef WIN32
843     INFOS("dlerror() result is : " << dlerror());
844 #endif
845     return Engines::EngineComponent::_nil() ;
846   }
847
848   // --- create instance
849   Engines::EngineComponent_var iobject = Engines::EngineComponent::_nil() ;
850   try
851   {
852     int numInstance = _numInstance;
853     char aNumI[12];
854     sprintf( aNumI , "%d" , numInstance );
855     std::string instanceName = aGenRegisterName + "_inst_" + aNumI;
856     std::string component_registerName =
857       _containerName + "/" + instanceName;
858
859     // --- Instantiate required CORBA object
860
861     PortableServer::ObjectId *id; //not owner, do not delete (nore use var)
862     id = (Component_factory) ( _orb, _poa, _id, instanceName.c_str(),
863                                aGenRegisterName.c_str() );
864     if (id == NULL)
865     {
866       INFOS("Factory function returns NULL !");
867       return iobject._retn();
868     }
869
870     // --- get reference from id
871     CORBA::Object_var obj = _poa->id_to_reference(*id);
872     iobject = Engines::EngineComponent::_narrow(obj);
873
874     _listInstances_map[instanceName] = iobject;
875     _cntInstances_map[aGenRegisterName] += 1;
876
877     // --- register the engine under the name
878     //     containerName(.dir)/instanceName(.object)
879     _NS->Register(iobject , component_registerName.c_str());
880     MESSAGE( component_registerName.c_str() << " bound" );
881   }
882   catch (...)
883   {
884     INFOS( "Container_i::createInstance exception caught" );
885   }
886   return iobject._retn();
887 }
888
889 void
890 Engines_Parallel_Container_i::create_paco_component_node_instance(const char* componentName,
891                                                                   const char* proxy_containerName)
892 {
893   // Init de la mĂ©thode
894   char * proxy_ior;
895   Engines::EngineComponent_PaCO_var work_node;
896   std::string aCompName = componentName;
897   std::string _proxy_containerName = proxy_containerName;
898
899 #ifndef WIN32
900 #ifdef __APPLE__
901   string impl_name = string ("lib") + aCompName + string("Engine.dylib");
902 #else
903   string impl_name = string ("lib") + aCompName +string("Engine.so");
904 #endif
905 #else
906   string impl_name = aCompName +string("Engine.dll");
907 #endif
908   void* handle = _library_map[impl_name];
909   _numInstanceMutex.lock() ; // lock on the instance number
910   _numInstance++ ;
911   int numInstance = _numInstance ;
912   _numInstanceMutex.unlock() ;
913   char aNumI[12];
914   sprintf( aNumI , "%d" , numInstance ) ;
915   string instanceName = aCompName + "_inst_" + aNumI ;
916
917   // Step 1 : Get proxy !
918   string component_registerName = _proxy_containerName + "/" + instanceName;
919   CORBA::Object_var temp = _NS->Resolve(component_registerName.c_str());
920   Engines::EngineComponent_var obj_proxy = Engines::EngineComponent::_narrow(temp);
921   if (CORBA::is_nil(obj_proxy))
922   {
923     INFOS("Proxy reference from NamingService is nil !");
924     INFOS("Proxy name was : " << component_registerName);
925     SALOME::ExceptionStruct es;
926     es.type = SALOME::INTERNAL_ERROR;
927     es.text = "Proxy reference from NamingService is nil !";
928     throw SALOME::SALOME_Exception(es);
929   }
930   proxy_ior = _orb->object_to_string(obj_proxy);
931
932   // Get factory
933   string factory_name = aCompName + string("Engine_factory");
934   FACTORY_FUNCTION Component_factory = (FACTORY_FUNCTION) dlsym(handle, factory_name.c_str());
935   if (!Component_factory)
936   {
937     INFOS("Can't resolve symbol : " + factory_name);
938 #ifndef WIN32
939     INFOS("dlerror() result is : " << dlerror());
940 #endif
941     std::string ex_text = "Can't resolve symbol : " + factory_name;
942     SALOME::ExceptionStruct es;
943     es.type = SALOME::INTERNAL_ERROR;
944     es.text = CORBA::string_dup(ex_text.c_str());
945     throw SALOME::SALOME_Exception(es);
946   }
947
948   try
949   {
950     char aNumI2[12];
951     sprintf(aNumI2 , "%d" , getMyRank()) ;
952     std::string instanceName = aCompName + "_inst_" + aNumI + "_work_node_" + aNumI2;
953     std::string component_registerName = _containerName + "/" + instanceName;
954
955     // --- Instantiate work node
956     PortableServer::ObjectId *id ; //not owner, do not delete (nore use var)
957     id = (Component_factory) (_orb, proxy_ior, getMyRank(), _poa, _id, instanceName.c_str(), componentName);
958     CORBA::string_free(proxy_ior);
959
960     // --- get reference from id
961     CORBA::Object_var obj = _poa->id_to_reference(*id);
962     work_node = Engines::EngineComponent_PaCO::_narrow(obj) ;
963     if (CORBA::is_nil(work_node))
964     {
965       INFOS("work_node reference from factory is nil !");
966       SALOME::ExceptionStruct es;
967       es.type = SALOME::INTERNAL_ERROR;
968       es.text = "work_node reference from factory is nil !";
969       throw SALOME::SALOME_Exception(es);
970     }
971     work_node->deploy();
972     _NS->Register(work_node, component_registerName.c_str());
973     _par_obj_inst_map[instanceName] = id;
974     MESSAGE(component_registerName.c_str() << " bound" );
975   }
976   catch (...)
977   {
978     INFOS("Container_i::create_paco_component_node_instance exception caught");
979     SALOME::ExceptionStruct es;
980     es.type = SALOME::INTERNAL_ERROR;
981     es.text = "Container_i::create_paco_component_node_instance exception caught";
982     throw SALOME::SALOME_Exception(es);
983   }
984 }
985
986 //=============================================================================
987 //! Decrement component instance reference count
988 /*! 
989  *
990  */
991 //=============================================================================
992
993 void Engines_Parallel_Container_i::decInstanceCnt(std::string genericRegisterName)
994 {
995   if(_cntInstances_map.count(genericRegisterName) !=0 )
996   {
997     std::string aGenRegisterName =genericRegisterName;
998     MESSAGE("Engines_Parallel_Container_i::decInstanceCnt " << aGenRegisterName);
999     ASSERT(_cntInstances_map[aGenRegisterName] > 0); 
1000     _numInstanceMutex.lock(); // lock to be alone
1001     // (see finalize_removal, load_component_Library)
1002     _cntInstances_map[aGenRegisterName] -= 1;
1003     SCRUTE(_cntInstances_map[aGenRegisterName]);
1004     if (_cntInstances_map[aGenRegisterName] == 0)
1005     {
1006       std::string impl_name =
1007         Engines_Component_i::GetDynLibraryName(aGenRegisterName.c_str());
1008       SCRUTE(impl_name);
1009       void* handle = _library_map[impl_name];
1010       ASSERT(handle);
1011       _toRemove_map[impl_name] = handle;
1012     }
1013     _numInstanceMutex.unlock();
1014   }
1015 }
1016
1017 //=============================================================================
1018 //! Indicate if container is a python one
1019 /*! 
1020  *  Retrieves only with container naming convention if it is a python container
1021  */
1022 //=============================================================================
1023
1024 bool Engines_Parallel_Container_i::isPythonContainer(const char* ContainerName)
1025 {
1026   bool ret=false;
1027   return ret;
1028 }
1029
1030
1031 // Cette mĂ©thode permet de tenir Ă  jour le compteur des
1032 // instances pour le container parallèle.
1033 // En effet losrque l'on charge un composant sĂ©quentielle seul
1034 // le compteur du noeud 0 est augmentĂ©, il faut donc tenir les autres 
1035 // noeuds Ă  jour.
1036 void
1037 Engines_Parallel_Container_i::updateInstanceNumber()
1038 {
1039   if (getMyRank() != 0)
1040   {
1041     _numInstanceMutex.lock();
1042     _numInstance++;
1043     _numInstanceMutex.unlock();
1044   }
1045 }
1046
1047 /*! \brief copy a file from a remote host (container) to the local host
1048  * \param container the remote container
1049  * \param remoteFile the file to copy locally from the remote host into localFile
1050  * \param localFile the local file
1051  */
1052 void 
1053 Engines_Parallel_Container_i::copyFile(Engines::Container_ptr container, const char* remoteFile, const char* localFile)
1054 {
1055   Engines::fileTransfer_var fileTransfer = container->getFileTransfer();
1056
1057   FILE* fp;
1058   if ((fp = fopen(localFile,"wb")) == NULL)
1059     {
1060       INFOS("file " << localFile << " cannot be open for writing");
1061       return;
1062     }
1063
1064   CORBA::Long fileId = fileTransfer->open(remoteFile);
1065   if (fileId > 0)
1066     {
1067       Engines::fileBlock* aBlock;
1068       int toFollow = 1;
1069       int ctr=0;
1070       while (toFollow)
1071         {
1072           ctr++;
1073           SCRUTE(ctr);
1074           aBlock = fileTransfer->getBlock(fileId);
1075           toFollow = aBlock->length();
1076           SCRUTE(toFollow);
1077           CORBA::Octet *buf = aBlock->get_buffer();
1078           fwrite(buf, sizeof(CORBA::Octet), toFollow, fp);
1079           delete aBlock;
1080         }
1081       fclose(fp);
1082       MESSAGE("end of transfer");
1083       fileTransfer->close(fileId);
1084     }
1085   else
1086     {
1087       INFOS("open reference file for copy impossible");
1088     }
1089 }
1090
1091 /*! \brief create a PyNode object to execute remote python code
1092  * \param nodeName the name of the node
1093  * \param code the python code to load
1094  * \return the PyNode
1095  */
1096 Engines::PyNode_ptr 
1097 Engines_Parallel_Container_i::createPyNode(const char* nodeName, const char* code)
1098 {
1099   INFOS("Python component not yet implemented");
1100   Engines::PyNode_var node= Engines::PyNode::_nil();
1101   return node._retn();
1102 }
1103
1104 Engines::PyNode_ptr Engines_Parallel_Container_i::getDefaultPyNode(const char *nodeName)
1105 {
1106   INFOS("Python component not yet implemented");
1107   return Engines::PyNode::_nil();
1108 }
1109
1110 Engines::PyScriptNode_ptr 
1111 Engines_Parallel_Container_i::createPyScriptNode(const char* nodeName, const char* cod)
1112 {
1113   INFOS("Python script node not yet implemented");
1114   Engines::PyScriptNode_var node= Engines::PyScriptNode::_nil();
1115   return node._retn();
1116 }
1117
1118 Engines::PyScriptNode_ptr Engines_Parallel_Container_i::getDefaultPyScriptNode(const char *nodeName)
1119 {
1120   INFOS("Python script node not yet implemented");
1121   return Engines::PyScriptNode::_nil();
1122 }
1123
1124 //=============================================================================
1125 /*! 
1126  *  
1127  */
1128 //=============================================================================
1129
1130 void ActSigIntHandler()
1131 {
1132 #ifndef WIN32
1133   struct sigaction SigIntAct ;
1134   SigIntAct.sa_sigaction = &SigIntHandler ;
1135   SigIntAct.sa_flags = SA_SIGINFO ;
1136 #endif
1137
1138   // DEBUG 03.02.2005 : the first parameter of sigaction is not a mask of signals
1139   // (SIGINT | SIGUSR1) :
1140   // it must be only one signal ===> one call for SIGINT 
1141   // and an other one for SIGUSR1
1142
1143 #ifndef WIN32
1144   if ( sigaction( SIGINT , &SigIntAct, NULL ) ) {
1145     perror("SALOME_Container main ") ;
1146     exit(0) ;
1147   }
1148   if ( sigaction( SIGUSR1 , &SigIntAct, NULL ) ) {
1149     perror("SALOME_Container main ") ;
1150     exit(0) ;
1151   }
1152   if ( sigaction( SIGUSR2 , &SigIntAct, NULL ) )
1153   {
1154     perror("SALOME_Container main ") ;
1155     exit(0) ;
1156   }
1157
1158   //PAL9042 JR : during the execution of a Signal Handler (and of methods called through Signal Handlers)
1159   //             use of streams (and so on) should never be used because :
1160   //             streams of C++ are naturally thread-safe and use pthread_mutex_lock ===>
1161   //             A stream operation may be interrupted by a signal and if the Handler use stream we
1162   //             may have a "Dead-Lock" ===HangUp
1163   //==INFOS is commented
1164   //  INFOS(pthread_self() << "SigIntHandler activated") ;
1165 #else  
1166   signal( SIGINT, SigIntHandler );
1167   signal( SIGUSR1, SigIntHandler );
1168 #endif
1169
1170 }
1171
1172 void SetCpuUsed();
1173 void CallCancelThread();
1174
1175 #ifndef WIN32
1176 void SigIntHandler(int what , siginfo_t * siginfo ,
1177                    void * toto ) {
1178   //PAL9042 JR : during the execution of a Signal Handler (and of methods called through Signal Handlers)
1179   //             use of streams (and so on) should never be used because :
1180   //             streams of C++ are naturally thread-safe and use pthread_mutex_lock ===>
1181   //             A stream operation may be interrupted by a signal and if the Handler use stream we
1182   //             may have a "Dead-Lock" ===HangUp
1183   //==MESSAGE is commented
1184   //  MESSAGE(pthread_self() << "SigIntHandler what     " << what << endl
1185   //          << "              si_signo " << siginfo->si_signo << endl
1186   //          << "              si_code  " << siginfo->si_code << endl
1187   //          << "              si_pid   " << siginfo->si_pid) ;
1188   if ( _Sleeping ) {
1189     _Sleeping = false ;
1190     //     MESSAGE("SigIntHandler END sleeping.") ;
1191     return ;
1192   }
1193   else {
1194     ActSigIntHandler() ;
1195     if ( siginfo->si_signo == SIGUSR1 ) {
1196       SetCpuUsed() ;
1197     }
1198     else if ( siginfo->si_signo == SIGUSR2 )
1199     {
1200       CallCancelThread() ;
1201     }
1202     else {
1203       _Sleeping = true ;
1204       //      MESSAGE("SigIntHandler BEGIN sleeping.") ;
1205       int count = 0 ;
1206       while( _Sleeping ) {
1207         sleep( 1 ) ;
1208         count += 1 ;
1209       }
1210       //      MESSAGE("SigIntHandler LEAVE sleeping after " << count << " s.") ;
1211     }
1212     return ;
1213   }
1214 }
1215 #else // Case WIN32
1216 void SigIntHandler( int what ) {
1217   MESSAGE( pthread_self() << "SigIntHandler what     " << what << endl );
1218   if ( _Sleeping ) {
1219     _Sleeping = false ;
1220     MESSAGE("SigIntHandler END sleeping.") ;
1221     return ;
1222   }
1223   else {
1224     ActSigIntHandler() ;
1225     if ( what == SIGUSR1 ) {
1226       SetCpuUsed() ;
1227     }
1228     else {
1229       _Sleeping = true ;
1230       MESSAGE("SigIntHandler BEGIN sleeping.") ;
1231       int count = 0 ;
1232       while( _Sleeping ) {
1233         Sleep( 1000 ) ;
1234         count += 1 ;
1235       }
1236       MESSAGE("SigIntHandler LEAVE sleeping after " << count << " s.") ;
1237     }
1238     return ;
1239   }
1240 }
1241 #endif