Salome HOME
RNV: replace 'and' by '&&'
[modules/kernel.git] / src / ParallelContainer / SALOME_ParallelContainer_i.cxx
1 // Copyright (C) 2007-2016  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, 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  *  Construtor
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 successfull 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= PyString_AsString(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  *  \param studyId         0 for multiStudy instance, 
384  *                         study Id (>0) otherwise
385  *  \return a loaded component
386  */
387 //=============================================================================
388 Engines::EngineComponent_ptr
389 Engines_Parallel_Container_i::create_component_instance(const char*genericRegisterName,
390                                                         CORBA::Long studyId)
391 {
392   Engines::FieldsDict_var env = new Engines::FieldsDict;
393   char* reason;
394   Engines::EngineComponent_ptr compo = create_component_instance_env(genericRegisterName,studyId,env, reason);
395   CORBA::string_free(reason);
396   return compo;
397 }
398
399 //=============================================================================
400 //! Create a new component instance
401 /*! 
402  *  CORBA method: Creates a new servant instance of a component.
403  *  The servant registers itself to naming service and Registry.
404  *  \param genericRegisterName  Name of the component instance to register
405  *                         in Registry & Name Service (without _inst_n suffix)
406  *  \param studyId         0 for multiStudy instance, 
407  *                         study Id (>0) otherwise
408  *  \param env             dict of environment variables
409  *  \return a loaded component
410  */
411 //=============================================================================
412
413 Engines::EngineComponent_ptr
414 Engines_Parallel_Container_i::create_component_instance_env(const char*genericRegisterName,
415                                                             CORBA::Long studyId,
416                                                             const Engines::FieldsDict& env,
417                                                             CORBA::String_out reason)
418 {
419   MESSAGE("Begin of create_component_instance in node : " << getMyRank());
420   reason=CORBA::string_dup("");
421
422   if (studyId < 0)
423   {
424     INFOS("studyId must be > 0 for mono study instance, =0 for multiStudy");
425     return Engines::EngineComponent::_nil() ;
426   }
427
428   std::string aCompName = genericRegisterName;
429 #ifndef WIN32
430 #ifdef __APPLE__
431   std::string impl_name = string ("lib") + aCompName + string("Engine.dylib");
432 #else
433   std::string impl_name = string ("lib") + aCompName +string("Engine.so");
434 #endif
435 #else
436   std::string impl_name = aCompName +string("Engine.dll");
437 #endif
438
439   _numInstanceMutex.lock();
440   _numInstance++;
441
442   // Test if the component lib is loaded
443   std::string type_of_lib("Not Loaded");
444   void* handle = _library_map[impl_name];
445   if (handle)
446     type_of_lib = "cpp";
447   if (_library_map.count(aCompName) != 0 && !handle)
448     type_of_lib = "python";
449   
450   if (type_of_lib == "Not Loaded")
451   {
452     std::cerr << "Component library is not loaded or imported ! lib was : " << aCompName << std::endl;
453     _numInstanceMutex.unlock();
454     return Engines::EngineComponent::_nil();
455   }
456
457   Engines::EngineComponent_var iobject = Engines::EngineComponent::_nil();
458   if (type_of_lib == "cpp")
459     iobject = createCPPInstance(aCompName, handle, studyId);
460   else
461     iobject = createPythonInstance(aCompName, studyId);
462
463   _numInstanceMutex.unlock();
464   return iobject._retn();
465 }
466
467 //=============================================================================
468 //! Find an existing (in the container) component instance
469 /*! 
470  *  CORBA method: Finds a servant instance of a component
471  *  \param registeredName  Name of the component in Registry or Name Service,
472  *                         without instance suffix number
473  *  \param studyId         0 if instance is not associated to a study, 
474  *                         >0 otherwise (== study id)
475  *  \return the first instance found with same studyId
476  */
477 //=============================================================================
478
479 Engines::EngineComponent_ptr Engines_Parallel_Container_i::find_component_instance( const char* registeredName,
480                                                                               CORBA::Long studyId)
481 {
482   Engines::EngineComponent_var anEngine = Engines::EngineComponent::_nil();
483   std::map<std::string,Engines::EngineComponent_var>::iterator itm =_listInstances_map.begin();
484   while (itm != _listInstances_map.end())
485   {
486     std::string instance = (*itm).first;
487     SCRUTE(instance);
488     if (instance.find(registeredName) == 0)
489     {
490       anEngine = (*itm).second;
491       if (studyId == anEngine->getStudyId())
492       {
493         return anEngine._retn();
494       }
495     }
496     itm++;
497   }
498   return anEngine._retn();  
499 }
500
501 char* Engines_Parallel_Container_i::create_python_service_instance(const char* CompName,
502                                                                    CORBA::String_out reason)
503 {
504   // not implemented
505   reason=CORBA::string_dup("");
506   return CORBA::string_dup("");
507 }
508
509 //=============================================================================
510 //! Find or create a new component instance
511 /*! 
512  *  CORBA method: find or create an instance of the component (servant),
513  *  load a new component class (dynamic library) if required,
514  *  ---- FOR COMPATIBILITY WITH 2.2 ---- 
515  *  ---- USE ONLY FOR MULTISTUDY INSTANCES ! --------
516  *  The servant registers itself to naming service and Registry.
517  *  \param genericRegisterName  Name of the component to register
518  *                              in Registry & Name Service
519  *  \param componentName       Name of the constructed library of the component
520  *  \return a loaded component
521  */
522 //=============================================================================
523
524 Engines::EngineComponent_ptr Engines_Parallel_Container_i::load_impl( const char* genericRegisterName,
525                                                                 const char* componentName )
526 {
527   Engines::EngineComponent_var iobject = Engines::EngineComponent::_nil();
528   char* reason;
529   if (load_component_Library(genericRegisterName,reason))
530     iobject = find_or_create_instance(genericRegisterName);
531   CORBA::string_free(reason);
532   return iobject._retn();
533 }
534
535
536 //=============================================================================
537 //! Remove the component instance from container
538 /*! 
539  *  CORBA method: Stops the component servant, and deletes all related objects
540  *  \param component_i     Component to be removed
541  */
542 //=============================================================================
543
544 void Engines_Parallel_Container_i::remove_impl(Engines::EngineComponent_ptr component_i)
545 {
546   ASSERT(!CORBA::is_nil(component_i));
547   std::string instanceName = component_i->instanceName();
548   _numInstanceMutex.lock() ; // lock to be alone (stl container write)
549   // Test if the component is in this container
550   std::map<std::string, Engines::EngineComponent_var>::iterator itm;
551   itm = _listInstances_map.find(instanceName);
552   if (itm != _listInstances_map.end())
553   {
554     MESSAGE("Unloading component " << instanceName);
555     _listInstances_map.erase(instanceName);
556     component_i->destroy() ;
557     _NS->Destroy_Name(instanceName.c_str());
558   }
559   else
560     std::cerr << "WARNING !!!! component instance was not in this container !!!" << std::endl;
561   _numInstanceMutex.unlock() ;
562 }
563
564 //=============================================================================
565 //! Unload component libraries from the container
566 /*! 
567  *  CORBA method: Discharges unused libraries from the container.
568  */
569 //=============================================================================
570
571 void Engines_Parallel_Container_i::finalize_removal()
572 {
573   MESSAGE("Finalize removal : dlclose");
574   MESSAGE("WARNING FINALIZE DOES CURRENTLY NOTHING !!!");
575
576   // (see decInstanceCnt, load_component_Library)
577   //std::map<std::string, void *>::iterator ith;
578   //for (ith = _toRemove_map.begin(); ith != _toRemove_map.end(); ith++)
579   //{
580   //  void *handle = (*ith).second;
581   //  std::string impl_name= (*ith).first;
582   //  if (handle)
583   //  {
584   //    SCRUTE(handle);
585   //    SCRUTE(impl_name);
586   //    dlclose(handle);                // SALOME unstable after ...
587   //    _library_map.erase(impl_name);
588   //  }
589   //}
590
591   _numInstanceMutex.lock(); // lock to be alone
592   _toRemove_map.clear();
593   _numInstanceMutex.unlock();
594 }
595
596 //=============================================================================
597 //! Kill the container
598 /*! 
599  *  CORBA method: Kill the container process with exit(0).
600  *  To remove :  never returns !
601  */
602 //=============================================================================
603
604 bool Engines_Parallel_Container_i::Kill_impl()
605 {
606   MESSAGE("Engines_Parallel_Container_i::Kill() my pid is "<< _pid 
607           << " my containerName is " << _containerName.c_str() 
608           << " my machineName is " << _hostname.c_str());
609   INFOS("===============================================================");
610   INFOS("= REMOVE calls to Kill_impl in C++ container                  =");
611   INFOS("===============================================================");
612   //exit( 0 ) ;
613   ASSERT(0);
614   return false;
615 }
616
617 //=============================================================================
618 //! Get or create a file reference object associated to a local file (to transfer it)
619 /*! 
620  *  CORBA method: get or create a fileRef object associated to a local file
621  *  (a file on the computer on which runs the container server), which stores
622  *  a list of (machine, localFileName) corresponding to copies already done.
623  * 
624  *  \param  origFileName absolute path for a local file to copy on other
625  *          computers
626  *  \return a fileRef object associated to the file.
627  */
628 //=============================================================================
629
630 Engines::fileRef_ptr
631 Engines_Parallel_Container_i::createFileRef(const char* origFileName)
632 {
633   std::string origName(origFileName);
634   Engines::fileRef_var theFileRef = Engines::fileRef::_nil();
635
636   if (origName[0] != '/')
637   {
638     INFOS("path of file to copy must be an absolute path begining with '/'");
639     return Engines::fileRef::_nil();
640   }
641
642   if (CORBA::is_nil(_fileRef_map[origName]))
643   {
644     CORBA::Object_var obj=_poa->id_to_reference(*_id);
645     Engines::Container_var pCont = Engines::Container::_narrow(obj);
646     fileRef_i* aFileRef = new fileRef_i(pCont, origFileName);
647     theFileRef = Engines::fileRef::_narrow(aFileRef->_this());
648     _numInstanceMutex.lock() ; // lock to be alone (stl container write)
649     _fileRef_map[origName] = theFileRef;
650     _numInstanceMutex.unlock() ;
651   }
652
653   theFileRef =  Engines::fileRef::_duplicate(_fileRef_map[origName]);
654   ASSERT(! CORBA::is_nil(theFileRef));
655   return theFileRef._retn();
656 }
657
658 //=============================================================================
659 /*! 
660  *  CORBA method:
661  *  \return a reference to the fileTransfer object
662  */
663 //=============================================================================
664
665 Engines::fileTransfer_ptr
666 Engines_Parallel_Container_i::getFileTransfer()
667 {
668   Engines::fileTransfer_var aFileTransfer
669     = Engines::fileTransfer::_duplicate(_fileTransfer);
670   return aFileTransfer._retn();
671 }
672
673
674 Engines::Salome_file_ptr 
675 Engines_Parallel_Container_i::createSalome_file(const char* origFileName) 
676 {
677   string origName(origFileName);
678   if (CORBA::is_nil(_Salome_file_map[origName]))
679   {
680     Salome_file_i* aSalome_file = new Salome_file_i();
681     try 
682     {
683       aSalome_file->setLocalFile(origFileName);
684       aSalome_file->recvFiles();
685     }
686     catch (const SALOME::SALOME_Exception& e)
687     {
688       return Engines::Salome_file::_nil();
689     }
690
691     Engines::Salome_file_var theSalome_file = Engines::Salome_file::_nil();
692     theSalome_file = Engines::Salome_file::_narrow(aSalome_file->_this());
693     _numInstanceMutex.lock() ; // lock to be alone (stl container write)
694     _Salome_file_map[origName] = theSalome_file;
695     _numInstanceMutex.unlock() ;
696   }
697
698   Engines::Salome_file_ptr theSalome_file =  
699     Engines::Salome_file::_duplicate(_Salome_file_map[origName]);
700   ASSERT(!CORBA::is_nil(theSalome_file));
701   return theSalome_file;
702 }
703
704
705 //=============================================================================
706 //! Finds an already existing component instance or create a new instance
707 /*! 
708  *  C++ method: Finds an already existing servant instance of a component, or
709  *              create an instance.
710  *  ---- USE ONLY FOR MULTISTUDY INSTANCES ! --------
711  *  \param genericRegisterName    Name of the component instance to register
712  *                                in Registry & Name Service,
713  *                                (without _inst_n suffix, like "COMPONENT")
714  *  \return a loaded component
715  * 
716  *  example with names:
717  *  aGenRegisterName = COMPONENT (= first argument)
718  *  impl_name = libCOMPONENTEngine.so (= second argument)
719  *  _containerName = /Containers/cli76ce/FactoryServer
720  *  factoryName = COMPONENTEngine_factory
721  *  component_registerBase = /Containers/cli76ce/FactoryServer/COMPONENT
722  *
723  *  instanceName = COMPONENT_inst_1
724  *  component_registerName = /Containers/cli76ce/FactoryServer/COMPONENT_inst_1
725  */
726 //=============================================================================
727
728 Engines::EngineComponent_ptr
729 Engines_Parallel_Container_i::find_or_create_instance(std::string genericRegisterName)
730 {
731   Engines::EngineComponent_var iobject = Engines::EngineComponent::_nil();
732   try
733   {
734     std::string aGenRegisterName = genericRegisterName;
735     // --- find a registered instance in naming service, or create
736     std::string component_registerBase = _containerName + "/" + aGenRegisterName;
737     CORBA::Object_var obj = _NS->ResolveFirst(component_registerBase.c_str());
738     if (CORBA::is_nil( obj ))
739     {
740       iobject = create_component_instance(genericRegisterName.c_str(), 
741                                           0); // force multiStudy instance here !
742     }
743     else
744     { 
745       iobject = Engines::EngineComponent::_narrow(obj) ;
746       Engines_Component_i *servant = dynamic_cast<Engines_Component_i*>(_poa->reference_to_servant(iobject));
747       ASSERT(servant)
748       int studyId = servant->getStudyId();
749       ASSERT (studyId >= 0);
750       if (studyId != 0)  // monoStudy instance: NOK
751       {
752         iobject = Engines::EngineComponent::_nil();
753         INFOS("load_impl & find_component_instance methods "
754               << "NOT SUITABLE for mono study components");
755       }
756     }
757   }
758   catch (...)
759   {
760     INFOS( "Container_i::load_impl catched" ) ;
761   }
762   return iobject._retn();
763 }
764
765 //=============================================================================
766 //! Create a new Python component instance 
767 /*! 
768  *  C++ method: create a servant instance of a component.
769  *  \param genericRegisterName    Name of the component instance to register
770  *                                in Registry & Name Service,
771  *                                (without _inst_n suffix, like "COMPONENT")
772  *  \param handle                 loaded library handle
773  *  \param studyId                0 for multiStudy instance, 
774  *                                study Id (>0) otherwise
775  *  \return a loaded component
776  * 
777  *  example with names:
778  *  aGenRegisterName = COMPONENT (= first argument)
779  *  _containerName = /Containers/cli76ce/FactoryServer
780  *  factoryName = COMPONENTEngine_factory
781  *  component_registerBase = /Containers/cli76ce/FactoryServer/COMPONENT
782  *  instanceName = COMPONENT_inst_1
783  *  component_registerName = /Containers/cli76ce/FactoryServer/COMPONENT_inst_1
784  */
785 //=============================================================================
786 Engines::EngineComponent_ptr
787 Engines_Parallel_Container_i::createPythonInstance(std::string genericRegisterName, int studyId)
788 {
789
790   Engines::EngineComponent_var iobject = Engines::EngineComponent::_nil();
791
792   int numInstance = _numInstance;
793   char aNumI[12];
794   sprintf( aNumI , "%d" , numInstance ) ;
795   std::string instanceName = genericRegisterName + "_inst_" + aNumI ;
796   std::string component_registerName = _containerName + "/" + instanceName;
797
798   Py_ACQUIRE_NEW_THREAD;
799   PyObject *mainmod = PyImport_AddModule("__main__");
800   PyObject *globals = PyModule_GetDict(mainmod);
801   PyObject *pyCont = PyDict_GetItemString(globals, "pyCont");
802   PyObject *result = PyObject_CallMethod(pyCont,
803                                          (char*)"create_component_instance",
804                                          (char*)"ssl",
805                                          genericRegisterName.c_str(),
806                                          instanceName.c_str(),
807                                          studyId);
808   const char *ior;
809   const char *error;
810   PyArg_ParseTuple(result,"ss", &ior, &error);
811   string iors = ior;
812   Py_DECREF(result);
813   Py_RELEASE_NEW_THREAD;
814
815   if( iors!="" )
816   {
817     CORBA::Object_var obj = _orb->string_to_object(iors.c_str());
818     iobject = Engines::EngineComponent::_narrow(obj);
819     _listInstances_map[instanceName] = iobject;
820   }
821   else
822     std::cerr << "createPythonInstance ior is empty ! Error in creation" << std::endl;
823
824   return iobject._retn();
825 }
826
827 //=============================================================================
828 //! Create a new CPP component instance 
829 /*! 
830  *  C++ method: create a servant instance of a component.
831  *  \param genericRegisterName    Name of the component instance to register
832  *                                in Registry & Name Service,
833  *                                (without _inst_n suffix, like "COMPONENT")
834  *  \param handle                 loaded library handle
835  *  \param studyId                0 for multiStudy instance, 
836  *                                study Id (>0) otherwise
837  *  \return a loaded component
838  * 
839  *  example with names:
840  *  aGenRegisterName = COMPONENT (= first argument)
841  *  _containerName = /Containers/cli76ce/FactoryServer
842  *  factoryName = COMPONENTEngine_factory
843  *  component_registerBase = /Containers/cli76ce/FactoryServer/COMPONENT
844  *  instanceName = COMPONENT_inst_1
845  *  component_registerName = /Containers/cli76ce/FactoryServer/COMPONENT_inst_1
846  */
847 //=============================================================================
848 Engines::EngineComponent_ptr
849 Engines_Parallel_Container_i::createCPPInstance(std::string genericRegisterName,
850                                                 void *handle,
851                                                 int studyId)
852 {
853   MESSAGE("Entering Engines_Parallel_Container_i::createCPPInstance");
854
855   // --- find the factory
856
857   std::string aGenRegisterName = genericRegisterName;
858   std::string factory_name = aGenRegisterName + string("Engine_factory");
859
860   typedef  PortableServer::ObjectId * (*FACTORY_FUNCTION_2)
861     (CORBA::ORB_ptr,
862      PortableServer::POA_ptr, 
863      PortableServer::ObjectId *, 
864      const char *, 
865      const char *) ;
866
867   FACTORY_FUNCTION_2 Component_factory = NULL;
868 #ifndef WIN32
869   Component_factory = (FACTORY_FUNCTION_2)dlsym( handle, factory_name.c_str() );
870 #else
871   Component_factory = (FACTORY_FUNCTION_2)GetProcAddress( (HINSTANCE)handle, factory_name.c_str() );
872 #endif
873
874   if (!Component_factory)
875   {
876     INFOS("Can't resolve symbol: " + factory_name);
877 #ifndef WIN32
878     INFOS("dlerror() result is : " << dlerror());
879 #endif
880     return Engines::EngineComponent::_nil() ;
881   }
882
883   // --- create instance
884   Engines::EngineComponent_var iobject = Engines::EngineComponent::_nil() ;
885   try
886   {
887     int numInstance = _numInstance;
888     char aNumI[12];
889     sprintf( aNumI , "%d" , numInstance );
890     std::string instanceName = aGenRegisterName + "_inst_" + aNumI;
891     std::string component_registerName =
892       _containerName + "/" + instanceName;
893
894     // --- Instanciate required CORBA object
895
896     PortableServer::ObjectId *id; //not owner, do not delete (nore use var)
897     id = (Component_factory) ( _orb, _poa, _id, instanceName.c_str(),
898                                aGenRegisterName.c_str() );
899     if (id == NULL)
900     {
901       INFOS("Factory function returns NULL !");
902       return iobject._retn();
903     }
904
905     // --- get reference & servant from id
906     CORBA::Object_var obj = _poa->id_to_reference(*id);
907     iobject = Engines::EngineComponent::_narrow(obj);
908
909     Engines_Component_i *servant = 
910       dynamic_cast<Engines_Component_i*>(_poa->reference_to_servant(iobject));
911     ASSERT(servant);
912     servant->_remove_ref(); // compensate previous id_to_reference 
913     _listInstances_map[instanceName] = iobject;
914     _cntInstances_map[aGenRegisterName] += 1;
915 #if defined(_DEBUG_) || defined(_DEBUG)
916     bool ret_studyId = servant->setStudyId(studyId);
917     ASSERT(ret_studyId);
918 #else
919     servant->setStudyId(studyId);
920 #endif
921
922     // --- register the engine under the name
923     //     containerName(.dir)/instanceName(.object)
924     _NS->Register(iobject , component_registerName.c_str());
925     MESSAGE( component_registerName.c_str() << " bound" );
926   }
927   catch (...)
928   {
929     INFOS( "Container_i::createInstance exception catched" );
930   }
931   return iobject._retn();
932 }
933
934 void
935 Engines_Parallel_Container_i::create_paco_component_node_instance(const char* componentName,
936                                                                   const char* proxy_containerName,
937                                                                   CORBA::Long studyId)
938 {
939   // Init de la méthode
940   char * proxy_ior;
941   Engines::EngineComponent_PaCO_var work_node;
942   std::string aCompName = componentName;
943   std::string _proxy_containerName = proxy_containerName;
944
945 #ifndef WIN32
946 #ifdef __APPLE__
947   string impl_name = string ("lib") + aCompName + string("Engine.dylib");
948 #else
949   string impl_name = string ("lib") + aCompName +string("Engine.so");
950 #endif
951 #else
952   string impl_name = aCompName +string("Engine.dll");
953 #endif
954   void* handle = _library_map[impl_name];
955   _numInstanceMutex.lock() ; // lock on the instance number
956   _numInstance++ ;
957   int numInstance = _numInstance ;
958   _numInstanceMutex.unlock() ;
959   char aNumI[12];
960   sprintf( aNumI , "%d" , numInstance ) ;
961   string instanceName = aCompName + "_inst_" + aNumI ;
962
963   // Step 1 : Get proxy !
964   string component_registerName = _proxy_containerName + "/" + instanceName;
965   CORBA::Object_var temp = _NS->Resolve(component_registerName.c_str());
966   Engines::EngineComponent_var obj_proxy = Engines::EngineComponent::_narrow(temp);
967   if (CORBA::is_nil(obj_proxy))
968   {
969     INFOS("Proxy reference from NamingService is nil !");
970     INFOS("Proxy name was : " << component_registerName);
971     SALOME::ExceptionStruct es;
972     es.type = SALOME::INTERNAL_ERROR;
973     es.text = "Proxy reference from NamingService is nil !";
974     throw SALOME::SALOME_Exception(es);
975   }
976   proxy_ior = _orb->object_to_string(obj_proxy);
977
978   // Get factory
979   string factory_name = aCompName + string("Engine_factory");
980   FACTORY_FUNCTION Component_factory = (FACTORY_FUNCTION) dlsym(handle, factory_name.c_str());
981   if (!Component_factory)
982   {
983     INFOS("Can't resolve symbol : " + factory_name);
984 #ifndef WIN32
985     INFOS("dlerror() result is : " << dlerror());
986 #endif
987     std::string ex_text = "Can't resolve symbol : " + factory_name;
988     SALOME::ExceptionStruct es;
989     es.type = SALOME::INTERNAL_ERROR;
990     es.text = CORBA::string_dup(ex_text.c_str());
991     throw SALOME::SALOME_Exception(es);
992   }
993
994   try
995   {
996     char aNumI2[12];
997     sprintf(aNumI2 , "%d" , getMyRank()) ;
998     std::string instanceName = aCompName + "_inst_" + aNumI + "_work_node_" + aNumI2;
999     std::string component_registerName = _containerName + "/" + instanceName;
1000
1001     // --- Instanciate work node
1002     PortableServer::ObjectId *id ; //not owner, do not delete (nore use var)
1003     id = (Component_factory) (_orb, proxy_ior, getMyRank(), _poa, _id, instanceName.c_str(), componentName);
1004     CORBA::string_free(proxy_ior);
1005
1006     // --- get reference & servant from id
1007     CORBA::Object_var obj = _poa->id_to_reference(*id);
1008     work_node = Engines::EngineComponent_PaCO::_narrow(obj) ;
1009     if (CORBA::is_nil(work_node))
1010     {
1011       INFOS("work_node reference from factory is nil !");
1012       SALOME::ExceptionStruct es;
1013       es.type = SALOME::INTERNAL_ERROR;
1014       es.text = "work_node reference from factory is nil !";
1015       throw SALOME::SALOME_Exception(es);
1016     }
1017     work_node->deploy();
1018     _NS->Register(work_node, component_registerName.c_str());
1019     _par_obj_inst_map[instanceName] = id;
1020     MESSAGE(component_registerName.c_str() << " bound" );
1021   }
1022   catch (...)
1023   {
1024     INFOS("Container_i::create_paco_component_node_instance exception catched");
1025     SALOME::ExceptionStruct es;
1026     es.type = SALOME::INTERNAL_ERROR;
1027     es.text = "Container_i::create_paco_component_node_instance exception catched";
1028     throw SALOME::SALOME_Exception(es);
1029   }
1030 }
1031
1032 //=============================================================================
1033 //! Decrement component instance reference count
1034 /*! 
1035  *
1036  */
1037 //=============================================================================
1038
1039 void Engines_Parallel_Container_i::decInstanceCnt(std::string genericRegisterName)
1040 {
1041   if(_cntInstances_map.count(genericRegisterName) !=0 )
1042   {
1043     std::string aGenRegisterName =genericRegisterName;
1044     MESSAGE("Engines_Parallel_Container_i::decInstanceCnt " << aGenRegisterName);
1045     ASSERT(_cntInstances_map[aGenRegisterName] > 0); 
1046     _numInstanceMutex.lock(); // lock to be alone
1047     // (see finalize_removal, load_component_Library)
1048     _cntInstances_map[aGenRegisterName] -= 1;
1049     SCRUTE(_cntInstances_map[aGenRegisterName]);
1050     if (_cntInstances_map[aGenRegisterName] == 0)
1051     {
1052       std::string impl_name =
1053         Engines_Component_i::GetDynLibraryName(aGenRegisterName.c_str());
1054       SCRUTE(impl_name);
1055       void* handle = _library_map[impl_name];
1056       ASSERT(handle);
1057       _toRemove_map[impl_name] = handle;
1058     }
1059     _numInstanceMutex.unlock();
1060   }
1061 }
1062
1063 //=============================================================================
1064 //! Indicate if container is a python one
1065 /*! 
1066  *  Retrieves only with container naming convention if it is a python container
1067  */
1068 //=============================================================================
1069
1070 bool Engines_Parallel_Container_i::isPythonContainer(const char* ContainerName)
1071 {
1072   bool ret=false;
1073   return ret;
1074 }
1075
1076
1077 // Cette méthode permet de tenir à jour le compteur des
1078 // instances pour le container parallèle.
1079 // En effet losrque l'on charge un composant séquentielle seul
1080 // le compteur du noeud 0 est augmenté, il faut donc tenir les autres 
1081 // noeuds à jour.
1082 void
1083 Engines_Parallel_Container_i::updateInstanceNumber()
1084 {
1085   if (getMyRank() != 0)
1086   {
1087     _numInstanceMutex.lock();
1088     _numInstance++;
1089     _numInstanceMutex.unlock();
1090   }
1091 }
1092
1093 /*! \brief copy a file from a remote host (container) to the local host
1094  * \param container the remote container
1095  * \param remoteFile the file to copy locally from the remote host into localFile
1096  * \param localFile the local file
1097  */
1098 void 
1099 Engines_Parallel_Container_i::copyFile(Engines::Container_ptr container, const char* remoteFile, const char* localFile)
1100 {
1101   Engines::fileTransfer_var fileTransfer = container->getFileTransfer();
1102
1103   FILE* fp;
1104   if ((fp = fopen(localFile,"wb")) == NULL)
1105     {
1106       INFOS("file " << localFile << " cannot be open for writing");
1107       return;
1108     }
1109
1110   CORBA::Long fileId = fileTransfer->open(remoteFile);
1111   if (fileId > 0)
1112     {
1113       Engines::fileBlock* aBlock;
1114       int toFollow = 1;
1115       int ctr=0;
1116       while (toFollow)
1117         {
1118           ctr++;
1119           SCRUTE(ctr);
1120           aBlock = fileTransfer->getBlock(fileId);
1121           toFollow = aBlock->length();
1122           SCRUTE(toFollow);
1123           CORBA::Octet *buf = aBlock->get_buffer();
1124           fwrite(buf, sizeof(CORBA::Octet), toFollow, fp);
1125           delete aBlock;
1126         }
1127       fclose(fp);
1128       MESSAGE("end of transfer");
1129       fileTransfer->close(fileId);
1130     }
1131   else
1132     {
1133       INFOS("open reference file for copy impossible");
1134     }
1135 }
1136
1137 /*! \brief create a PyNode object to execute remote python code
1138  * \param nodeName the name of the node
1139  * \param code the python code to load
1140  * \return the PyNode
1141  */
1142 Engines::PyNode_ptr 
1143 Engines_Parallel_Container_i::createPyNode(const char* nodeName, const char* code)
1144 {
1145   INFOS("Python component not yet implemented");
1146   Engines::PyNode_var node= Engines::PyNode::_nil();
1147   return node._retn();
1148 }
1149
1150 Engines::PyNode_ptr Engines_Parallel_Container_i::getDefaultPyNode(const char *nodeName)
1151 {
1152   INFOS("Python component not yet implemented");
1153   return Engines::PyNode::_nil();
1154 }
1155
1156 Engines::PyScriptNode_ptr 
1157 Engines_Parallel_Container_i::createPyScriptNode(const char* nodeName, const char* cod)
1158 {
1159   INFOS("Python script node not yet implemented");
1160   Engines::PyScriptNode_var node= Engines::PyScriptNode::_nil();
1161   return node._retn();
1162 }
1163
1164 Engines::PyScriptNode_ptr Engines_Parallel_Container_i::getDefaultPyScriptNode(const char *nodeName)
1165 {
1166   INFOS("Python script node not yet implemented");
1167   return Engines::PyScriptNode::_nil();
1168 }
1169
1170 //=============================================================================
1171 /*! 
1172  *  
1173  */
1174 //=============================================================================
1175
1176 void ActSigIntHandler()
1177 {
1178 #ifndef WIN32
1179   struct sigaction SigIntAct ;
1180   SigIntAct.sa_sigaction = &SigIntHandler ;
1181   SigIntAct.sa_flags = SA_SIGINFO ;
1182 #endif
1183
1184   // DEBUG 03.02.2005 : the first parameter of sigaction is not a mask of signals
1185   // (SIGINT | SIGUSR1) :
1186   // it must be only one signal ===> one call for SIGINT 
1187   // and an other one for SIGUSR1
1188
1189 #ifndef WIN32
1190   if ( sigaction( SIGINT , &SigIntAct, NULL ) ) {
1191     perror("SALOME_Container main ") ;
1192     exit(0) ;
1193   }
1194   if ( sigaction( SIGUSR1 , &SigIntAct, NULL ) ) {
1195     perror("SALOME_Container main ") ;
1196     exit(0) ;
1197   }
1198   if ( sigaction( SIGUSR2 , &SigIntAct, NULL ) )
1199   {
1200     perror("SALOME_Container main ") ;
1201     exit(0) ;
1202   }
1203
1204   //PAL9042 JR : during the execution of a Signal Handler (and of methods called through Signal Handlers)
1205   //             use of streams (and so on) should never be used because :
1206   //             streams of C++ are naturally thread-safe and use pthread_mutex_lock ===>
1207   //             A stream operation may be interrupted by a signal and if the Handler use stream we
1208   //             may have a "Dead-Lock" ===HangUp
1209   //==INFOS is commented
1210   //  INFOS(pthread_self() << "SigIntHandler activated") ;
1211 #else  
1212   signal( SIGINT, SigIntHandler );
1213   signal( SIGUSR1, SigIntHandler );
1214 #endif
1215
1216 }
1217
1218 void SetCpuUsed();
1219 void CallCancelThread();
1220
1221 #ifndef WIN32
1222 void SigIntHandler(int what , siginfo_t * siginfo ,
1223                    void * toto ) {
1224   //PAL9042 JR : during the execution of a Signal Handler (and of methods called through Signal Handlers)
1225   //             use of streams (and so on) should never be used because :
1226   //             streams of C++ are naturally thread-safe and use pthread_mutex_lock ===>
1227   //             A stream operation may be interrupted by a signal and if the Handler use stream we
1228   //             may have a "Dead-Lock" ===HangUp
1229   //==MESSAGE is commented
1230   //  MESSAGE(pthread_self() << "SigIntHandler what     " << what << endl
1231   //          << "              si_signo " << siginfo->si_signo << endl
1232   //          << "              si_code  " << siginfo->si_code << endl
1233   //          << "              si_pid   " << siginfo->si_pid) ;
1234   if ( _Sleeping ) {
1235     _Sleeping = false ;
1236     //     MESSAGE("SigIntHandler END sleeping.") ;
1237     return ;
1238   }
1239   else {
1240     ActSigIntHandler() ;
1241     if ( siginfo->si_signo == SIGUSR1 ) {
1242       SetCpuUsed() ;
1243     }
1244     else if ( siginfo->si_signo == SIGUSR2 )
1245     {
1246       CallCancelThread() ;
1247     }
1248     else {
1249       _Sleeping = true ;
1250       //      MESSAGE("SigIntHandler BEGIN sleeping.") ;
1251       int count = 0 ;
1252       while( _Sleeping ) {
1253         sleep( 1 ) ;
1254         count += 1 ;
1255       }
1256       //      MESSAGE("SigIntHandler LEAVE sleeping after " << count << " s.") ;
1257     }
1258     return ;
1259   }
1260 }
1261 #else // Case WIN32
1262 void SigIntHandler( int what ) {
1263   MESSAGE( pthread_self() << "SigIntHandler what     " << what << endl );
1264   if ( _Sleeping ) {
1265     _Sleeping = false ;
1266     MESSAGE("SigIntHandler END sleeping.") ;
1267     return ;
1268   }
1269   else {
1270     ActSigIntHandler() ;
1271     if ( what == SIGUSR1 ) {
1272       SetCpuUsed() ;
1273     }
1274     else {
1275       _Sleeping = true ;
1276       MESSAGE("SigIntHandler BEGIN sleeping.") ;
1277       int count = 0 ;
1278       while( _Sleeping ) {
1279         Sleep( 1000 ) ;
1280         count += 1 ;
1281       }
1282       MESSAGE("SigIntHandler LEAVE sleeping after " << count << " s.") ;
1283     }
1284     return ;
1285   }
1286 }
1287 #endif