1 // SALOME Container : implementation of container and engine for Kernel
3 // Copyright (C) 2003 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
24 // File : Container_i.cxx
25 // Author : Paul RASCLE, EDF - MARC TAJCHMAN, CEA
29 //#define private public
44 #include "utilities.h"
45 #include <SALOMEconfig.h>
47 #include CORBA_SERVER_HEADER(SALOME_Component)
48 #include CORBA_SERVER_HEADER(SALOME_Exception)
50 //#include <SALOME_Component.hh>
52 #include <pthread.h> // must be before Python.h !
53 #include "SALOME_Container_i.hxx"
54 #include "SALOME_Component_i.hxx"
55 #include "SALOME_FileRef_i.hxx"
56 #include "SALOME_FileTransfer_i.hxx"
57 #include "Salome_file_i.hxx"
58 #include "SALOME_NamingService.hxx"
62 #include "Container_init_python.hxx"
66 bool _Sleeping = false ;
68 // // Needed by multi-threaded Python --- Supervision
73 // Containers with name FactoryServer are started via rsh in LifeCycleCORBA
74 // Other Containers are started via start_impl of FactoryServer
76 extern "C" {void ActSigIntHandler() ; }
78 extern "C" {void SigIntHandler(int, siginfo_t *, void *) ; }
80 extern "C" {void SigIntHandler( int ) ; }
84 # define separator '\\'
86 # define separator '/'
90 map<std::string, int> Engines_Container_i::_cntInstances_map;
91 map<std::string, void *> Engines_Container_i::_library_map;
92 map<std::string, void *> Engines_Container_i::_toRemove_map;
93 omni_mutex Engines_Container_i::_numInstanceMutex ;
95 //=============================================================================
97 * Default constructor, not for use
99 //=============================================================================
101 Engines_Container_i::Engines_Container_i () :
106 //=============================================================================
110 //=============================================================================
112 Engines_Container_i::Engines_Container_i (CORBA::ORB_ptr orb,
113 PortableServer::POA_ptr poa,
114 char *containerName ,
115 int argc , char* argv[],
117 bool isServantAloneInProcess
119 _numInstance(0),_isServantAloneInProcess(isServantAloneInProcess)
121 _pid = (long)getpid();
129 string hostname = GetHostname();
131 MESSAGE(hostname << " " << getpid() <<
132 " Engines_Container_i starting argc " <<
133 _argc << " Thread " << pthread_self() ) ;
135 MESSAGE(hostname << " " << _getpid() <<
136 " Engines_Container_i starting argc " << _argc<< " Thread " << pthread_self().p ) ;
142 MESSAGE(" argv" << i << " " << _argv[ i ]) ;
148 INFOS("SALOME_Container usage : SALOME_Container ServerName");
152 _isSupervContainer = false;
153 if (strcmp(argv[1],"SuperVisionContainer") == 0) _isSupervContainer = true;
155 if (_isSupervContainer)
161 _orb = CORBA::ORB::_duplicate(orb) ;
162 _poa = PortableServer::POA::_duplicate(poa) ;
164 // Pour les containers paralleles: il ne faut pas enregistrer et activer
165 // le container generique, mais le container specialise
169 _id = _poa->activate_object(this);
170 _NS = new SALOME_NamingService();
171 _NS->init_orb( _orb ) ;
172 CORBA::Object_var obj=_poa->id_to_reference(*_id);
173 Engines::Container_var pCont
174 = Engines::Container::_narrow(obj);
177 _containerName = _NS->BuildContainerNameForNS(containerName,
179 SCRUTE(_containerName);
180 _NS->Register(pCont, _containerName.c_str());
181 MESSAGE("Engines_Container_i::Engines_Container_i : Container name "
185 // import SALOME_Container
186 // pycont = SALOME_Container.SALOME_Container_i(containerIORStr)
188 CORBA::String_var sior = _orb->object_to_string(pCont);
189 string myCommand="pyCont = SALOME_Container.SALOME_Container_i('";
190 myCommand += _containerName + "','";
195 if (!_isSupervContainer)
199 PyEval_AcquireLock();
200 PyThreadState *myTstate = PyThreadState_New(KERNEL_PYTHON::_interp);
201 PyThreadState *myoldTstate = PyThreadState_Swap(myTstate);
203 Py_ACQUIRE_NEW_THREAD;
207 // mpv: this is temporary solution: there is a unregular crash if not
210 // first element is the path to Registry.dll, but it's wrong
211 PyRun_SimpleString("import sys\n");
212 PyRun_SimpleString("sys.path = sys.path[1:]\n");
214 PyRun_SimpleString("import SALOME_Container\n");
215 PyRun_SimpleString((char*)myCommand.c_str());
216 Py_RELEASE_NEW_THREAD;
219 fileTransfer_i* aFileTransfer = new fileTransfer_i();
220 CORBA::Object_var obref=aFileTransfer->_this();
221 _fileTransfer = Engines::fileTransfer::_narrow(obref);
222 aFileTransfer->_remove_ref();
226 //=============================================================================
230 //=============================================================================
232 Engines_Container_i::~Engines_Container_i()
234 MESSAGE("Container_i::~Container_i()");
240 //=============================================================================
242 * CORBA attribute: Container name (see constructor)
244 //=============================================================================
246 char* Engines_Container_i::name()
248 return CORBA::string_dup(_containerName.c_str()) ;
251 //=============================================================================
253 * CORBA attribute: Container working directory
255 //=============================================================================
257 char* Engines_Container_i::workingdir()
261 return CORBA::string_dup(wd) ;
264 //=============================================================================
266 * CORBA attribute: Container log file name
268 //=============================================================================
270 char* Engines_Container_i::logfilename()
272 return CORBA::string_dup(_logfilename.c_str()) ;
275 void Engines_Container_i::logfilename(const char* name)
280 //=============================================================================
282 * CORBA method: Get the hostName of the Container (without domain extensions)
284 //=============================================================================
286 char* Engines_Container_i::getHostName()
288 string s = GetHostname();
289 // MESSAGE("Engines_Container_i::getHostName " << s);
290 return CORBA::string_dup(s.c_str()) ;
293 //=============================================================================
295 * CORBA method: Get the PID (process identification) of the Container
297 //=============================================================================
299 CORBA::Long Engines_Container_i::getPID()
301 return (CORBA::Long)getpid();
304 //=============================================================================
306 * CORBA method: check if servant is still alive
308 //=============================================================================
310 void Engines_Container_i::ping()
312 MESSAGE("Engines_Container_i::ping() pid "<< getpid());
315 //=============================================================================
317 * CORBA method, oneway: Server shutdown.
318 * - Container name removed from naming service,
319 * - servant deactivation,
320 * - orb shutdown if no other servants in the process
322 //=============================================================================
324 void Engines_Container_i::Shutdown()
326 MESSAGE("Engines_Container_i::Shutdown()");
328 /* For each component contained in this container
329 * tell it to self-destroy
331 std::map<std::string, Engines::Component_var>::iterator itm;
332 for (itm = _listInstances_map.begin(); itm != _listInstances_map.end(); itm++)
333 itm->second->destroy();
335 _NS->Destroy_FullDirectory(_containerName.c_str());
336 _NS->Destroy_Name(_containerName.c_str());
338 //_poa->deactivate_object(*_id);
339 if(_isServantAloneInProcess)
341 MESSAGE("Effective Shutdown of container Begins...");
342 if(!CORBA::is_nil(_orb))
347 /* int checkifexecutable(const char *filename)
349 * Return non-zero if the name is an executable file, and
350 * zero if it is not executable, or if it does not exist.
353 int checkifexecutable(const string& filename)
356 struct stat statinfo;
358 result = stat(filename.c_str(), &statinfo);
359 if (result < 0) return 0;
360 if (!S_ISREG(statinfo.st_mode)) return 0;
365 if (statinfo.st_uid == geteuid()) return statinfo.st_mode & S_IXUSR;
366 if (statinfo.st_gid == getegid()) return statinfo.st_mode & S_IXGRP;
367 return statinfo.st_mode & S_IXOTH;
372 /* int findpathof(char *pth, const char *exe)
374 * Find executable by searching the PATH environment variable.
376 * const char *exe - executable name to search for.
377 * char *pth - the path found is stored here, space
378 * needs to be available.
380 * If a path is found, returns non-zero, and the path is stored
381 * in pth. If exe is not found returns 0, with pth undefined.
384 int findpathof(string& pth, const string& exe)
386 string path( getenv("PATH") );
387 if ( path.size() == 0 )
407 while(!stop && !found)
409 int pos = path.find( path_spr, offset );
410 if (pos == string::npos)
413 pth = path.substr( offset, pos - offset );
414 if ( pth.size() > 0 )
416 if( pth[pth.size()-1] != dir_spr )
419 found = checkifexecutable(pth.c_str());
430 if (strchr(exe, separator) != NULL) {
432 if (realpath(exe, pth) == NULL) return 0;
434 return checkifexecutable(pth);
437 searchpath = getenv("PATH");
438 if (searchpath == NULL) return 0;
439 if (strlen(searchpath) <= 0) return 0;
441 string env_path(searchpath);
446 end = strchr(beg, ':');
449 strncpy(pth, beg, PATH_MAX);
452 strncpy(pth, beg, end - beg);
453 pth[end - beg] = '\0';
456 if (pth[len - 1] != '/') strncat(pth, "/", 1);
457 strncat(pth, exe, PATH_MAX - len);
458 found = checkifexecutable(pth);
459 if (!stop) beg = end + 1;
460 } while (!stop && !found);
467 //=============================================================================
469 * CORBA method: load a new component class (Python or C++ implementation)
470 * \param componentName like COMPONENT
471 * try to make a Python import of COMPONENT,
472 * then a lib open of libCOMPONENTEngine.so
473 * \return true if dlopen successfull or already done, false otherwise
475 //=============================================================================
478 Engines_Container_i::load_component_Library(const char* componentName)
481 string aCompName = componentName;
483 // --- try dlopen C++ component
486 string impl_name = string ("lib") + aCompName + string("Engine.so");
488 string impl_name = aCompName + string("Engine.dll");
492 _numInstanceMutex.lock(); // lock to be alone
493 // (see decInstanceCnt, finalize_removal))
494 if (_toRemove_map.count(impl_name) != 0) _toRemove_map.erase(impl_name);
495 if (_library_map.count(impl_name) != 0)
497 MESSAGE("Library " << impl_name << " already loaded");
498 _numInstanceMutex.unlock();
504 handle = dlopen( impl_name.c_str() , RTLD_LAZY ) ;
507 handle = LoadLibrary( impl_name.c_str() );
512 _library_map[impl_name] = handle;
513 _numInstanceMutex.unlock();
516 _numInstanceMutex.unlock();
518 // --- try import Python component
520 INFOS("try import Python component "<<componentName);
521 if (_isSupervContainer)
523 INFOS("Supervision Container does not support Python Component Engines");
526 if (_library_map.count(aCompName) != 0)
528 return true; // Python Component, already imported
532 Py_ACQUIRE_NEW_THREAD;
533 PyObject *mainmod = PyImport_AddModule("__main__");
534 PyObject *globals = PyModule_GetDict(mainmod);
535 PyObject *pyCont = PyDict_GetItemString(globals, "pyCont");
536 PyObject *result = PyObject_CallMethod(pyCont,
537 (char*)"import_component",
538 (char*)"s",componentName);
539 int ret= PyInt_AsLong(result);
542 Py_RELEASE_NEW_THREAD;
544 if (ret) // import possible: Python component
546 _numInstanceMutex.lock() ; // lock to be alone (stl container write)
547 _library_map[aCompName] = (void *)pyCont; // any non O value OK
548 _numInstanceMutex.unlock() ;
549 MESSAGE("import Python: "<<aCompName<<" OK");
553 // Try to find an executable
554 std::string executable=aCompName+".exe";
556 if (findpathof(path, executable))
559 INFOS( "Impossible to load component: " << componentName );
560 INFOS( "Can't load shared library: " << impl_name );
561 INFOS( "Can't import Python module: " << componentName );
562 INFOS( "Can't execute program: " << executable );
566 //=============================================================================
568 * CORBA method: Creates a new servant instance of a component.
569 * The servant registers itself to naming service and Registry.
570 * \param genericRegisterName Name of the component instance to register
571 * in Registry & Name Service (without _inst_n suffix)
572 * \param studyId 0 for multiStudy instance,
573 * study Id (>0) otherwise
574 * \return a loaded component
576 //=============================================================================
578 Engines::Component_ptr
579 Engines_Container_i::create_component_instance(const char*genericRegisterName,
584 INFOS("studyId must be > 0 for mono study instance, =0 for multiStudy");
585 return Engines::Component::_nil() ;
588 Engines::Component_var iobject = Engines::Component::_nil() ;
590 string aCompName = genericRegisterName;
591 if (_library_map.count(aCompName) != 0) // Python component
593 if (_isSupervContainer)
595 INFOS("Supervision Container does not support Python Component Engines");
596 return Engines::Component::_nil();
598 _numInstanceMutex.lock() ; // lock on the instance number
600 int numInstance = _numInstance ;
601 _numInstanceMutex.unlock() ;
604 sprintf( aNumI , "%d" , numInstance ) ;
605 string instanceName = aCompName + "_inst_" + aNumI ;
606 string component_registerName =
607 _containerName + "/" + instanceName;
609 Py_ACQUIRE_NEW_THREAD;
610 PyObject *mainmod = PyImport_AddModule("__main__");
611 PyObject *globals = PyModule_GetDict(mainmod);
612 PyObject *pyCont = PyDict_GetItemString(globals, "pyCont");
613 PyObject *result = PyObject_CallMethod(pyCont,
614 (char*)"create_component_instance",
617 instanceName.c_str(),
619 string iors = PyString_AsString(result);
622 Py_RELEASE_NEW_THREAD;
626 CORBA::Object_var obj = _orb->string_to_object(iors.c_str());
627 iobject = Engines::Component::_narrow( obj ) ;
628 _listInstances_map[instanceName] = iobject;
630 return iobject._retn();
636 string impl_name = string ("lib") + genericRegisterName +string("Engine.so");
638 string impl_name = genericRegisterName +string("Engine.dll");
640 if (_library_map.count(impl_name) != 0) // C++ component
642 void* handle = _library_map[impl_name];
643 iobject = createInstance(genericRegisterName,
646 return iobject._retn();
649 // If it's not a Python or a C++ component try to launch a standalone component
650 // in a sub directory
651 // This component is implemented in an executable with name genericRegisterName.exe
652 // It must register itself in Naming Service. The container waits some time (10 s max)
653 // it's registration.
655 _numInstanceMutex.lock() ; // lock on the instance number
657 int numInstance = _numInstance ;
658 _numInstanceMutex.unlock() ;
661 sprintf( aNumI , "%d" , numInstance ) ;
662 string instanceName = aCompName + "_inst_" + aNumI ;
663 string component_registerName = _containerName + "/" + instanceName;
665 //check if an entry exist in naming service
666 CORBA::Object_var nsobj = _NS->Resolve(component_registerName.c_str());
667 if ( !CORBA::is_nil(nsobj) )
669 // unregister the registered component
670 _NS->Destroy_Name(component_registerName.c_str());
671 //kill or shutdown it ???
674 // first arg container ior string
675 // second arg container name
676 // third arg instance name
678 Engines::Container_var pCont= _this();
679 CORBA::String_var sior = _orb->object_to_string(pCont);
683 command+=instanceName;
685 command+=instanceName;
687 command+=genericRegisterName ;
690 command+= sior; // container ior string
692 command+=_containerName; //container name
694 command+=instanceName; //instance name
696 MESSAGE("SALOME_Container::create_component_instance command=" << command);
697 // launch component with a system call
698 int status=system(command.c_str());
702 MESSAGE("SALOME_Container::create_component_instance system failed " << "(system command status -1)");
703 return Engines::Component::_nil();
706 else if (WEXITSTATUS(status) == 217)
708 MESSAGE("SALOME_Container::create_component_instance system failed " << "(system command status 217)");
709 return Engines::Component::_nil();
715 CORBA::Object_var obj = CORBA::Object::_nil() ;
716 while ( CORBA::is_nil(obj) && count )
724 MESSAGE( count << ". Waiting for component " << genericRegisterName);
725 obj = _NS->Resolve(component_registerName.c_str());
728 if(CORBA::is_nil(obj))
730 MESSAGE("SALOME_Container::create_component_instance failed");
731 return Engines::Component::_nil();
735 MESSAGE("SALOME_Container::create_component_instance successful");
736 iobject=Engines::Component::_narrow(obj);
737 _listInstances_map[instanceName] = iobject;
738 return iobject._retn();
743 //=============================================================================
745 * CORBA method: Finds a servant instance of a component
746 * \param registeredName Name of the component in Registry or Name Service,
747 * without instance suffix number
748 * \param studyId 0 if instance is not associated to a study,
749 * >0 otherwise (== study id)
750 * \return the first instance found with same studyId
752 //=============================================================================
754 Engines::Component_ptr
755 Engines_Container_i::find_component_instance( const char* registeredName,
758 Engines::Component_var anEngine = Engines::Component::_nil();
759 map<string,Engines::Component_var>::iterator itm =_listInstances_map.begin();
760 while (itm != _listInstances_map.end())
762 string instance = (*itm).first;
764 if (instance.find(registeredName) == 0)
766 anEngine = (*itm).second;
767 if (studyId == anEngine->getStudyId())
769 return anEngine._retn();
774 return anEngine._retn();
777 //=============================================================================
779 * CORBA method: find or create an instance of the component (servant),
780 * load a new component class (dynamic library) if required,
781 * ---- FOR COMPATIBILITY WITH 2.2 ----
782 * ---- USE ONLY FOR MULTISTUDY INSTANCES ! --------
783 * The servant registers itself to naming service and Registry.
784 * \param genericRegisterName Name of the component to register
785 * in Registry & Name Service
786 * \param componentName Name of the constructed library of the component
787 * \return a loaded component
789 //=============================================================================
791 Engines::Component_ptr
792 Engines_Container_i::load_impl( const char* genericRegisterName,
793 const char* componentName )
795 string impl_name = string ("lib") + genericRegisterName +string("Engine.so");
796 Engines::Component_var iobject = Engines::Component::_nil() ;
797 if (load_component_Library(genericRegisterName))
798 iobject = find_or_create_instance(genericRegisterName, impl_name);
799 return iobject._retn();
803 //=============================================================================
805 * CORBA method: Stops the component servant, and deletes all related objects
806 * \param component_i Component to be removed
808 //=============================================================================
810 void Engines_Container_i::remove_impl(Engines::Component_ptr component_i)
812 ASSERT(! CORBA::is_nil(component_i));
813 string instanceName = component_i->instanceName() ;
814 MESSAGE("unload component " << instanceName);
815 _numInstanceMutex.lock() ; // lock to be alone (stl container write)
816 _listInstances_map.erase(instanceName);
817 _numInstanceMutex.unlock() ;
818 component_i->destroy() ;
819 _NS->Destroy_Name(instanceName.c_str());
822 //=============================================================================
824 * CORBA method: Discharges unused libraries from the container.
826 //=============================================================================
828 void Engines_Container_i::finalize_removal()
830 MESSAGE("finalize unload : dlclose");
831 _numInstanceMutex.lock(); // lock to be alone
832 // (see decInstanceCnt, load_component_Library)
833 map<string, void *>::iterator ith;
834 for (ith = _toRemove_map.begin(); ith != _toRemove_map.end(); ith++)
836 void *handle = (*ith).second;
837 string impl_name= (*ith).first;
842 // dlclose(handle); // SALOME unstable after ...
843 // _library_map.erase(impl_name);
846 _toRemove_map.clear();
847 _numInstanceMutex.unlock();
850 //=============================================================================
852 * CORBA method: Kill the container process with exit(0).
853 * To remove : never returns !
855 //=============================================================================
857 bool Engines_Container_i::Kill_impl()
859 MESSAGE("Engines_Container_i::Kill() pid "<< getpid() << " containerName "
860 << _containerName.c_str() << " machineName "
861 << GetHostname().c_str());
862 INFOS("===============================================================");
863 INFOS("= REMOVE calls to Kill_impl in C++ container =");
864 INFOS("===============================================================");
870 //=============================================================================
872 * CORBA method: get or create a fileRef object associated to a local file
873 * (a file on the computer on which runs the container server), which stores
874 * a list of (machine, localFileName) corresponding to copies already done.
876 * \param origFileName absolute path for a local file to copy on other
878 * \return a fileRef object associated to the file.
880 //=============================================================================
883 Engines_Container_i::createFileRef(const char* origFileName)
885 string origName(origFileName);
886 Engines::fileRef_var theFileRef = Engines::fileRef::_nil();
888 if (origName[0] != '/')
890 INFOS("path of file to copy must be an absolute path begining with '/'");
891 return Engines::fileRef::_nil();
894 if (CORBA::is_nil(_fileRef_map[origName]))
896 CORBA::Object_var obj=_poa->id_to_reference(*_id);
897 Engines::Container_var pCont = Engines::Container::_narrow(obj);
898 fileRef_i* aFileRef = new fileRef_i(pCont, origFileName);
899 theFileRef = Engines::fileRef::_narrow(aFileRef->_this());
900 _numInstanceMutex.lock() ; // lock to be alone (stl container write)
901 _fileRef_map[origName] = theFileRef;
902 _numInstanceMutex.unlock() ;
905 theFileRef = Engines::fileRef::_duplicate(_fileRef_map[origName]);
906 ASSERT(! CORBA::is_nil(theFileRef));
907 return theFileRef._retn();
910 //=============================================================================
913 * \return a reference to the fileTransfer object
915 //=============================================================================
917 Engines::fileTransfer_ptr
918 Engines_Container_i::getFileTransfer()
920 Engines::fileTransfer_var aFileTransfer
921 = Engines::fileTransfer::_duplicate(_fileTransfer);
922 return aFileTransfer._retn();
926 Engines::Salome_file_ptr
927 Engines_Container_i::createSalome_file(const char* origFileName)
929 string origName(origFileName);
930 if (CORBA::is_nil(_Salome_file_map[origName]))
932 Salome_file_i* aSalome_file = new Salome_file_i();
933 aSalome_file->setContainer(Engines::Container::_duplicate(this->_this()));
936 aSalome_file->setLocalFile(origFileName);
937 aSalome_file->recvFiles();
939 catch (const SALOME::SALOME_Exception& e)
941 return Engines::Salome_file::_nil();
944 Engines::Salome_file_var theSalome_file = Engines::Salome_file::_nil();
945 theSalome_file = Engines::Salome_file::_narrow(aSalome_file->_this());
946 _numInstanceMutex.lock() ; // lock to be alone (stl container write)
947 _Salome_file_map[origName] = theSalome_file;
948 _numInstanceMutex.unlock() ;
951 Engines::Salome_file_ptr theSalome_file =
952 Engines::Salome_file::_duplicate(_Salome_file_map[origName]);
953 ASSERT(!CORBA::is_nil(theSalome_file));
954 return theSalome_file;
956 //=============================================================================
958 * C++ method: Finds an already existing servant instance of a component, or
959 * create an instance.
960 * ---- USE ONLY FOR MULTISTUDY INSTANCES ! --------
961 * \param genericRegisterName Name of the component instance to register
962 * in Registry & Name Service,
963 * (without _inst_n suffix, like "COMPONENT")
964 * \param componentLibraryName like "libCOMPONENTEngine.so"
965 * \return a loaded component
967 * example with names:
968 * aGenRegisterName = COMPONENT (= first argument)
969 * impl_name = libCOMPONENTEngine.so (= second argument)
970 * _containerName = /Containers/cli76ce/FactoryServer
971 * factoryName = COMPONENTEngine_factory
972 * component_registerBase = /Containers/cli76ce/FactoryServer/COMPONENT
974 * instanceName = COMPONENT_inst_1
975 * component_registerName = /Containers/cli76ce/FactoryServer/COMPONENT_inst_1
977 //=============================================================================
979 Engines::Component_ptr
980 Engines_Container_i::find_or_create_instance(string genericRegisterName,
981 string componentLibraryName)
983 string aGenRegisterName = genericRegisterName;
984 string impl_name = componentLibraryName;
985 if (_library_map.count(impl_name) == 0)
987 INFOS("shared library " << impl_name <<" must be loaded before creating instance");
988 return Engines::Component::_nil() ;
992 // --- find a registered instance in naming service, or create
994 void* handle = _library_map[impl_name];
995 string component_registerBase =
996 _containerName + "/" + aGenRegisterName;
997 Engines::Component_var iobject = Engines::Component::_nil() ;
1000 CORBA::Object_var obj =
1001 _NS->ResolveFirst( component_registerBase.c_str());
1002 if ( CORBA::is_nil( obj ) )
1004 iobject = createInstance(genericRegisterName,
1006 0); // force multiStudy instance here !
1010 iobject = Engines::Component::_narrow( obj ) ;
1011 Engines_Component_i *servant =
1012 dynamic_cast<Engines_Component_i*>
1013 (_poa->reference_to_servant(iobject));
1015 int studyId = servant->getStudyId();
1016 ASSERT (studyId >= 0);
1017 if (studyId == 0) // multiStudy instance, OK
1020 MESSAGE(component_registerBase.c_str()<<" already bound");
1022 else // monoStudy instance: NOK
1024 iobject = Engines::Component::_nil();
1025 INFOS("load_impl & find_component_instance methods "
1026 << "NOT SUITABLE for mono study components");
1032 INFOS( "Container_i::load_impl catched" ) ;
1034 return iobject._retn();
1038 //=============================================================================
1040 * C++ method: create a servant instance of a component.
1041 * \param genericRegisterName Name of the component instance to register
1042 * in Registry & Name Service,
1043 * (without _inst_n suffix, like "COMPONENT")
1044 * \param handle loaded library handle
1045 * \param studyId 0 for multiStudy instance,
1046 * study Id (>0) otherwise
1047 * \return a loaded component
1049 * example with names:
1050 * aGenRegisterName = COMPONENT (= first argument)
1051 * _containerName = /Containers/cli76ce/FactoryServer
1052 * factoryName = COMPONENTEngine_factory
1053 * component_registerBase = /Containers/cli76ce/FactoryServer/COMPONENT
1054 * instanceName = COMPONENT_inst_1
1055 * component_registerName = /Containers/cli76ce/FactoryServer/COMPONENT_inst_1
1057 //=============================================================================
1059 Engines::Component_ptr
1060 Engines_Container_i::createInstance(string genericRegisterName,
1064 // --- find the factory
1066 string aGenRegisterName = genericRegisterName;
1067 string factory_name = aGenRegisterName + string("Engine_factory");
1068 SCRUTE(factory_name) ;
1070 typedef PortableServer::ObjectId * (*FACTORY_FUNCTION)
1072 PortableServer::POA_ptr,
1073 PortableServer::ObjectId *,
1078 FACTORY_FUNCTION Component_factory = (FACTORY_FUNCTION)dlsym( handle, factory_name.c_str() );
1080 FACTORY_FUNCTION Component_factory = (FACTORY_FUNCTION)GetProcAddress( (HINSTANCE)handle, factory_name.c_str() );
1083 if ( !Component_factory )
1085 INFOS( "Can't resolve symbol: " + factory_name );
1087 SCRUTE( dlerror() );
1089 return Engines::Component::_nil() ;
1092 // --- create instance
1094 Engines::Component_var iobject = Engines::Component::_nil() ;
1098 _numInstanceMutex.lock() ; // lock on the instance number
1100 int numInstance = _numInstance ;
1101 _numInstanceMutex.unlock() ;
1104 sprintf( aNumI , "%d" , numInstance ) ;
1105 string instanceName = aGenRegisterName + "_inst_" + aNumI ;
1106 string component_registerName =
1107 _containerName + "/" + instanceName;
1109 // --- Instanciate required CORBA object
1111 PortableServer::ObjectId *id ; //not owner, do not delete (nore use var)
1112 id = (Component_factory) ( _orb, _poa, _id, instanceName.c_str(),
1113 aGenRegisterName.c_str() ) ;
1115 return iobject._retn();
1117 // --- get reference & servant from id
1119 CORBA::Object_var obj = _poa->id_to_reference(*id);
1120 iobject = Engines::Component::_narrow( obj ) ;
1122 Engines_Component_i *servant =
1123 dynamic_cast<Engines_Component_i*>(_poa->reference_to_servant(iobject));
1125 //SCRUTE(servant->pd_refCount);
1126 servant->_remove_ref(); // compensate previous id_to_reference
1127 //SCRUTE(servant->pd_refCount);
1128 _numInstanceMutex.lock() ; // lock to be alone (stl container write)
1129 _listInstances_map[instanceName] = iobject;
1130 _cntInstances_map[aGenRegisterName] += 1;
1131 _numInstanceMutex.unlock() ;
1132 SCRUTE(aGenRegisterName);
1133 SCRUTE(_cntInstances_map[aGenRegisterName]);
1134 //SCRUTE(servant->pd_refCount);
1135 #if defined(_DEBUG_) || defined(_DEBUG)
1136 bool ret_studyId = servant->setStudyId(studyId);
1137 ASSERT(ret_studyId);
1139 servant->setStudyId(studyId);
1142 // --- register the engine under the name
1143 // containerName(.dir)/instanceName(.object)
1145 _NS->Register( iobject , component_registerName.c_str() ) ;
1146 MESSAGE( component_registerName.c_str() << " bound" ) ;
1150 INFOS( "Container_i::createInstance exception catched" ) ;
1152 return iobject._retn();
1155 //=============================================================================
1159 //=============================================================================
1161 void Engines_Container_i::decInstanceCnt(string genericRegisterName)
1163 if(_cntInstances_map.count(genericRegisterName)==0)
1165 string aGenRegisterName =genericRegisterName;
1166 MESSAGE("Engines_Container_i::decInstanceCnt " << aGenRegisterName);
1167 ASSERT(_cntInstances_map[aGenRegisterName] > 0);
1168 _numInstanceMutex.lock(); // lock to be alone
1169 // (see finalize_removal, load_component_Library)
1170 _cntInstances_map[aGenRegisterName] -= 1;
1171 SCRUTE(_cntInstances_map[aGenRegisterName]);
1172 if (_cntInstances_map[aGenRegisterName] == 0)
1175 Engines_Component_i::GetDynLibraryName(aGenRegisterName.c_str());
1177 void* handle = _library_map[impl_name];
1179 _toRemove_map[impl_name] = handle;
1181 _numInstanceMutex.unlock();
1184 //=============================================================================
1186 * Retrieves only with container naming convention if it is a python container
1188 //=============================================================================
1190 bool Engines_Container_i::isPythonContainer(const char* ContainerName)
1193 int len=strlen(ContainerName);
1195 if(strcmp(ContainerName+len-2,"Py")==0)
1200 //=============================================================================
1204 //=============================================================================
1206 void ActSigIntHandler()
1209 struct sigaction SigIntAct ;
1210 SigIntAct.sa_sigaction = &SigIntHandler ;
1211 SigIntAct.sa_flags = SA_SIGINFO ;
1214 // DEBUG 03.02.2005 : the first parameter of sigaction is not a mask of signals
1215 // (SIGINT | SIGUSR1) :
1216 // it must be only one signal ===> one call for SIGINT
1217 // and an other one for SIGUSR1
1220 if ( sigaction( SIGINT , &SigIntAct, NULL ) )
1222 perror("SALOME_Container main ") ;
1225 if ( sigaction( SIGUSR1 , &SigIntAct, NULL ) )
1227 perror("SALOME_Container main ") ;
1230 if ( sigaction( SIGUSR2 , &SigIntAct, NULL ) )
1232 perror("SALOME_Container main ") ;
1236 //PAL9042 JR : during the execution of a Signal Handler (and of methods called through Signal Handlers)
1237 // use of streams (and so on) should never be used because :
1238 // streams of C++ are naturally thread-safe and use pthread_mutex_lock ===>
1239 // A stream operation may be interrupted by a signal and if the Handler use stream we
1240 // may have a "Dead-Lock" ===HangUp
1241 //==INFOS is commented
1242 // INFOS(pthread_self() << "SigIntHandler activated") ;
1245 signal( SIGINT, SigIntHandler );
1246 signal( SIGUSR1, SigIntHandler );
1252 void CallCancelThread() ;
1255 void SigIntHandler(int what ,
1256 siginfo_t * siginfo ,
1259 //PAL9042 JR : during the execution of a Signal Handler (and of methods called through Signal Handlers)
1260 // use of streams (and so on) should never be used because :
1261 // streams of C++ are naturally thread-safe and use pthread_mutex_lock ===>
1262 // A stream operation may be interrupted by a signal and if the Handler use stream we
1263 // may have a "Dead-Lock" ===HangUp
1264 //==MESSAGE is commented
1265 // MESSAGE(pthread_self() << "SigIntHandler what " << what << endl
1266 // << " si_signo " << siginfo->si_signo << endl
1267 // << " si_code " << siginfo->si_code << endl
1268 // << " si_pid " << siginfo->si_pid) ;
1273 // MESSAGE("SigIntHandler END sleeping.") ;
1278 ActSigIntHandler() ;
1279 if ( siginfo->si_signo == SIGUSR1 )
1283 else if ( siginfo->si_signo == SIGUSR2 )
1285 CallCancelThread() ;
1290 // MESSAGE("SigIntHandler BEGIN sleeping.") ;
1297 // MESSAGE("SigIntHandler LEAVE sleeping after " << count << " s.") ;
1303 void SigIntHandler( int what )
1306 MESSAGE( pthread_self() << "SigIntHandler what " << what << endl );
1308 MESSAGE( "SigIntHandler what " << what << endl );
1313 MESSAGE("SigIntHandler END sleeping.") ;
1318 ActSigIntHandler() ;
1319 if ( what == SIGUSR1 )
1326 MESSAGE("SigIntHandler BEGIN sleeping.") ;
1333 MESSAGE("SigIntHandler LEAVE sleeping after " << count << " s.") ;