Back to index

salome-kernel  6.5.0
MPIContainer_i.cxx
Go to the documentation of this file.
00001 // Copyright (C) 2007-2012  CEA/DEN, EDF R&D, OPEN CASCADE
00002 //
00003 // Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
00004 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
00005 //
00006 // This library is free software; you can redistribute it and/or
00007 // modify it under the terms of the GNU Lesser General Public
00008 // License as published by the Free Software Foundation; either
00009 // version 2.1 of the License.
00010 //
00011 // This library is distributed in the hope that it will be useful,
00012 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00013 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014 // Lesser General Public License for more details.
00015 //
00016 // You should have received a copy of the GNU Lesser General Public
00017 // License along with this library; if not, write to the Free Software
00018 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
00019 //
00020 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
00021 //
00022 //  File   : MPIContainer_i.cxx
00023 //  Module : SALOME
00024 
00025 #include <iostream>
00026 #include <dlfcn.h>
00027 #include <stdio.h>
00028 #include "Basics_Utils.hxx"
00029 #include "SALOME_Component_i.hxx"
00030 #include "MPIContainer_i.hxx"
00031 #include "SALOME_NamingService.hxx"
00032 #include "Utils_SINGLETON.hxx"
00033 #include "OpUtil.hxx"
00034 #include "utilities.h"
00035 #include <time.h>
00036 #include <sys/time.h>
00037 #include <pthread.h>  // must be before Python.h !
00038 #include <Python.h>
00039 #include "Container_init_python.hxx"
00040 
00041 // L'appel au registry SALOME ne se fait que pour le process 0
00042 Engines_MPIContainer_i::Engines_MPIContainer_i(CORBA::ORB_ptr orb, 
00043                                                PortableServer::POA_ptr poa,
00044                                                char * containerName,
00045                                                int argc, char *argv[]) 
00046   : Engines_Container_i(orb,poa,containerName,argc,argv,false)
00047 {
00048 
00049   _id = _poa->activate_object(this);
00050   CORBA::Object_var obj=_poa->id_to_reference(*_id);
00051   Engines::Container_var pCont = Engines::Container::_narrow(obj);
00052   _remove_ref();
00053 
00054   if(_numproc==0){
00055 
00056     _NS = new SALOME_NamingService();
00057     _NS->init_orb( CORBA::ORB::_duplicate(_orb) ) ;
00058 
00059     std::string hostname = Kernel_Utils::GetHostname();
00060     _containerName = _NS->BuildContainerNameForNS(containerName,hostname.c_str());
00061     SCRUTE(_containerName);
00062     _NS->Register(pCont, _containerName.c_str());
00063 
00064   }
00065 
00066   // Root recupere les ior des container des autre process
00067   Engines::MPIObject_var pobj = POA_Engines::MPIContainer::_this();
00068   BCastIOR(_orb,pobj,true);
00069 }
00070 
00071 Engines_MPIContainer_i::Engines_MPIContainer_i() 
00072   : Engines_Container_i()
00073 {
00074 }
00075 
00076 Engines_MPIContainer_i::~Engines_MPIContainer_i(void)
00077 {
00078   MESSAGE("[" << _numproc << "] Engines_MPIContainer_i::~Engines_MPIContainer_i()");
00079 }
00080 
00081 // Load component
00082 void Engines_MPIContainer_i::Shutdown()
00083 {
00084   int ip;
00085   MESSAGE("[" << _numproc << "] shutdown of MPI Corba Server");
00086   if( _numproc == 0 ){
00087     _NS->Destroy_FullDirectory(_containerName.c_str());
00088     _NS->Destroy_Name(_containerName.c_str());
00089     for(ip= 1;ip<_nbproc;ip++)
00090       (Engines::MPIContainer::_narrow((*_tior)[ip]))->Shutdown();
00091   }
00092 
00093   std::map<std::string, Engines::EngineComponent_var>::iterator itm;
00094   for (itm = _listInstances_map.begin(); itm != _listInstances_map.end(); itm++)
00095     {
00096       try
00097         {
00098           itm->second->destroy();
00099         }
00100       catch(const CORBA::Exception& e)
00101         {
00102           // ignore this entry and continue
00103         }
00104       catch(...)
00105         {
00106           // ignore this entry and continue
00107         }
00108     }
00109 
00110   _orb->shutdown(0);
00111 
00112 }
00113 
00114 // Load a component library
00115 bool Engines_MPIContainer_i::load_component_Library(const char* componentName, CORBA::String_out reason)
00116 {
00117   reason=CORBA::string_dup("");
00118 
00119   pthread_t *th;
00120   if(_numproc == 0){
00121     th = new pthread_t[_nbproc];
00122     for(int ip=1;ip<_nbproc;ip++){
00123       thread_st *st = new thread_st;
00124       st->ip = ip;
00125       st->tior = _tior;
00126       st->compoName = componentName;
00127       pthread_create(&(th[ip]),NULL,th_loadcomponentlibrary,(void*)st);
00128     }
00129   }
00130 
00131   bool ret = Lload_component_Library(componentName);
00132 
00133   if(_numproc == 0){
00134     for(int ip=1;ip<_nbproc;ip++)
00135       pthread_join(th[ip],NULL);
00136     delete th;
00137   }
00138   return ret;
00139 }
00140 
00141 bool Engines_MPIContainer_i::Lload_component_Library(const char* componentName)
00142 {
00143   std::string aCompName = componentName;
00144 
00145   // --- try dlopen C++ component
00146 
00147   std::string impl_name = std::string ("lib") + aCompName + std::string("Engine.so");
00148   
00149   _numInstanceMutex.lock(); // lock to be alone 
00150   // (see decInstanceCnt, finalize_removal))
00151   if (_toRemove_map[impl_name]) _toRemove_map.erase(impl_name);
00152   if (_library_map[impl_name])
00153     {
00154       MESSAGE("[" << _numproc << "] Library " << impl_name << " already loaded");
00155       _numInstanceMutex.unlock();
00156       return true;
00157     }
00158   
00159   void* handle;
00160   handle = dlopen( impl_name.c_str() , RTLD_LAZY ) ;
00161   if ( handle )
00162     {
00163       _library_map[impl_name] = handle;
00164       _numInstanceMutex.unlock();
00165       MESSAGE("[" << _numproc << "] Library " << impl_name << " loaded");
00166       return true;
00167     }
00168   else
00169     {
00170       MESSAGE("[" << _numproc << "] Can't load shared library : " << impl_name);
00171       MESSAGE("[" << _numproc << "] error dlopen: " << dlerror());
00172     }
00173   _numInstanceMutex.unlock();
00174 
00175   // --- try import Python component
00176 
00177   INFOS("[" << _numproc << "] try import Python component "<<componentName);
00178   if (_isSupervContainer)
00179     {
00180       INFOS("[" << _numproc << "] Supervision Container does not support Python Component Engines");
00181       return false;
00182     }
00183   if (_library_map[aCompName])
00184     {
00185       return true; // Python Component, already imported
00186     }
00187   else
00188     {
00189       Py_ACQUIRE_NEW_THREAD;
00190       PyObject *mainmod = PyImport_AddModule((char *)"__main__");
00191       PyObject *globals = PyModule_GetDict(mainmod);
00192       PyObject *pyCont = PyDict_GetItemString(globals, "pyCont");
00193       PyObject *result = PyObject_CallMethod(pyCont,
00194                                              (char*)"import_component",
00195                                              (char*)"s",componentName);
00196       std::string ret= PyString_AsString(result);
00197       SCRUTE(ret);
00198       Py_RELEASE_NEW_THREAD;
00199   
00200       if (ret=="") // import possible: Python component
00201         {
00202           _library_map[aCompName] = (void *)pyCont; // any non O value OK
00203           MESSAGE("[" << _numproc << "] import Python: "<<aCompName<<" OK");
00204           return true;
00205         }
00206     }
00207   return false;
00208 }
00209 
00210 // Create an instance of component
00211 Engines::EngineComponent_ptr
00212 Engines_MPIContainer_i::create_component_instance_env( const char* componentName,
00213                                                        CORBA::Long studyId,
00214                                                        const Engines::FieldsDict& env,
00215                                                        CORBA::String_out reason)
00216 {
00217   reason=CORBA::string_dup("");
00218 
00219   pthread_t *th;
00220   if(_numproc == 0){
00221     th = new pthread_t[_nbproc];
00222     for(int ip=1;ip<_nbproc;ip++){
00223       thread_st *st = new thread_st;
00224       st->ip = ip;
00225       st->tior = _tior;
00226       st->compoName = componentName;
00227       st->studyId = studyId;
00228       pthread_create(&(th[ip]),NULL,th_createcomponentinstance,(void*)st);
00229     }
00230   }
00231 
00232   Engines::EngineComponent_ptr cptr = Lcreate_component_instance(componentName,studyId);
00233 
00234   if(_numproc == 0){
00235     for(int ip=1;ip<_nbproc;ip++)
00236       pthread_join(th[ip],NULL);
00237     delete th;
00238   }
00239 
00240   return cptr;
00241 }
00242 
00243 Engines::EngineComponent_ptr
00244 Engines_MPIContainer_i::Lcreate_component_instance( const char* genericRegisterName, CORBA::Long studyId)
00245 {
00246   if (studyId < 0) {
00247     INFOS("studyId must be > 0 for mono study instance, =0 for multiStudy");
00248     return Engines::EngineComponent::_nil() ;
00249   }
00250 
00251   Engines::EngineComponent_var iobject = Engines::EngineComponent::_nil() ;
00252   Engines::MPIObject_var pobj;
00253 
00254   std::string aCompName = genericRegisterName;
00255   if (_library_map[aCompName]) { // Python component
00256     if (_isSupervContainer) {
00257       INFOS("Supervision Container does not support Python Component Engines");
00258       return Engines::EngineComponent::_nil();
00259     }
00260     _numInstanceMutex.lock() ; // lock on the instance number
00261     _numInstance++ ;
00262     int numInstance = _numInstance ;
00263     _numInstanceMutex.unlock() ;
00264 
00265     char aNumI[12];
00266     sprintf( aNumI , "%d" , numInstance ) ;
00267     std::string instanceName = aCompName + "_inst_" + aNumI ;
00268     std::string component_registerName =
00269       _containerName + "/" + instanceName;
00270 
00271     Py_ACQUIRE_NEW_THREAD;
00272     PyObject *mainmod = PyImport_AddModule((char*)"__main__");
00273     PyObject *globals = PyModule_GetDict(mainmod);
00274     PyObject *pyCont = PyDict_GetItemString(globals, "pyCont");
00275     PyObject *result = PyObject_CallMethod(pyCont,
00276                                            (char*)"create_component_instance",
00277                                            (char*)"ssl",
00278                                            aCompName.c_str(),
00279                                            instanceName.c_str(),
00280                                            studyId);
00281     const char *ior;
00282     const char *error;
00283     PyArg_ParseTuple(result,"ss", &ior, &error);
00284     std::string iors = ior;
00285     SCRUTE(iors);
00286     Py_RELEASE_NEW_THREAD;
00287   
00288     CORBA::Object_var obj = _orb->string_to_object(iors.c_str());
00289     iobject = Engines::EngineComponent::_narrow( obj ) ;
00290     pobj = Engines::MPIObject::_narrow(obj) ;
00291     if( _numproc == 0 )
00292       _NS->Register(iobject, component_registerName.c_str()) ;
00293     // Root recupere les ior des composants des autre process
00294     BCastIOR(_orb,pobj,false);
00295 
00296     return iobject._retn();
00297   }
00298   
00299   //--- try C++
00300 
00301   std::string impl_name = std::string ("lib") + genericRegisterName +std::string("Engine.so");
00302   if (_library_map.count(impl_name) != 0) // C++ component
00303     {
00304       void* handle = _library_map[impl_name];
00305       iobject = createMPIInstance(genericRegisterName,
00306                                     handle,
00307                                     studyId);
00308       return iobject._retn();
00309     }
00310 
00311   return Engines::EngineComponent::_nil() ;
00312 }
00313 
00314 Engines::EngineComponent_ptr
00315 Engines_MPIContainer_i::createMPIInstance(std::string genericRegisterName,
00316                                           void *handle,
00317                                           int studyId)
00318 {
00319   Engines::EngineComponent_var iobject;
00320   Engines::MPIObject_var pobj;
00321   // --- find the factory
00322 
00323   std::string aGenRegisterName = genericRegisterName;
00324   std::string factory_name = aGenRegisterName + std::string("Engine_factory");
00325 
00326   typedef  PortableServer::ObjectId * (*MPIFACTORY_FUNCTION)
00327     (CORBA::ORB_ptr,
00328      PortableServer::POA_ptr, 
00329      PortableServer::ObjectId *, 
00330      const char *, 
00331      const char *) ;
00332 
00333   dlerror();
00334   MPIFACTORY_FUNCTION MPIComponent_factory = (MPIFACTORY_FUNCTION) dlsym(handle, factory_name.c_str());
00335 
00336   if ( !MPIComponent_factory )
00337     {
00338       INFOS( "[" << _numproc << "] Can't resolve symbol: " + factory_name );
00339       SCRUTE( dlerror() );
00340       pobj = Engines::MPIObject::_nil();
00341       BCastIOR(_orb,pobj,false);
00342       return Engines::EngineComponent::_nil();
00343     }
00344 
00345   // --- create instance
00346 
00347   iobject = Engines::EngineComponent::_nil() ;
00348 
00349   try
00350     {
00351       _numInstanceMutex.lock() ; // lock on the instance number
00352       _numInstance++ ;
00353       int numInstance = _numInstance ;
00354       _numInstanceMutex.unlock() ;
00355 
00356       char aNumI[12];
00357       sprintf( aNumI , "%d" , numInstance ) ;
00358       std::string instanceName = aGenRegisterName + "_inst_" + aNumI ;
00359       std::string component_registerName =
00360         _containerName + "/" + instanceName;
00361 
00362       // --- Instanciate required CORBA object
00363 
00364       PortableServer::ObjectId *id ; //not owner, do not delete (nore use var)
00365       id = (MPIComponent_factory) ( _orb, _poa, _id, instanceName.c_str(), aGenRegisterName.c_str() ) ;
00366 
00367       // --- get reference & servant from id
00368 
00369       CORBA::Object_var obj = _poa->id_to_reference(*id);
00370       iobject = Engines::EngineComponent::_narrow( obj ) ;
00371       pobj = Engines::MPIObject::_narrow(obj) ;
00372 
00373       Engines_Component_i *servant =
00374         dynamic_cast<Engines_Component_i*>(_poa->reference_to_servant(iobject));
00375       ASSERT(servant);
00376       //SCRUTE(servant->pd_refCount);
00377       servant->_remove_ref(); // compensate previous id_to_reference 
00378       //SCRUTE(servant->pd_refCount);
00379       _listInstances_map[instanceName] = iobject;
00380       _cntInstances_map[aGenRegisterName] += 1;
00381       //SCRUTE(servant->pd_refCount);
00382 #ifndef _DEBUG_
00383       servant->setStudyId(studyId);
00384 #else
00385       bool ret_studyId = servant->setStudyId(studyId);
00386       ASSERT(ret_studyId);
00387 #endif
00388 
00389       // --- register the engine under the name
00390       //     containerName(.dir)/instanceName(.object)
00391 
00392       if( _numproc == 0 ){
00393         _NS->Register( iobject , component_registerName.c_str() ) ;
00394         MESSAGE( component_registerName.c_str() << " bound" ) ;
00395       }
00396       // Root recupere les ior des composants des autre process
00397       BCastIOR(_orb,pobj,false);
00398 
00399     }
00400   catch(const std::exception &ex){
00401     INFOS( ex.what() ) ;
00402     return Engines::EngineComponent::_nil();
00403   }
00404   return iobject._retn();
00405 }
00406 
00407 // Load component
00408 Engines::EngineComponent_ptr Engines_MPIContainer_i::load_impl(const char* nameToRegister,
00409                                                  const char* componentName)
00410 {
00411   pthread_t *th;
00412   if(_numproc == 0){
00413     th = new pthread_t[_nbproc];
00414     for(int ip=1;ip<_nbproc;ip++){
00415       thread_st *st = new thread_st;
00416       st->ip = ip;
00417       st->tior = _tior;
00418       st->nameToRegister = nameToRegister;
00419       st->compoName = componentName;
00420       pthread_create(&(th[ip]),NULL,th_loadimpl,(void*)st);
00421     }
00422   }
00423 
00424   Engines::EngineComponent_ptr cptr =  Lload_impl(nameToRegister,componentName);
00425 
00426   if(_numproc == 0){
00427     for(int ip=1;ip<_nbproc;ip++)
00428       pthread_join(th[ip],NULL);
00429     delete th;
00430   }
00431 
00432   return cptr;
00433 }
00434 
00435 // Load component
00436 Engines::EngineComponent_ptr Engines_MPIContainer_i::Lload_impl(
00437                                    const char* nameToRegister,
00438                                    const char* componentName)
00439 {
00440   Engines::EngineComponent_var iobject;
00441   Engines::MPIObject_var pobj;
00442   char cproc[4];
00443 
00444   sprintf(cproc,"_%d",_numproc);
00445 
00446   BEGIN_OF("[" << _numproc << "] MPIContainer_i::Lload_impl");
00447 
00448   _numInstanceMutex.lock() ; // lock on the instance number
00449   _numInstance++ ;
00450   char _aNumI[12];
00451   sprintf(_aNumI,"%d",_numInstance) ;
00452 
00453   std::string _impl_name = componentName;
00454   std::string _nameToRegister = nameToRegister;
00455   std::string instanceName = _nameToRegister + "_inst_" + _aNumI + cproc;
00456   MESSAGE("[" << _numproc << "] instanceName=" << instanceName);
00457 
00458   std::string absolute_impl_name(_impl_name);
00459   MESSAGE("[" << _numproc << "] absolute_impl_name=" << absolute_impl_name);
00460   void * handle = dlopen(absolute_impl_name.c_str(), RTLD_LAZY);
00461   if(!handle){
00462     INFOS("[" << _numproc << "] Can't load shared library : " << absolute_impl_name);
00463     INFOS("[" << _numproc << "] error dlopen: " << dlerror());
00464     return Engines::EngineComponent::_nil() ;
00465   }
00466 
00467   std::string factory_name = _nameToRegister + std::string("Engine_factory");
00468   MESSAGE("[" << _numproc << "] factory_name=" << factory_name) ;
00469 
00470   dlerror();
00471   PortableServer::ObjectId * (*MPIComponent_factory) (CORBA::ORB_ptr,
00472                                                   PortableServer::POA_ptr,
00473                                                   PortableServer::ObjectId *,
00474                                                   const char *,
00475                                                   const char *) =
00476     (PortableServer::ObjectId * (*) (CORBA::ORB_ptr,
00477                                      PortableServer::POA_ptr, 
00478                                      PortableServer::ObjectId *, 
00479                                      const char *, 
00480                                      const char *)) 
00481     dlsym(handle, factory_name.c_str());
00482 
00483   char *error ;
00484   if ((error = dlerror()) != NULL){
00485     // Try to load a sequential component
00486     MESSAGE("[" << _numproc << "] Try to load a sequential component");
00487     _numInstanceMutex.unlock() ;
00488     iobject = Engines_Container_i::load_impl(nameToRegister,componentName);
00489     if( CORBA::is_nil(iobject) ) return Engines::EngineComponent::_duplicate(iobject);
00490   }
00491   else{
00492     // Instanciation du composant parallele
00493     MESSAGE("[" << _numproc << "] Try to load a parallel component");
00494     PortableServer::ObjectId * id = (MPIComponent_factory)
00495       (_orb, _poa, _id, instanceName.c_str(), _nameToRegister.c_str());
00496     // get reference from id
00497     CORBA::Object_var o = _poa->id_to_reference(*id);
00498     pobj = Engines::MPIObject::_narrow(o) ;
00499     iobject = Engines::EngineComponent::_narrow(o) ;
00500   }
00501 
00502   if( _numproc == 0 ){
00503     // utiliser + tard le registry ici :
00504     // register the engine under the name containerName.dir/nameToRegister.object
00505     std::string component_registerName = _containerName + "/" + _nameToRegister;
00506     _NS->Register(iobject, component_registerName.c_str()) ;
00507   }
00508 
00509   _numInstanceMutex.unlock() ;
00510 
00511   // Root recupere les ior des composants des autre process
00512   BCastIOR(_orb,pobj,false);
00513 
00514   END_OF("[" <<_numproc << "] MPIContainer_i::Lload_impl");
00515   return Engines::EngineComponent::_duplicate(iobject);
00516 
00517 }
00518 
00519 void Engines_MPIContainer_i::remove_impl(Engines::EngineComponent_ptr component_i)
00520 {
00521   Engines::MPIObject_ptr pcptr;
00522   Engines::MPIObject_ptr spcptr;
00523 
00524   pthread_t *th;
00525   if(_numproc == 0){
00526     pcptr = (Engines::MPIObject_ptr)component_i;
00527     th = new pthread_t[_nbproc];
00528     for(int ip=1;ip<_nbproc;ip++){
00529       thread_st *st = new thread_st;
00530       st->ip = ip;
00531       st->tior = _tior;
00532       spcptr = Engines::MPIObject::_narrow((*(pcptr->tior()))[ip]);
00533       st->cptr = (Engines::EngineComponent_ptr)spcptr;
00534       pthread_create(&(th[ip]),NULL,th_removeimpl,(void*)st);
00535     }
00536   }
00537 
00538   ASSERT(! CORBA::is_nil(component_i));
00539   std::string instanceName = component_i->instanceName() ;
00540   MESSAGE("[" << _numproc << "] unload component " << instanceName);
00541   _numInstanceMutex.lock() ; // lock on the remove on handle_map
00542   _listInstances_map.erase(instanceName);
00543   _numInstanceMutex.unlock() ;
00544   component_i->destroy() ;
00545   if(_numproc == 0)
00546     _NS->Destroy_Name(instanceName.c_str());
00547 
00548   if(_numproc == 0){
00549     for(int ip=1;ip<_nbproc;ip++)
00550       pthread_join(th[ip],NULL);
00551     delete th;
00552   }
00553 
00554 }
00555 
00556 void Engines_MPIContainer_i::finalize_removal()
00557 {
00558   pthread_t *th;
00559   if(_numproc == 0){
00560     th = new pthread_t[_nbproc];
00561     for(int ip=1;ip<_nbproc;ip++){
00562       thread_st *st = new thread_st;
00563       st->ip = ip;
00564       st->tior = _tior;
00565       pthread_create(&(th[ip]),NULL,th_finalizeremoval,(void*)st);
00566     }
00567   }
00568 
00569   _numInstanceMutex.lock(); // lock to be alone
00570   // (see decInstanceCnt, load_component_Library)
00571   std::map<std::string, void *>::iterator ith;
00572   for (ith = _toRemove_map.begin(); ith != _toRemove_map.end(); ith++)
00573   {
00574     void *handle = (*ith).second;
00575     std::string impl_name= (*ith).first;
00576     if (handle)
00577     {
00578       SCRUTE(handle);
00579       SCRUTE(impl_name);
00580       //        dlclose(handle);                // SALOME unstable after ...
00581       //        _library_map.erase(impl_name);
00582     }
00583   }
00584   _toRemove_map.clear();
00585   _numInstanceMutex.unlock();
00586 
00587   if(_numproc == 0){
00588     for(int ip=1;ip<_nbproc;ip++)
00589       pthread_join(th[ip],NULL);
00590     delete th;
00591   }
00592 }
00593 
00594 void *th_loadcomponentlibrary(void *s)
00595 {
00596   thread_st *st = (thread_st*)s;
00597   char* reason;
00598   (Engines::MPIContainer::_narrow((*(st->tior))[st->ip]))->load_component_Library(st->compoName.c_str(),reason);
00599   CORBA::string_free(reason);
00600   return NULL;
00601 }
00602 
00603 void *th_createcomponentinstance(void *s)
00604 {
00605   thread_st *st = (thread_st*)s;
00606   (Engines::MPIContainer::_narrow((*(st->tior))[st->ip]))->create_component_instance(st->compoName.c_str(),st->studyId);
00607   return NULL;
00608 }
00609 
00610 void *th_loadimpl(void *s)
00611 {
00612   thread_st *st = (thread_st*)s;
00613   (Engines::MPIContainer::_narrow((*(st->tior))[st->ip]))->load_impl(st->nameToRegister.c_str(),st->compoName.c_str());
00614   return NULL;
00615 }
00616 
00617 void *th_removeimpl(void *s)
00618 {
00619   thread_st *st = (thread_st*)s;
00620   (Engines::MPIContainer::_narrow((*(st->tior))[st->ip]))->remove_impl(st->cptr);
00621   return NULL;
00622 }
00623 
00624 void *th_finalizeremoval(void *s)
00625 {
00626   thread_st *st = (thread_st*)s;
00627   (Engines::MPIContainer::_narrow((*(st->tior))[st->ip]))->finalize_removal();
00628   return NULL;
00629 }