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.opencascade.org/SALOME/ or email : webmaster.salome@opencascade.org
24 // File : Component_i.cxx
25 // Author : Paul RASCLE, EDF - MARC TAJCHMAN, CEA
29 //#define private protected // for pd_refCount trace
30 #include "SALOME_Component_i.hxx"
31 #include "SALOME_Container_i.hxx"
32 #include "RegistryConnexion.hxx"
37 #include "utilities.h"
40 #include <sys/resource.h>
45 extern bool _Sleeping ;
46 static Engines_Component_i * theEngines_Component ;
48 bool Engines_Component_i::_isMultiStudy = true;
49 bool Engines_Component_i::_isMultiInstance = false;
51 //=============================================================================
53 * Default constructor, not for use
55 //=============================================================================
57 Engines_Component_i::Engines_Component_i()
60 INFOS("Default Constructor...");
63 //=============================================================================
65 * Standard Constructor for generic Component, used in derived class
66 * Connection to Registry and Notification
67 * \param orb Object Request broker given by Container
68 * \parap poa Portable Object Adapter from Container (normally root_poa)
69 * \param contId container CORBA id inside the server
70 * \param instanceName unique instance name for this object (see Container_i)
71 * \param interfaceName component class name
72 * \param notif use of notification
74 //=============================================================================
76 Engines_Component_i::Engines_Component_i(CORBA::ORB_ptr orb,
77 PortableServer::POA_ptr poa,
78 PortableServer::ObjectId * contId,
79 const char *instanceName,
80 const char *interfaceName,
82 _instanceName(instanceName),
83 _interfaceName(interfaceName),
84 _myConnexionToRegistry(0),
92 MESSAGE("Component constructor with instanceName "<< _instanceName);
93 //SCRUTE(pd_refCount);
94 _orb = CORBA::ORB::_duplicate(orb);
95 _poa = PortableServer::POA::_duplicate(poa);
97 CORBA::Object_var o = _poa->id_to_reference(*contId); // container ior...
98 const CORBA::String_var ior = _orb->object_to_string(o);
99 _myConnexionToRegistry = new RegistryConnexion(0, 0, ior,"theSession",
100 _instanceName.c_str());
102 _notifSupplier = new NOTIFICATION_Supplier(instanceName, notif);
103 //SCRUTE(pd_refCount);
106 //=============================================================================
108 * Standard constructor for parallel component
109 * Connection Notification (no connection to Registry !)
110 * \param orb Object Request broker given by Container
111 * \parap poa Portable Object Adapter from Container (normally root_poa)
112 * \param contId container CORBA id inside the server
113 * \param instanceName unique instance name for this object (see Container_i)
114 * \param interfaceName component class name
115 * \param flag not used...
116 * \param notif use of notification
118 //=============================================================================
120 Engines_Component_i::Engines_Component_i(CORBA::ORB_ptr orb,
121 PortableServer::POA_ptr poa,
122 PortableServer::ObjectId * contId,
123 const char *instanceName,
124 const char *interfaceName,
127 _instanceName(instanceName),
128 _interfaceName(interfaceName),
129 _myConnexionToRegistry(0),
137 _orb = CORBA::ORB::_duplicate(orb);
138 _poa = PortableServer::POA::_duplicate(poa);
141 _notifSupplier = new NOTIFICATION_Supplier(instanceName, notif);
144 //=============================================================================
146 * Destructor: call Container for decrement of instances count.
147 * When instances count falls to 0, the container tries to remove the
148 * component library (dlclose)
150 //=============================================================================
152 Engines_Component_i::~Engines_Component_i()
154 MESSAGE("Component destructor");
155 Engines_Container_i::decInstanceCnt(_interfaceName);
158 //=============================================================================
160 * CORBA method: return name of the instance, unique in this Container
162 //=============================================================================
164 char* Engines_Component_i::instanceName()
166 return CORBA::string_dup(_instanceName.c_str()) ;
169 //=============================================================================
171 * CORBA method: return name of the component class
173 //=============================================================================
175 char* Engines_Component_i::interfaceName()
177 return CORBA::string_dup(_interfaceName.c_str()) ;
180 //=============================================================================
182 * CORBA method: Get study Id
183 * \return -1: not initialised (Internal Error)
184 * 0: multistudy component instance
185 * >0: study id associated to this instance
187 //=============================================================================
189 CORBA::Long Engines_Component_i::getStudyId()
194 //=============================================================================
196 * CORBA method: Test if instance is alive and responds
198 //=============================================================================
200 void Engines_Component_i::ping()
202 MESSAGE("Engines_Component_i::ping() pid "<< getpid() << " threadid "
206 //=============================================================================
208 * CORBA method: Deactivate this instance. CORBA object is deactivated (do not
209 * respond any more to CORBA calls), the connection to Regsitry is removed
210 * (Registry informed of deactivation), internal server reference counter on
211 * the derived servant class is decremented, to allow destruction of the class
212 * (delete) by POA, when there are no more references.
213 * -- TO BE USED BY CONTAINER ONLY (Container housekeeping) --
215 //=============================================================================
217 void Engines_Component_i::destroy()
219 MESSAGE("Engines_Component_i::destroy()");
220 //SCRUTE(pd_refCount);
222 delete _notifSupplier;
225 delete _myConnexionToRegistry;
226 _myConnexionToRegistry = 0 ;
227 _poa->deactivate_object(*_id) ;
228 CORBA::release(_poa) ;
230 //SCRUTE(pd_refCount);
231 _thisObj->_remove_ref();
232 //SCRUTE(pd_refCount);
233 MESSAGE("Engines_Component_i::destroyed") ;
236 //=============================================================================
238 * CORBA method: return CORBA reference of the Container
241 //=============================================================================
243 Engines::Container_ptr Engines_Component_i::GetContainerRef()
245 MESSAGE("Engines_Component_i::GetContainerRef");
246 CORBA::Object_ptr o = _poa->id_to_reference(*_contId) ;
247 return Engines::Container::_narrow(o);
250 //=============================================================================
253 * Gives a sequence of (key=string,value=any) to the component.
254 * Base class component stores the sequence in a map.
255 * The map is cleared before.
256 * This map is for use by derived classes.
257 * \param dico sequence of (key=string,value=any)
259 //=============================================================================
261 void Engines_Component_i::setProperties(const Engines::FieldsDict& dico)
264 for (CORBA::ULong i=0; i<dico.length(); i++)
266 std::string cle(dico[i].key);
267 _fieldsDict[cle] = dico[i].value;
271 //=============================================================================
274 * returns a previously stored map (key=string,value=any) as a sequence.
275 * (see setProperties)
277 //=============================================================================
279 Engines::FieldsDict* Engines_Component_i::getProperties()
281 Engines::FieldsDict_var copie = new Engines::FieldsDict;
282 copie->length(_fieldsDict.size());
283 map<std::string,CORBA::Any>::iterator it;
285 for (it = _fieldsDict.begin(); it != _fieldsDict.end(); it++, i++)
287 std::string cle((*it).first);
288 copie[i].key = CORBA::string_dup(cle.c_str());
289 copie[i].value = _fieldsDict[cle];
291 return copie._retn();
294 //=============================================================================
296 * CORBA method: used by Supervision to give names to this instance
298 //=============================================================================
300 void Engines_Component_i::Names( const char * graphName ,
301 const char * nodeName )
303 _graphName = graphName ;
304 _nodeName = nodeName ;
305 // MESSAGE("Engines_Component_i::Names( '" << _graphName << "' , '"
306 // << _nodeName << "' )");
309 //=============================================================================
311 * CORBA method: used in Supervision
313 //=============================================================================
315 bool Engines_Component_i::Kill_impl()
317 // MESSAGE("Engines_Component_i::Kill_i() pthread_t "<< pthread_self()
318 // << " pid " << getpid() << " instanceName "
319 // << _instanceName.c_str() << " interface " << _interfaceName.c_str()
320 // << " machineName " << GetHostname().c_str()<< " _id " << hex << _id
321 // << dec << " _ThreadId " << _ThreadId << " this " << hex << this
324 bool RetVal = false ;
325 if ( _ThreadId > 0 && pthread_self() != _ThreadId )
327 RetVal = Killer( _ThreadId , 0 ) ;
328 _ThreadId = (pthread_t ) -1 ;
333 //=============================================================================
335 * CORBA method: used in Supervision
337 //=============================================================================
339 bool Engines_Component_i::Stop_impl()
341 MESSAGE("Engines_Component_i::Stop_i() pthread_t "<< pthread_self()
342 << " pid " << getpid() << " instanceName "
343 << _instanceName.c_str() << " interface " << _interfaceName.c_str()
344 << " machineName " << GetHostname().c_str()<< " _id " << hex << _id
345 << dec << " _ThreadId " << _ThreadId );
348 bool RetVal = false ;
349 if ( _ThreadId > 0 && pthread_self() != _ThreadId )
351 RetVal = Killer( _ThreadId , 0 ) ;
352 _ThreadId = (pthread_t ) -1 ;
357 //=============================================================================
359 * CORBA method: used in Supervision
361 //=============================================================================
363 bool Engines_Component_i::Suspend_impl()
365 MESSAGE("Engines_Component_i::Suspend_i() pthread_t "<< pthread_self()
366 << " pid " << getpid() << " instanceName "
367 << _instanceName.c_str() << " interface " << _interfaceName.c_str()
368 << " machineName " << GetHostname().c_str()<< " _id " << hex << _id
369 << dec << " _ThreadId " << _ThreadId );
371 bool RetVal = false ;
372 if ( _ThreadId > 0 && pthread_self() != _ThreadId )
380 RetVal = Killer( _ThreadId ,SIGINT ) ;
386 //=============================================================================
388 * CORBA method: used in Supervision
390 //=============================================================================
392 bool Engines_Component_i::Resume_impl()
394 MESSAGE("Engines_Component_i::Resume_i() pthread_t "<< pthread_self()
395 << " pid " << getpid() << " instanceName "
396 << _instanceName.c_str() << " interface " << _interfaceName.c_str()
397 << " machineName " << GetHostname().c_str()<< " _id " << hex << _id
398 << dec << " _ThreadId " << _ThreadId );
399 bool RetVal = false ;
400 if ( _ThreadId > 0 && pthread_self() != _ThreadId )
415 //=============================================================================
419 //=============================================================================
421 CORBA::Long Engines_Component_i::CpuUsed_impl()
424 if ( _ThreadId || _Executed )
428 if ( pthread_self() != _ThreadId )
435 // Get Cpu in the appropriate thread with that object !...
436 theEngines_Component = this ;
437 Killer( _ThreadId ,SIGUSR1 ) ;
439 cpu = _ThreadCpuUsed ;
443 _ThreadCpuUsed = CpuUsed() ;
444 cpu = _ThreadCpuUsed ;
445 // cout << pthread_self() << " Engines_Component_i::CpuUsed_impl "
446 // << _serviceName << " " << cpu << endl ;
451 cpu = _ThreadCpuUsed ;
452 // cout << pthread_self() << " Engines_Component_i::CpuUsed_impl "
453 // << _serviceName << " " << cpu<< endl ;
458 // cout<< pthread_self()<<"Engines_Component_i::CpuUsed_impl _ThreadId "
459 // <<_ThreadId <<" "<<_serviceName<<" _StartUsed "<<_StartUsed<<endl;
464 //=============================================================================
466 * C++ method: set study Id
467 * \param studyId 0 if instance is not associated to a study,
468 * >0 otherwise (== study id)
469 * \return true if the set of study Id is OK
470 * must be set once by Container, and cannot be changed after.
472 //=============================================================================
474 CORBA::Boolean Engines_Component_i::setStudyId(CORBA::Long studyId)
476 ASSERT( studyId >= 0);
477 CORBA::Boolean ret = false;
484 if ( _studyId == studyId) ret = true;
488 //=============================================================================
490 * C++ method: return CORBA instance id, the id is set in derived class
491 * constructor, when instance is activated.
493 //=============================================================================
495 PortableServer::ObjectId * Engines_Component_i::getId()
497 // MESSAGE("PortableServer::ObjectId * Engines_Component_i::getId()");
501 //=============================================================================
503 * C++ method: used by derived classes for supervision
505 //=============================================================================
507 void Engines_Component_i::beginService(const char *serviceName)
509 MESSAGE(pthread_self() << "Send BeginService notification for " <<serviceName
510 << endl << "Component instance : " << _instanceName << endl << endl);
511 _ThreadId = pthread_self() ;
513 _StartUsed = CpuUsed_impl() ;
516 _serviceName = serviceName ;
517 if ( pthread_setcanceltype( PTHREAD_CANCEL_ASYNCHRONOUS , NULL ) )
519 perror("pthread_setcanceltype ") ;
522 if ( pthread_setcancelstate( PTHREAD_CANCEL_ENABLE , NULL ) )
524 perror("pthread_setcancelstate ") ;
527 // MESSAGE(pthread_self() << " Return from BeginService for " << serviceName
528 // << " ThreadId " << _ThreadId << " StartUsed " << _StartUsed
529 // << " _graphName " << _graphName << " _nodeName " << _nodeName );
531 // --- for supervisor : all strings given with setProperties
532 // are set in environment
533 bool overwrite = true;
534 map<std::string,CORBA::Any>::iterator it;
535 for (it = _fieldsDict.begin(); it != _fieldsDict.end(); it++)
537 std::string cle((*it).first);
538 if ((*it).second.type()->kind() == CORBA::tk_string)
541 (*it).second >>= value;
542 // ---todo: replace __GNUC__ test by an autoconf macro AC_CHECK_FUNC.
544 int ret = setenv(cle.c_str(), value, overwrite);
546 //CCRT porting : setenv not defined in stdlib.h
550 // char* cast because 1st arg of linux putenv function
551 // is not a const char* !
552 int ret=putenv((char *)s.c_str());
553 //End of CCRT porting
555 MESSAGE("--- setenv: "<<cle<<" = "<< value);
560 //=============================================================================
562 * C++ method: used by derived classes for supervision
564 //=============================================================================
566 void Engines_Component_i::endService(const char *serviceName)
568 _ThreadCpuUsed = CpuUsed_impl() ;
569 MESSAGE(pthread_self() << " Send EndService notification for " << serviceName
570 << endl << " Component instance : " << _instanceName << " StartUsed "
571 << _StartUsed << " _ThreadCpuUsed "<< _ThreadCpuUsed << endl <<endl);
575 //=============================================================================
577 * C++ method: -- CHECK IF USED --
579 //=============================================================================
581 char* Engines_Component_i::graphName()
583 return CORBA::string_dup( _graphName.c_str() ) ;
586 //=============================================================================
588 * C++ method: -- CHECK IF USED --
590 //=============================================================================
592 char* Engines_Component_i::nodeName()
594 return CORBA::string_dup( _nodeName.c_str() ) ;
597 //=============================================================================
599 * C++ method: used in Supervision (see kill_impl)
601 //=============================================================================
603 bool Engines_Component_i::Killer( pthread_t ThreadId , int signum )
609 if ( pthread_cancel( ThreadId ) )
611 perror("Killer pthread_cancel error") ;
616 MESSAGE(pthread_self() << "Killer : ThreadId " << ThreadId
617 << " pthread_canceled") ;
622 if ( pthread_kill( ThreadId , signum ) == -1 )
624 perror("Killer pthread_kill error") ;
629 MESSAGE(pthread_self() << "Killer : ThreadId " << ThreadId
630 << " pthread_killed(" << signum << ")") ;
637 //=============================================================================
641 //=============================================================================
645 theEngines_Component->SetCurCpu() ;
648 //=============================================================================
652 //=============================================================================
654 void Engines_Component_i::SetCurCpu()
656 _ThreadCpuUsed = CpuUsed() ;
657 // MESSAGE(pthread_self() <<
658 // " Engines_Component_i::SetCurCpu() _ThreadCpuUsed " << _ThreadCpuUsed) ;
661 //=============================================================================
665 //=============================================================================
667 long Engines_Component_i::CpuUsed()
670 struct rusage usage ;
671 if ( _ThreadId || _Executed )
673 if ( getrusage( RUSAGE_SELF , &usage ) == -1 )
675 perror("Engines_Component_i::CpuUsed") ;
678 cpu = usage.ru_utime.tv_sec - _StartUsed ;
679 // cout << pthread_self() << " Engines_Component_i::CpuUsed " << " "
680 // << _serviceName << usage.ru_utime.tv_sec << " - " << _StartUsed
681 // << " = " << cpu << endl ;
685 // cout << pthread_self() << "Engines_Component_i::CpuUsed _ThreadId "
686 // << _ThreadId << " " << _serviceName<< " _StartUsed "
687 // << _StartUsed << endl ;
692 //=============================================================================
694 * C++ method: Send message to event channel
696 //=============================================================================
698 void Engines_Component_i::sendMessage(const char *event_type,
701 _notifSupplier->Send(graphName(), nodeName(), event_type, message);
704 //=============================================================================
708 //=============================================================================
710 string Engines_Component_i::GetDynLibraryName(const char *componentName)
718 //=============================================================================
722 //=============================================================================
724 string Engines_Component_i::BuildComponentNameForNS(const char *ComponentName,
725 const char *ContainerName,
726 const char *hostname)
729 Engines_Container_i::BuildContainerNameForNS(ContainerName,hostname);
734 //=============================================================================
736 * C++ method: DumpPython default implementation
738 //=============================================================================
740 Engines::TMPFile* Engines_Component_i::DumpPython(CORBA::Object_ptr theStudy,
741 CORBA::Boolean isPublished,
742 CORBA::Boolean& isValidScript)
744 char* aScript = "def RebuildData(theStudy): pass";
745 char* aBuffer = new char[strlen(aScript)+1];
746 strcpy(aBuffer, aScript);
747 CORBA::Octet* anOctetBuf = (CORBA::Octet*)aBuffer;
748 int aBufferSize = strlen(aBuffer)+1;
749 Engines::TMPFile_var aStreamFile = new Engines::TMPFile(aBufferSize, aBufferSize, anOctetBuf, 1);
750 isValidScript = true;
751 return aStreamFile._retn();