1 // Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE
3 // Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
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.
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.
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
20 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
22 // SALOME Container : implementation of container and engine for Kernel
23 // File : Container_i.cxx
24 // Author : Paul RASCLE, EDF - MARC TAJCHMAN, CEA
27 //#define private public
32 #include <sys/types.h>
45 #include "utilities.h"
46 #include <SALOMEconfig.h>
47 #include CORBA_SERVER_HEADER(SALOME_Component)
48 #include CORBA_SERVER_HEADER(SALOME_Exception)
49 #include <pthread.h> // must be before Python.h !
50 #include "SALOME_Container_i.hxx"
51 #include "SALOME_Component_i.hxx"
52 #include "SALOME_FileRef_i.hxx"
53 #include "SALOME_FileTransfer_i.hxx"
54 #include "Salome_file_i.hxx"
55 #include "SALOME_NamingService.hxx"
56 #include "Basics_Utils.hxx"
59 #include "Container_init_python.hxx"
63 bool _Sleeping = false ;
65 // // Needed by multi-threaded Python --- Supervision
69 extern "C" {void ActSigIntHandler() ; }
71 extern "C" {void SigIntHandler(int, siginfo_t *, void *) ; }
73 extern "C" {void SigIntHandler( int ) ; }
77 # define separator '\\'
79 # define separator '/'
83 map<std::string, int> Engines_Container_i::_cntInstances_map;
84 map<std::string, void *> Engines_Container_i::_library_map;
85 map<std::string, void *> Engines_Container_i::_toRemove_map;
86 omni_mutex Engines_Container_i::_numInstanceMutex ;
88 static PyObject* _pyCont;
90 int checkifexecutable(const std::string&);
91 int findpathof(std::string&, const std::string&);
93 /*! \class Engines_Container_i
94 * \brief C++ implementation of Engines::Container interface
99 //=============================================================================
101 * Default constructor, not for use
103 //=============================================================================
105 Engines_Container_i::Engines_Container_i () :
106 _numInstance(0),_id(0),_NS(0)
110 //=============================================================================
114 //=============================================================================
116 Engines_Container_i::Engines_Container_i (CORBA::ORB_ptr orb,
117 PortableServer::POA_ptr poa,
118 char *containerName ,
119 int argc , char* argv[],
121 bool isServantAloneInProcess
123 _numInstance(0),_isServantAloneInProcess(isServantAloneInProcess),_id(0),_NS(0)
125 _pid = (long)getpid();
133 string hostname = Kernel_Utils::GetHostname();
135 MESSAGE(hostname << " " << getpid() <<
136 " Engines_Container_i starting argc " <<
137 _argc << " Thread " << pthread_self() ) ;
139 MESSAGE(hostname << " " << _getpid() <<
140 " Engines_Container_i starting argc " << _argc<< " Thread " << pthread_self().p ) ;
146 MESSAGE(" argv" << i << " " << _argv[ i ]) ;
152 INFOS("SALOME_Container usage : SALOME_Container ServerName");
156 _isSupervContainer = false;
157 if (strcmp(argv[1],"SuperVisionContainer") == 0) _isSupervContainer = true;
159 if (_isSupervContainer)
165 _orb = CORBA::ORB::_duplicate(orb) ;
166 _poa = PortableServer::POA::_duplicate(poa) ;
168 // Pour les containers paralleles: il ne faut pas enregistrer et activer
169 // le container generique, mais le container specialise
173 _id = _poa->activate_object(this);
174 _NS = new SALOME_NamingService();
175 _NS->init_orb( _orb ) ;
176 CORBA::Object_var obj=_poa->id_to_reference(*_id);
177 Engines::Container_var pCont
178 = Engines::Container::_narrow(obj);
181 _containerName = _NS->BuildContainerNameForNS(containerName,
183 SCRUTE(_containerName);
184 _NS->Register(pCont, _containerName.c_str());
185 MESSAGE("Engines_Container_i::Engines_Container_i : Container name "
189 // import SALOME_Container
190 // pycont = SALOME_Container.SALOME_Container_i(containerIORStr)
192 CORBA::String_var sior = _orb->object_to_string(pCont);
193 string myCommand="pyCont = SALOME_Container.SALOME_Container_i('";
194 myCommand += _containerName + "','";
199 if (!_isSupervContainer)
201 PyGILState_STATE gstate = PyGILState_Ensure();
204 // mpv: this is temporary solution: there is a unregular crash if not
207 // first element is the path to Registry.dll, but it's wrong
208 PyRun_SimpleString("import sys\n");
209 PyRun_SimpleString("sys.path = sys.path[1:]\n");
211 PyRun_SimpleString("import SALOME_Container\n");
212 PyRun_SimpleString((char*)myCommand.c_str());
213 PyObject *mainmod = PyImport_AddModule("__main__");
214 PyObject *globals = PyModule_GetDict(mainmod);
215 _pyCont = PyDict_GetItemString(globals, "pyCont");
217 PyGILState_Release(gstate);
220 fileTransfer_i* aFileTransfer = new fileTransfer_i();
221 CORBA::Object_var obref=aFileTransfer->_this();
222 _fileTransfer = Engines::fileTransfer::_narrow(obref);
223 aFileTransfer->_remove_ref();
227 //=============================================================================
231 //=============================================================================
233 Engines_Container_i::~Engines_Container_i()
235 MESSAGE("Container_i::~Container_i()");
242 //=============================================================================
243 //! Get container name
245 * CORBA attribute: Container name (see constructor)
247 //=============================================================================
249 char* Engines_Container_i::name()
251 return CORBA::string_dup(_containerName.c_str()) ;
254 //=============================================================================
255 //! Get container working directory
257 * CORBA attribute: Container working directory
259 //=============================================================================
261 char* Engines_Container_i::workingdir()
265 return CORBA::string_dup(wd) ;
268 //=============================================================================
269 //! Get container log file name
271 * CORBA attribute: Container log file name
273 //=============================================================================
275 char* Engines_Container_i::logfilename()
277 return CORBA::string_dup(_logfilename.c_str()) ;
280 //! Set container log file name
281 void Engines_Container_i::logfilename(const char* name)
286 //=============================================================================
287 //! Get container host name
289 * CORBA method: Get the hostName of the Container (without domain extensions)
291 //=============================================================================
293 char* Engines_Container_i::getHostName()
295 string s = Kernel_Utils::GetHostname();
296 // MESSAGE("Engines_Container_i::getHostName " << s);
297 return CORBA::string_dup(s.c_str()) ;
300 //=============================================================================
301 //! Get container PID
303 * CORBA method: Get the PID (process identification) of the Container
305 //=============================================================================
307 CORBA::Long Engines_Container_i::getPID()
309 return (CORBA::Long)getpid();
312 //=============================================================================
313 //! Ping the servant to check it is still alive
315 * CORBA method: check if servant is still alive
317 //=============================================================================
319 void Engines_Container_i::ping()
321 MESSAGE("Engines_Container_i::ping() pid "<< getpid());
324 //=============================================================================
325 //! Shutdown the container
327 * CORBA method, oneway: Server shutdown.
328 * - Container name removed from naming service,
329 * - servant deactivation,
330 * - orb shutdown if no other servants in the process
332 //=============================================================================
334 void Engines_Container_i::Shutdown()
336 MESSAGE("Engines_Container_i::Shutdown()");
338 /* For each component contained in this container
339 * tell it to self-destroy
341 std::map<std::string, Engines::Component_var>::iterator itm;
342 for (itm = _listInstances_map.begin(); itm != _listInstances_map.end(); itm++)
346 itm->second->destroy();
348 catch(const CORBA::Exception& e)
350 // ignore this entry and continue
354 // ignore this entry and continue
357 _listInstances_map.clear();
359 _NS->Destroy_FullDirectory(_containerName.c_str());
360 _NS->Destroy_Name(_containerName.c_str());
361 if(_isServantAloneInProcess)
363 MESSAGE("Effective Shutdown of container Begins...");
364 if(!CORBA::is_nil(_orb))
369 /* int checkifexecutable(const char *filename)
371 * Return non-zero if the name is an executable file, and
372 * zero if it is not executable, or if it does not exist.
375 int checkifexecutable(const string& filename)
378 struct stat statinfo;
380 result = stat(filename.c_str(), &statinfo);
381 if (result < 0) return 0;
382 if (!S_ISREG(statinfo.st_mode)) return 0;
387 if (statinfo.st_uid == geteuid()) return statinfo.st_mode & S_IXUSR;
388 if (statinfo.st_gid == getegid()) return statinfo.st_mode & S_IXGRP;
389 return statinfo.st_mode & S_IXOTH;
394 /* int findpathof(char *pth, const char *exe)
396 * Find executable by searching the PATH environment variable.
398 * const char *exe - executable name to search for.
399 * char *pth - the path found is stored here, space
400 * needs to be available.
402 * If a path is found, returns non-zero, and the path is stored
403 * in pth. If exe is not found returns 0, with pth undefined.
406 int findpathof(string& pth, const string& exe)
408 string path( getenv("PATH") );
409 if ( path.size() == 0 )
429 while(!stop && !found)
431 int pos = path.find( path_spr, offset );
432 if (pos == string::npos)
435 pth = path.substr( offset, pos - offset );
436 if ( pth.size() > 0 )
438 if( pth[pth.size()-1] != dir_spr )
441 found = checkifexecutable(pth.c_str());
452 if (strchr(exe, separator) != NULL) {
454 if (realpath(exe, pth) == NULL) return 0;
456 return checkifexecutable(pth);
459 searchpath = getenv("PATH");
460 if (searchpath == NULL) return 0;
461 if (strlen(searchpath) <= 0) return 0;
463 string env_path(searchpath);
468 end = strchr(beg, ':');
471 strncpy(pth, beg, PATH_MAX);
474 strncpy(pth, beg, end - beg);
475 pth[end - beg] = '\0';
478 if (pth[len - 1] != '/') strncat(pth, "/", 1);
479 strncat(pth, exe, PATH_MAX - len);
480 found = checkifexecutable(pth);
481 if (!stop) beg = end + 1;
482 } while (!stop && !found);
489 //=============================================================================
490 //! load a new component class
492 * CORBA method: load a new component class (Python or C++ implementation)
493 * \param componentName like COMPONENT
494 * try to make a Python import of COMPONENT,
495 * then a lib open of libCOMPONENTEngine.so
496 * \return true if dlopen successfull or already done, false otherwise
498 //=============================================================================
501 Engines_Container_i::load_component_Library(const char* componentName)
504 string aCompName = componentName;
506 // --- try dlopen C++ component
509 string impl_name = string ("lib") + aCompName + string("Engine.so");
511 string impl_name = aCompName + string("Engine.dll");
515 _numInstanceMutex.lock(); // lock to be alone
516 // (see decInstanceCnt, finalize_removal))
517 if (_toRemove_map.count(impl_name) != 0) _toRemove_map.erase(impl_name);
518 if (_library_map.count(impl_name) != 0)
520 MESSAGE("Library " << impl_name << " already loaded");
521 _numInstanceMutex.unlock();
525 std::string retso="";
528 handle = dlopen( impl_name.c_str() , RTLD_LAZY ) ;
529 if ( !handle )retso=dlerror();
532 handle = LoadLibrary( impl_name.c_str() );
537 _library_map[impl_name] = handle;
538 _numInstanceMutex.unlock();
541 _numInstanceMutex.unlock();
543 // --- try import Python component
545 INFOS("try import Python component "<<componentName);
547 if (_isSupervContainer)
549 INFOS("Supervision Container does not support Python Component Engines");
552 if (_library_map.count(aCompName) != 0)
554 return true; // Python Component, already imported
558 PyGILState_STATE gstate = PyGILState_Ensure();
559 PyObject *result = PyObject_CallMethod(_pyCont,
560 (char*)"import_component",
561 (char*)"s",componentName);
563 retpy=PyString_AsString(result);
566 PyGILState_Release(gstate);
568 if (retpy=="") // import possible: Python component
570 _numInstanceMutex.lock() ; // lock to be alone (stl container write)
571 _library_map[aCompName] = (void *)_pyCont; // any non O value OK
572 _numInstanceMutex.unlock() ;
573 MESSAGE("import Python: "<<aCompName<<" OK");
577 // Try to find an executable
578 std::string executable=aCompName+".exe";
580 if (findpathof(path, executable))
583 INFOS( "Impossible to load component: " << componentName );
584 INFOS( "Can't load shared library: " << impl_name );
585 std::cerr << retso << std::endl;
586 INFOS( "Can't import Python module: " << componentName );
587 std::cerr << retpy << std::endl;
588 INFOS( "Can't execute program: " << executable );
592 //=============================================================================
593 //! Create a new component instance
595 * CORBA method: Creates a new servant instance of a component.
596 * The servant registers itself to naming service and Registry.
597 * \param genericRegisterName Name of the component instance to register
598 * in Registry & Name Service (without _inst_n suffix)
599 * \param studyId 0 for multiStudy instance,
600 * study Id (>0) otherwise
601 * \return a loaded component
603 //=============================================================================
605 Engines::Component_ptr
606 Engines_Container_i::create_component_instance(const char*genericRegisterName,
609 Engines::FieldsDict_var env = new Engines::FieldsDict;
610 return create_component_instance_env(genericRegisterName,studyId,env);
613 //=============================================================================
614 //! Create a new component instance with environment variables specified
616 * CORBA method: Creates a new servant instance of a component.
617 * The servant registers itself to naming service and Registry.
618 * \param genericRegisterName Name of the component instance to register
619 * in Registry & Name Service (without _inst_n suffix)
620 * \param studyId 0 for multiStudy instance,
621 * study Id (>0) otherwise
622 * \param env dict of env variables
623 * \return a loaded component
625 //=============================================================================
627 Engines::Component_ptr
628 Engines_Container_i::create_component_instance_env(const char*genericRegisterName,
629 CORBA::Long studyId,const Engines::FieldsDict& env)
633 INFOS("studyId must be > 0 for mono study instance, =0 for multiStudy");
634 return Engines::Component::_nil() ;
637 Engines::Component_var iobject = Engines::Component::_nil() ;
639 string aCompName = genericRegisterName;
640 if (_library_map.count(aCompName) != 0) // Python component
642 if (_isSupervContainer)
644 INFOS("Supervision Container does not support Python Component Engines");
645 return Engines::Component::_nil();
647 _numInstanceMutex.lock() ; // lock on the instance number
649 int numInstance = _numInstance ;
650 _numInstanceMutex.unlock() ;
653 sprintf( aNumI , "%d" , numInstance ) ;
654 string instanceName = aCompName + "_inst_" + aNumI ;
655 string component_registerName =
656 _containerName + "/" + instanceName;
658 PyGILState_STATE gstate = PyGILState_Ensure();
659 PyObject *result = PyObject_CallMethod(_pyCont,
660 (char*)"create_component_instance",
663 instanceName.c_str(),
665 string iors = PyString_AsString(result);
668 PyGILState_Release(gstate);
672 CORBA::Object_var obj = _orb->string_to_object(iors.c_str());
673 iobject = Engines::Component::_narrow( obj ) ;
674 _listInstances_map[instanceName] = iobject;
676 return iobject._retn();
682 string impl_name = string ("lib") + genericRegisterName +string("Engine.so");
684 string impl_name = genericRegisterName +string("Engine.dll");
686 if (_library_map.count(impl_name) != 0) // C++ component
688 void* handle = _library_map[impl_name];
689 iobject = createInstance(genericRegisterName,
692 return iobject._retn();
695 // If it's not a Python or a C++ component try to launch a standalone component
696 // in a sub directory
697 // This component is implemented in an executable with name genericRegisterName.exe
698 // It must register itself in Naming Service. The container waits some time (10 s max)
699 // it's registration.
701 _numInstanceMutex.lock() ; // lock on the instance number
703 int numInstance = _numInstance ;
704 _numInstanceMutex.unlock() ;
707 sprintf( aNumI , "%d" , numInstance ) ;
708 string instanceName = aCompName + "_inst_" + aNumI ;
709 string component_registerName = _containerName + "/" + instanceName;
711 //check if an entry exist in naming service
712 CORBA::Object_var nsobj = _NS->Resolve(component_registerName.c_str());
713 if ( !CORBA::is_nil(nsobj) )
715 // unregister the registered component
716 _NS->Destroy_Name(component_registerName.c_str());
717 //kill or shutdown it ???
720 // first arg container ior string
721 // second arg container name
722 // third arg instance name
724 Engines::Container_var pCont= _this();
725 CORBA::String_var sior = _orb->object_to_string(pCont);
729 command+=instanceName;
731 command+=instanceName;
733 command+=genericRegisterName ;
736 command+= sior; // container ior string
738 command+=_containerName; //container name
740 command+=instanceName; //instance name
742 MESSAGE("SALOME_Container::create_component_instance command=" << command);
745 // use fork/execl instead of system to get finer control on env variables
748 if(pid == 0) // child
750 for (CORBA::ULong i=0; i < env.length(); i++)
752 if (env[i].value.type()->kind() == CORBA::tk_string)
755 env[i].value >>= value;
756 std::string s(env[i].key);
759 putenv(strdup(s.c_str()));
763 execl("/bin/sh", "sh", "-c", command.c_str() , (char *)0);
766 else if(pid < 0) // failed to fork
775 tpid = wait(&status);
776 } while (tpid != pid);
779 // launch component with a system call
780 int status=system(command.c_str());
785 MESSAGE("SALOME_Container::create_component_instance system failed " << "(system command status -1)");
786 return Engines::Component::_nil();
789 else if (WEXITSTATUS(status) == 217)
791 MESSAGE("SALOME_Container::create_component_instance system failed " << "(system command status 217)");
792 return Engines::Component::_nil();
798 CORBA::Object_var obj = CORBA::Object::_nil() ;
799 while ( CORBA::is_nil(obj) && count )
807 MESSAGE( count << ". Waiting for component " << genericRegisterName);
808 obj = _NS->Resolve(component_registerName.c_str());
811 if(CORBA::is_nil(obj))
813 MESSAGE("SALOME_Container::create_component_instance failed");
814 return Engines::Component::_nil();
818 MESSAGE("SALOME_Container::create_component_instance successful");
819 iobject=Engines::Component::_narrow(obj);
820 _listInstances_map[instanceName] = iobject;
821 return iobject._retn();
826 //=============================================================================
827 //! Find an existing (in the container) component instance
829 * CORBA method: Finds a servant instance of a component
830 * \param registeredName Name of the component in Registry or Name Service,
831 * without instance suffix number
832 * \param studyId 0 if instance is not associated to a study,
833 * >0 otherwise (== study id)
834 * \return the first instance found with same studyId
836 //=============================================================================
838 Engines::Component_ptr
839 Engines_Container_i::find_component_instance( const char* registeredName,
842 Engines::Component_var anEngine = Engines::Component::_nil();
843 map<string,Engines::Component_var>::iterator itm =_listInstances_map.begin();
844 while (itm != _listInstances_map.end())
846 string instance = (*itm).first;
848 if (instance.find(registeredName) == 0)
850 anEngine = (*itm).second;
851 if (studyId == anEngine->getStudyId())
853 return anEngine._retn();
858 return anEngine._retn();
861 //=============================================================================
862 //! Find or create a new component instance
864 * CORBA method: find or create an instance of the component (servant),
865 * load a new component class (dynamic library) if required,
867 * ---- FOR COMPATIBILITY WITH 2.2 ----
869 * ---- USE ONLY FOR MULTISTUDY INSTANCES ! --------
871 * The servant registers itself to naming service and Registry.
872 * \param genericRegisterName Name of the component to register
873 * in Registry & Name Service
874 * \param componentName Name of the constructed library of the component
875 * \return a loaded component
877 //=============================================================================
879 Engines::Component_ptr
880 Engines_Container_i::load_impl( const char* genericRegisterName,
881 const char* componentName )
883 string impl_name = string ("lib") + genericRegisterName +string("Engine.so");
884 Engines::Component_var iobject = Engines::Component::_nil() ;
885 if (load_component_Library(genericRegisterName))
886 iobject = find_or_create_instance(genericRegisterName, impl_name);
887 return iobject._retn();
891 //=============================================================================
892 //! Remove the component instance from container
894 * CORBA method: Stops the component servant, and deletes all related objects
895 * \param component_i Component to be removed
897 //=============================================================================
899 void Engines_Container_i::remove_impl(Engines::Component_ptr component_i)
901 ASSERT(! CORBA::is_nil(component_i));
902 string instanceName = component_i->instanceName() ;
903 MESSAGE("unload component " << instanceName);
904 _numInstanceMutex.lock() ; // lock to be alone (stl container write)
905 _listInstances_map.erase(instanceName);
906 _numInstanceMutex.unlock() ;
907 component_i->destroy() ;
908 _NS->Destroy_Name(instanceName.c_str());
911 //=============================================================================
912 //! Unload component libraries from the container
914 * CORBA method: Discharges unused libraries from the container.
916 //=============================================================================
918 void Engines_Container_i::finalize_removal()
920 MESSAGE("finalize unload : dlclose");
921 _numInstanceMutex.lock(); // lock to be alone
922 // (see decInstanceCnt, load_component_Library)
923 map<string, void *>::iterator ith;
924 for (ith = _toRemove_map.begin(); ith != _toRemove_map.end(); ith++)
926 void *handle = (*ith).second;
927 string impl_name= (*ith).first;
932 // dlclose(handle); // SALOME unstable after ...
933 // _library_map.erase(impl_name);
936 _toRemove_map.clear();
937 _numInstanceMutex.unlock();
940 //=============================================================================
941 //! Kill the container
943 * CORBA method: Kill the container process with exit(0).
944 * To remove : never returns !
946 //=============================================================================
948 bool Engines_Container_i::Kill_impl()
950 MESSAGE("Engines_Container_i::Kill() pid "<< getpid() << " containerName "
951 << _containerName.c_str() << " machineName "
952 << Kernel_Utils::GetHostname().c_str());
953 INFOS("===============================================================");
954 INFOS("= REMOVE calls to Kill_impl in C++ container =");
955 INFOS("===============================================================");
961 //=============================================================================
962 //! Get or create a file reference object associated to a local file (to transfer it)
964 * CORBA method: get or create a fileRef object associated to a local file
965 * (a file on the computer on which runs the container server), which stores
966 * a list of (machine, localFileName) corresponding to copies already done.
968 * \param origFileName absolute path for a local file to copy on other
970 * \return a fileRef object associated to the file.
972 //=============================================================================
975 Engines_Container_i::createFileRef(const char* origFileName)
977 string origName(origFileName);
978 Engines::fileRef_var theFileRef = Engines::fileRef::_nil();
980 if (origName[0] != '/')
982 INFOS("path of file to copy must be an absolute path begining with '/'");
983 return Engines::fileRef::_nil();
986 if (CORBA::is_nil(_fileRef_map[origName]))
988 CORBA::Object_var obj=_poa->id_to_reference(*_id);
989 Engines::Container_var pCont = Engines::Container::_narrow(obj);
990 fileRef_i* aFileRef = new fileRef_i(pCont, origFileName);
991 theFileRef = Engines::fileRef::_narrow(aFileRef->_this());
992 _numInstanceMutex.lock() ; // lock to be alone (stl container write)
993 _fileRef_map[origName] = theFileRef;
994 _numInstanceMutex.unlock() ;
997 theFileRef = Engines::fileRef::_duplicate(_fileRef_map[origName]);
998 ASSERT(! CORBA::is_nil(theFileRef));
999 return theFileRef._retn();
1002 //=============================================================================
1003 //! Get a fileTransfer reference
1006 * \return a reference to the fileTransfer object
1008 //=============================================================================
1010 Engines::fileTransfer_ptr
1011 Engines_Container_i::getFileTransfer()
1013 Engines::fileTransfer_var aFileTransfer
1014 = Engines::fileTransfer::_duplicate(_fileTransfer);
1015 return aFileTransfer._retn();
1019 //! Create a Salome file
1020 Engines::Salome_file_ptr
1021 Engines_Container_i::createSalome_file(const char* origFileName)
1023 string origName(origFileName);
1024 if (CORBA::is_nil(_Salome_file_map[origName]))
1026 Salome_file_i* aSalome_file = new Salome_file_i();
1027 aSalome_file->setContainer(Engines::Container::_duplicate(this->_this()));
1030 aSalome_file->setLocalFile(origFileName);
1031 aSalome_file->recvFiles();
1033 catch (const SALOME::SALOME_Exception& e)
1035 return Engines::Salome_file::_nil();
1038 Engines::Salome_file_var theSalome_file = Engines::Salome_file::_nil();
1039 theSalome_file = Engines::Salome_file::_narrow(aSalome_file->_this());
1040 _numInstanceMutex.lock() ; // lock to be alone (stl container write)
1041 _Salome_file_map[origName] = theSalome_file;
1042 _numInstanceMutex.unlock() ;
1045 Engines::Salome_file_ptr theSalome_file =
1046 Engines::Salome_file::_duplicate(_Salome_file_map[origName]);
1047 ASSERT(!CORBA::is_nil(theSalome_file));
1048 return theSalome_file;
1050 //=============================================================================
1051 //! Finds an already existing component instance or create a new instance
1053 * C++ method: Finds an already existing servant instance of a component, or
1054 * create an instance.
1055 * ---- USE ONLY FOR MULTISTUDY INSTANCES ! --------
1056 * \param genericRegisterName Name of the component instance to register
1057 * in Registry & Name Service,
1058 * (without _inst_n suffix, like "COMPONENT")
1059 * \param componentLibraryName like "libCOMPONENTEngine.so"
1060 * \return a loaded component
1062 * example with names:
1063 * - aGenRegisterName = COMPONENT (= first argument)
1064 * - impl_name = libCOMPONENTEngine.so (= second argument)
1065 * - _containerName = /Containers/cli76ce/FactoryServer
1066 * - factoryName = COMPONENTEngine_factory
1067 * - component_registerBase = /Containers/cli76ce/FactoryServer/COMPONENT
1068 * - instanceName = COMPONENT_inst_1
1069 * - component_registerName = /Containers/cli76ce/FactoryServer/COMPONENT_inst_1
1071 //=============================================================================
1073 Engines::Component_ptr
1074 Engines_Container_i::find_or_create_instance(std::string genericRegisterName,
1075 std::string componentLibraryName)
1077 string aGenRegisterName = genericRegisterName;
1078 string impl_name = componentLibraryName;
1079 if (_library_map.count(impl_name) == 0)
1081 INFOS("shared library " << impl_name <<" must be loaded before creating instance");
1082 return Engines::Component::_nil() ;
1086 // --- find a registered instance in naming service, or create
1088 void* handle = _library_map[impl_name];
1089 string component_registerBase =
1090 _containerName + "/" + aGenRegisterName;
1091 Engines::Component_var iobject = Engines::Component::_nil() ;
1094 CORBA::Object_var obj =
1095 _NS->ResolveFirst( component_registerBase.c_str());
1096 if ( CORBA::is_nil( obj ) )
1098 iobject = createInstance(genericRegisterName,
1100 0); // force multiStudy instance here !
1104 iobject = Engines::Component::_narrow( obj ) ;
1105 Engines_Component_i *servant =
1106 dynamic_cast<Engines_Component_i*>
1107 (_poa->reference_to_servant(iobject));
1109 int studyId = servant->getStudyId();
1110 ASSERT (studyId >= 0);
1111 if (studyId == 0) // multiStudy instance, OK
1114 MESSAGE(component_registerBase.c_str()<<" already bound");
1116 else // monoStudy instance: NOK
1118 iobject = Engines::Component::_nil();
1119 INFOS("load_impl & find_component_instance methods "
1120 << "NOT SUITABLE for mono study components");
1126 INFOS( "Container_i::load_impl catched" ) ;
1128 return iobject._retn();
1132 //=============================================================================
1133 //! Create a new component instance
1135 * C++ method: create a servant instance of a component.
1136 * \param genericRegisterName Name of the component instance to register
1137 * in Registry & Name Service,
1138 * (without _inst_n suffix, like "COMPONENT")
1139 * \param handle loaded library handle
1140 * \param studyId 0 for multiStudy instance,
1141 * study Id (>0) otherwise
1142 * \return a loaded component
1144 * example with names:
1145 * - aGenRegisterName = COMPONENT (= first argument)
1146 * - _containerName = /Containers/cli76ce/FactoryServer
1147 * - factoryName = COMPONENTEngine_factory
1148 * - component_registerBase = /Containers/cli76ce/FactoryServer/COMPONENT
1149 * - instanceName = COMPONENT_inst_1
1150 * - component_registerName = /Containers/cli76ce/FactoryServer/COMPONENT_inst_1
1152 //=============================================================================
1154 Engines::Component_ptr
1155 Engines_Container_i::createInstance(std::string genericRegisterName,
1159 // --- find the factory
1161 string aGenRegisterName = genericRegisterName;
1162 string factory_name = aGenRegisterName + string("Engine_factory");
1163 SCRUTE(factory_name) ;
1165 typedef PortableServer::ObjectId * (*FACTORY_FUNCTION)
1167 PortableServer::POA_ptr,
1168 PortableServer::ObjectId *,
1173 FACTORY_FUNCTION Component_factory = (FACTORY_FUNCTION)dlsym( handle, factory_name.c_str() );
1175 FACTORY_FUNCTION Component_factory = (FACTORY_FUNCTION)GetProcAddress( (HINSTANCE)handle, factory_name.c_str() );
1178 if ( !Component_factory )
1180 INFOS( "Can't resolve symbol: " + factory_name );
1182 SCRUTE( dlerror() );
1184 return Engines::Component::_nil() ;
1187 // --- create instance
1189 Engines::Component_var iobject = Engines::Component::_nil() ;
1193 _numInstanceMutex.lock() ; // lock on the instance number
1195 int numInstance = _numInstance ;
1196 _numInstanceMutex.unlock() ;
1199 sprintf( aNumI , "%d" , numInstance ) ;
1200 string instanceName = aGenRegisterName + "_inst_" + aNumI ;
1201 string component_registerName =
1202 _containerName + "/" + instanceName;
1204 // --- Instanciate required CORBA object
1206 PortableServer::ObjectId *id ; //not owner, do not delete (nore use var)
1207 id = (Component_factory) ( _orb, _poa, _id, instanceName.c_str(),
1208 aGenRegisterName.c_str() ) ;
1210 return iobject._retn();
1212 // --- get reference & servant from id
1214 CORBA::Object_var obj = _poa->id_to_reference(*id);
1215 iobject = Engines::Component::_narrow( obj ) ;
1217 Engines_Component_i *servant =
1218 dynamic_cast<Engines_Component_i*>(_poa->reference_to_servant(iobject));
1220 //SCRUTE(servant->_refcount_value());
1221 _numInstanceMutex.lock() ; // lock to be alone (stl container write)
1222 _listInstances_map[instanceName] = iobject;
1223 _cntInstances_map[aGenRegisterName] += 1;
1224 _numInstanceMutex.unlock() ;
1225 SCRUTE(aGenRegisterName);
1226 SCRUTE(_cntInstances_map[aGenRegisterName]);
1227 servant->setStudyId(studyId);
1228 servant->_remove_ref(); // do not need servant any more (remove ref from reference_to_servant)
1229 //SCRUTE(servant->_refcount_value());
1231 // --- register the engine under the name
1232 // containerName(.dir)/instanceName(.object)
1234 _NS->Register( iobject , component_registerName.c_str() ) ;
1235 MESSAGE( component_registerName.c_str() << " bound" ) ;
1239 INFOS( "Container_i::createInstance exception catched" ) ;
1241 return iobject._retn();
1244 //=============================================================================
1245 //! Decrement component instance reference count
1249 //=============================================================================
1251 void Engines_Container_i::decInstanceCnt(std::string genericRegisterName)
1253 if(_cntInstances_map.count(genericRegisterName)==0)
1255 string aGenRegisterName =genericRegisterName;
1256 MESSAGE("Engines_Container_i::decInstanceCnt " << aGenRegisterName);
1257 ASSERT(_cntInstances_map[aGenRegisterName] > 0);
1258 _numInstanceMutex.lock(); // lock to be alone
1259 // (see finalize_removal, load_component_Library)
1260 _cntInstances_map[aGenRegisterName] -= 1;
1261 SCRUTE(_cntInstances_map[aGenRegisterName]);
1262 if (_cntInstances_map[aGenRegisterName] == 0)
1265 Engines_Component_i::GetDynLibraryName(aGenRegisterName.c_str());
1267 void* handle = _library_map[impl_name];
1269 _toRemove_map[impl_name] = handle;
1271 _numInstanceMutex.unlock();
1274 //=============================================================================
1275 //! Indicate if container is a python one
1277 * Retrieves only with container naming convention if it is a python container
1279 //=============================================================================
1281 bool Engines_Container_i::isPythonContainer(const char* ContainerName)
1284 int len=strlen(ContainerName);
1286 if(strcmp(ContainerName+len-2,"Py")==0)
1291 //=============================================================================
1295 //=============================================================================
1297 void ActSigIntHandler()
1300 struct sigaction SigIntAct ;
1301 SigIntAct.sa_sigaction = &SigIntHandler ;
1302 sigemptyset(&SigIntAct.sa_mask);
1303 SigIntAct.sa_flags = SA_SIGINFO ;
1306 // DEBUG 03.02.2005 : the first parameter of sigaction is not a mask of signals
1307 // (SIGINT | SIGUSR1) :
1308 // it must be only one signal ===> one call for SIGINT
1309 // and an other one for SIGUSR1
1312 if ( sigaction( SIGINT , &SigIntAct, NULL ) )
1314 perror("SALOME_Container main ") ;
1317 if ( sigaction( SIGUSR1 , &SigIntAct, NULL ) )
1319 perror("SALOME_Container main ") ;
1322 if ( sigaction( SIGUSR2 , &SigIntAct, NULL ) )
1324 perror("SALOME_Container main ") ;
1328 //PAL9042 JR : during the execution of a Signal Handler (and of methods called through Signal Handlers)
1329 // use of streams (and so on) should never be used because :
1330 // streams of C++ are naturally thread-safe and use pthread_mutex_lock ===>
1331 // A stream operation may be interrupted by a signal and if the Handler use stream we
1332 // may have a "Dead-Lock" ===HangUp
1333 //==INFOS is commented
1334 // INFOS(pthread_self() << "SigIntHandler activated") ;
1337 signal( SIGINT, SigIntHandler );
1338 signal( SIGUSR1, SigIntHandler );
1344 void CallCancelThread() ;
1347 void SigIntHandler(int what ,
1348 siginfo_t * siginfo ,
1351 //PAL9042 JR : during the execution of a Signal Handler (and of methods called through Signal Handlers)
1352 // use of streams (and so on) should never be used because :
1353 // streams of C++ are naturally thread-safe and use pthread_mutex_lock ===>
1354 // A stream operation may be interrupted by a signal and if the Handler use stream we
1355 // may have a "Dead-Lock" ===HangUp
1356 //==MESSAGE is commented
1357 // MESSAGE(pthread_self() << "SigIntHandler what " << what << endl
1358 // << " si_signo " << siginfo->si_signo << endl
1359 // << " si_code " << siginfo->si_code << endl
1360 // << " si_pid " << siginfo->si_pid) ;
1365 // MESSAGE("SigIntHandler END sleeping.") ;
1370 ActSigIntHandler() ;
1371 if ( siginfo->si_signo == SIGUSR1 )
1375 else if ( siginfo->si_signo == SIGUSR2 )
1377 CallCancelThread() ;
1382 // MESSAGE("SigIntHandler BEGIN sleeping.") ;
1389 // MESSAGE("SigIntHandler LEAVE sleeping after " << count << " s.") ;
1395 void SigIntHandler( int what )
1398 MESSAGE( pthread_self() << "SigIntHandler what " << what << endl );
1400 MESSAGE( "SigIntHandler what " << what << endl );
1405 MESSAGE("SigIntHandler END sleeping.") ;
1410 ActSigIntHandler() ;
1411 if ( what == SIGUSR1 )
1418 MESSAGE("SigIntHandler BEGIN sleeping.") ;
1425 MESSAGE("SigIntHandler LEAVE sleeping after " << count << " s.") ;
1432 /*! \brief copy a file from a remote host (container) to the local host
1433 * \param container the remote container
1434 * \param remoteFile the file to copy locally from the remote host into localFile
1435 * \param localFile the local file
1437 void Engines_Container_i::copyFile(Engines::Container_ptr container, const char* remoteFile, const char* localFile)
1439 Engines::fileTransfer_var fileTransfer = container->getFileTransfer();
1442 if ((fp = fopen(localFile,"wb")) == NULL)
1444 INFOS("file " << localFile << " cannot be open for writing");
1448 CORBA::Long fileId = fileTransfer->open(remoteFile);
1451 Engines::fileBlock* aBlock;
1458 aBlock = fileTransfer->getBlock(fileId);
1459 toFollow = aBlock->length();
1461 CORBA::Octet *buf = aBlock->get_buffer();
1462 fwrite(buf, sizeof(CORBA::Octet), toFollow, fp);
1466 MESSAGE("end of transfer");
1467 fileTransfer->close(fileId);
1471 INFOS("open reference file for copy impossible");
1475 /*! \brief create a PyNode object to execute remote python code
1476 * \param nodeName the name of the node
1477 * \param code the python code to load
1478 * \return the PyNode
1480 Engines::PyNode_ptr Engines_Container_i::createPyNode(const char* nodeName, const char* code)
1482 Engines::PyNode_var node= Engines::PyNode::_nil();
1484 PyGILState_STATE gstate = PyGILState_Ensure();
1485 PyObject *res = PyObject_CallMethod(_pyCont,
1486 (char*)"create_pynode",
1494 PyGILState_Release(gstate);
1495 SALOME::ExceptionStruct es;
1496 es.type = SALOME::INTERNAL_ERROR;
1497 es.text = "can not create a python node";
1498 throw SALOME::SALOME_Exception(es);
1500 long ierr=PyInt_AsLong(PyTuple_GetItem(res,0));
1501 PyObject* result=PyTuple_GetItem(res,1);
1502 std::string astr=PyString_AsString(result);
1504 PyGILState_Release(gstate);
1508 CORBA::Object_var obj = _orb->string_to_object(astr.c_str());
1509 node = Engines::PyNode::_narrow(obj);
1510 return node._retn();
1514 SALOME::ExceptionStruct es;
1515 es.type = SALOME::INTERNAL_ERROR;
1516 es.text = astr.c_str();
1517 throw SALOME::SALOME_Exception(es);