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 : 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"
39 #include "utilities.h"
43 #include <sys/resource.h>
46 #include <sys/timeb.h>
53 extern bool _Sleeping ;
54 static Engines_Component_i * theEngines_Component ;
56 bool Engines_Component_i::_isMultiStudy = true;
57 bool Engines_Component_i::_isMultiInstance = false;
59 //=============================================================================
61 * Default constructor, not for use
63 //=============================================================================
65 Engines_Component_i::Engines_Component_i()
68 INFOS("Default Constructor...");
71 //=============================================================================
73 * Standard Constructor for generic Component, used in derived class
74 * Connection to Registry and Notification
75 * \param orb Object Request broker given by Container
76 * \param poa Portable Object Adapter from Container (normally root_poa)
77 * \param contId container CORBA id inside the server
78 * \param instanceName unique instance name for this object (see Container_i)
79 * \param interfaceName component class name
80 * \param notif use of notification
82 //=============================================================================
84 Engines_Component_i::Engines_Component_i(CORBA::ORB_ptr orb,
85 PortableServer::POA_ptr poa,
86 PortableServer::ObjectId * contId,
87 const char *instanceName,
88 const char *interfaceName,
90 _instanceName(instanceName),
91 _interfaceName(interfaceName),
92 _myConnexionToRegistry(0),
99 _CanceledThread(false)
101 MESSAGE("Component constructor with instanceName "<< _instanceName);
102 //SCRUTE(pd_refCount);
103 _orb = CORBA::ORB::_duplicate(orb);
104 _poa = PortableServer::POA::_duplicate(poa);
106 CORBA::Object_var o = _poa->id_to_reference(*contId); // container ior...
107 const CORBA::String_var ior = _orb->object_to_string(o);
108 _myConnexionToRegistry = new RegistryConnexion(0, 0, ior,"theSession",
109 _instanceName.c_str());
111 _notifSupplier = new NOTIFICATION_Supplier(instanceName, notif);
112 //SCRUTE(pd_refCount);
115 //=============================================================================
117 * Standard constructor for parallel component
118 * Connection Notification (no connection to Registry !)
119 * \param orb Object Request broker given by Container
120 * \param poa Portable Object Adapter from Container (normally root_poa)
121 * \param contId container CORBA id inside the server
122 * \param instanceName unique instance name for this object (see Container_i)
123 * \param interfaceName component class name
124 * \param flag not used...
125 * \param notif use of notification
127 //=============================================================================
129 Engines_Component_i::Engines_Component_i(CORBA::ORB_ptr orb,
130 PortableServer::POA_ptr poa,
131 PortableServer::ObjectId * contId,
132 const char *instanceName,
133 const char *interfaceName,
136 _instanceName(instanceName),
137 _interfaceName(interfaceName),
138 _myConnexionToRegistry(0),
145 _CanceledThread(false)
147 _orb = CORBA::ORB::_duplicate(orb);
148 _poa = PortableServer::POA::_duplicate(poa);
151 _notifSupplier = new NOTIFICATION_Supplier(instanceName, notif);
154 //=============================================================================
156 * Destructor: call Container for decrement of instances count.
157 * When instances count falls to 0, the container tries to remove the
158 * component library (dlclose)
160 //=============================================================================
162 Engines_Component_i::~Engines_Component_i()
164 MESSAGE("Component destructor");
165 Engines_Container_i::decInstanceCnt(_interfaceName);
168 //=============================================================================
170 * CORBA method: return name of the instance, unique in this Container
172 //=============================================================================
174 char* Engines_Component_i::instanceName()
176 return CORBA::string_dup(_instanceName.c_str()) ;
179 //=============================================================================
181 * CORBA method: return name of the component class
183 //=============================================================================
185 char* Engines_Component_i::interfaceName()
187 return CORBA::string_dup(_interfaceName.c_str()) ;
190 //=============================================================================
192 * CORBA method: Get study Id
193 * \return -1: not initialised (Internal Error)
194 * 0: multistudy component instance
195 * >0: study id associated to this instance
197 //=============================================================================
199 CORBA::Long Engines_Component_i::getStudyId()
204 //=============================================================================
206 * CORBA method: Test if instance is alive and responds
208 //=============================================================================
210 void Engines_Component_i::ping()
212 MESSAGE("Engines_Component_i::ping() pid "<< getpid() << " threadid "
216 //=============================================================================
218 * CORBA method: Deactivate this instance. CORBA object is deactivated (do not
219 * respond any more to CORBA calls), the connection to Regsitry is removed
220 * (Registry informed of deactivation), internal server reference counter on
221 * the derived servant class is decremented, to allow destruction of the class
222 * (delete) by POA, when there are no more references.
223 * -- TO BE USED BY CONTAINER ONLY (Container housekeeping) --
225 //=============================================================================
227 void Engines_Component_i::destroy()
229 MESSAGE("Engines_Component_i::destroy()");
230 //SCRUTE(pd_refCount);
232 delete _notifSupplier;
235 delete _myConnexionToRegistry;
236 _myConnexionToRegistry = 0 ;
237 _poa->deactivate_object(*_id) ;
238 CORBA::release(_poa) ;
240 //SCRUTE(pd_refCount);
241 _thisObj->_remove_ref();
242 //SCRUTE(pd_refCount);
243 MESSAGE("Engines_Component_i::destroyed") ;
246 //=============================================================================
248 * CORBA method: return CORBA reference of the Container
251 //=============================================================================
253 Engines::Container_ptr Engines_Component_i::GetContainerRef()
255 // MESSAGE("Engines_Component_i::GetContainerRef");
256 CORBA::Object_ptr o = _poa->id_to_reference(*_contId) ;
257 return Engines::Container::_narrow(o);
260 //=============================================================================
263 * Gives a sequence of (key=string,value=any) to the component.
264 * Base class component stores the sequence in a map.
265 * The map is cleared before.
266 * This map is for use by derived classes.
267 * \param dico sequence of (key=string,value=any)
269 //=============================================================================
271 void Engines_Component_i::setProperties(const Engines::FieldsDict& dico)
274 for (CORBA::ULong i=0; i<dico.length(); i++)
276 std::string cle(dico[i].key);
277 _fieldsDict[cle] = dico[i].value;
281 //=============================================================================
284 * returns a previously stored map (key=string,value=any) as a sequence.
285 * (see setProperties)
287 //=============================================================================
289 Engines::FieldsDict* Engines_Component_i::getProperties()
291 Engines::FieldsDict_var copie = new Engines::FieldsDict;
292 copie->length(_fieldsDict.size());
293 map<std::string,CORBA::Any>::iterator it;
295 for (it = _fieldsDict.begin(); it != _fieldsDict.end(); it++, i++)
297 std::string cle((*it).first);
298 copie[i].key = CORBA::string_dup(cle.c_str());
299 copie[i].value = _fieldsDict[cle];
301 return copie._retn();
304 //=============================================================================
306 * CORBA method: used by Supervision to give names to this instance
308 //=============================================================================
310 void Engines_Component_i::Names( const char * graphName ,
311 const char * nodeName )
313 _graphName = graphName ;
314 _nodeName = nodeName ;
315 // MESSAGE("Engines_Component_i::Names( '" << _graphName << "' , '"
316 // << _nodeName << "' )");
319 //=============================================================================
321 * CORBA method: used in Supervision
323 //=============================================================================
325 bool Engines_Component_i::Kill_impl()
327 // MESSAGE("Engines_Component_i::Kill_i() pthread_t "<< pthread_self()
328 // << " pid " << getpid() << " instanceName "
329 // << _instanceName.c_str() << " interface " << _interfaceName.c_str()
330 // << " machineName " << GetHostname().c_str()<< " _id " << hex << _id
331 // << dec << " _ThreadId " << _ThreadId << " this " << hex << this
334 bool RetVal = false ;
336 if ( _ThreadId > 0 && pthread_self() != _ThreadId )
338 RetVal = Killer( _ThreadId , SIGUSR2 ) ;
339 _ThreadId = (pthread_t ) -1 ;
343 if ( _ThreadId > 0 && pthread_self().p != _ThreadId->p )
345 RetVal = Killer( *_ThreadId , 0 ) ;
346 _ThreadId = (pthread_t* ) 0 ;
353 //=============================================================================
355 * CORBA method: used in Supervision
357 //=============================================================================
359 bool Engines_Component_i::Stop_impl()
361 MESSAGE("Engines_Component_i::Stop_i() pthread_t "<< pthread_self()
362 << " pid " << getpid() << " instanceName "
363 << _instanceName.c_str() << " interface " << _interfaceName.c_str()
364 << " machineName " << GetHostname().c_str()<< " _id " << hex << _id
365 << dec << " _ThreadId " << _ThreadId );
368 bool RetVal = false ;
370 if ( _ThreadId > 0 && pthread_self() != _ThreadId )
372 RetVal = Killer( _ThreadId , 0 ) ;
373 _ThreadId = (pthread_t ) -1 ;
376 if ( _ThreadId > 0 && pthread_self().p != _ThreadId->p )
378 RetVal = Killer( *_ThreadId , 0 ) ;
379 _ThreadId = (pthread_t* ) 0 ;
385 //=============================================================================
387 * CORBA method: used in Supervision
389 //=============================================================================
391 bool Engines_Component_i::Suspend_impl()
393 MESSAGE("Engines_Component_i::Suspend_i() pthread_t "<< pthread_self()
394 << " pid " << getpid() << " instanceName "
395 << _instanceName.c_str() << " interface " << _interfaceName.c_str()
396 << " machineName " << GetHostname().c_str()<< " _id " << hex << _id
397 << dec << " _ThreadId " << _ThreadId );
399 bool RetVal = false ;
401 if ( _ThreadId > 0 && pthread_self() != _ThreadId )
403 if ( _ThreadId > 0 && pthread_self().p != _ThreadId->p )
413 RetVal = Killer( _ThreadId ,SIGINT ) ;
415 RetVal = Killer( *_ThreadId ,SIGINT ) ;
417 //if ( RetVal ) _Sleeping = true;
424 //=============================================================================
426 * CORBA method: used in Supervision
428 //=============================================================================
430 bool Engines_Component_i::Resume_impl()
432 MESSAGE("Engines_Component_i::Resume_i() pthread_t "<< pthread_self()
433 << " pid " << getpid() << " instanceName "
434 << _instanceName.c_str() << " interface " << _interfaceName.c_str()
435 << " machineName " << GetHostname().c_str()<< " _id " << hex << _id
436 << dec << " _ThreadId " << _ThreadId );
437 bool RetVal = false ;
439 if ( _ThreadId > 0 && pthread_self() != _ThreadId )
441 if ( _ThreadId > 0 && pthread_self().p != _ThreadId->p )
457 //=============================================================================
461 //=============================================================================
463 CORBA::Long Engines_Component_i::CpuUsed_impl()
466 if ( _ThreadId || _Executed )
471 if ( pthread_self() != _ThreadId )
473 if ( pthread_self().p != _ThreadId->p )
481 // Get Cpu in the appropriate thread with that object !...
482 theEngines_Component = this ;
484 Killer( _ThreadId ,SIGUSR1 ) ;
486 Killer( *_ThreadId ,SIGUSR11 ) ;
489 cpu = _ThreadCpuUsed ;
493 _ThreadCpuUsed = CpuUsed() ;
494 cpu = _ThreadCpuUsed ;
495 // cout << pthread_self() << " Engines_Component_i::CpuUsed_impl "
496 // << _serviceName << " " << cpu << endl ;
501 cpu = _ThreadCpuUsed ;
502 // cout << pthread_self() << " Engines_Component_i::CpuUsed_impl "
503 // << _serviceName << " " << cpu<< endl ;
508 // cout<< pthread_self()<<"Engines_Component_i::CpuUsed_impl _ThreadId "
509 // <<_ThreadId <<" "<<_serviceName<<" _StartUsed "<<_StartUsed<<endl;
515 //=============================================================================
517 * C++ method: return Container Servant
519 //=============================================================================
521 Engines_Container_i *Engines_Component_i::GetContainerPtr()
523 return dynamic_cast<Engines_Container_i*>(_poa->id_to_servant(*_contId)) ;
526 //=============================================================================
528 * C++ method: set study Id
529 * \param studyId 0 if instance is not associated to a study,
530 * >0 otherwise (== study id)
531 * \return true if the set of study Id is OK
532 * must be set once by Container, at instance creation,
533 * and cannot be changed after.
535 //=============================================================================
537 CORBA::Boolean Engines_Component_i::setStudyId(CORBA::Long studyId)
539 ASSERT( studyId >= 0);
540 CORBA::Boolean ret = false;
541 if (_studyId < 0) // --- not yet initialized
547 if ( _studyId == studyId) ret = true;
551 //=============================================================================
553 * C++ method: return CORBA instance id, the id is set in derived class
554 * constructor, when instance is activated.
556 //=============================================================================
558 PortableServer::ObjectId * Engines_Component_i::getId()
560 // MESSAGE("PortableServer::ObjectId * Engines_Component_i::getId()");
564 //=============================================================================
566 * C++ method: used by derived classes for supervision
568 //=============================================================================
570 void Engines_Component_i::beginService(const char *serviceName)
572 MESSAGE(pthread_self() << "Send BeginService notification for " <<serviceName
573 << endl << "Component instance : " << _instanceName << endl << endl);
575 _ThreadId = pthread_self() ;
577 _ThreadId = new pthread_t;
578 _ThreadId->p = pthread_self().p ;
579 _ThreadId->x = pthread_self().x ;
582 _StartUsed = CpuUsed_impl() ;
585 _serviceName = serviceName ;
586 theEngines_Component = this ;
587 if ( pthread_setcanceltype( PTHREAD_CANCEL_ASYNCHRONOUS , NULL ) )
589 perror("pthread_setcanceltype ") ;
592 if ( pthread_setcancelstate( PTHREAD_CANCEL_ENABLE , NULL ) )
594 perror("pthread_setcancelstate ") ;
597 // MESSAGE(pthread_self() << " Return from BeginService for " << serviceName
598 // << " ThreadId " << _ThreadId << " StartUsed " << _StartUsed
599 // << " _graphName " << _graphName << " _nodeName " << _nodeName );
601 // --- for supervisor : all strings given with setProperties
602 // are set in environment
603 bool overwrite = true;
604 map<std::string,CORBA::Any>::iterator it;
605 for (it = _fieldsDict.begin(); it != _fieldsDict.end(); it++)
607 std::string cle((*it).first);
608 if ((*it).second.type()->kind() == CORBA::tk_string)
611 (*it).second >>= value;
612 // ---todo: replace __GNUC__ test by an autoconf macro AC_CHECK_FUNC.
614 int ret = setenv(cle.c_str(), value, overwrite);
616 //CCRT porting : setenv not defined in stdlib.h
620 // char* cast because 1st arg of linux putenv function
621 // is not a const char* !
622 int ret=putenv((char *)s.c_str());
623 //End of CCRT porting
625 MESSAGE("--- setenv: "<<cle<<" = "<< value);
630 //=============================================================================
632 * C++ method: used by derived classes for supervision
634 //=============================================================================
636 void Engines_Component_i::endService(const char *serviceName)
638 if ( !_CanceledThread )
639 _ThreadCpuUsed = CpuUsed_impl() ;
640 MESSAGE(pthread_self() << " Send EndService notification for " << serviceName
641 << endl << " Component instance : " << _instanceName << " StartUsed "
642 << _StartUsed << " _ThreadCpuUsed "<< _ThreadCpuUsed << endl <<endl);
646 //=============================================================================
648 * C++ method: -- CHECK IF USED --
650 //=============================================================================
652 char* Engines_Component_i::graphName()
654 return CORBA::string_dup( _graphName.c_str() ) ;
657 //=============================================================================
659 * C++ method: -- CHECK IF USED --
661 //=============================================================================
663 char* Engines_Component_i::nodeName()
665 return CORBA::string_dup( _nodeName.c_str() ) ;
668 //=============================================================================
670 * C++ method: used in Supervision (see kill_impl)
672 //=============================================================================
674 bool Engines_Component_i::Killer( pthread_t ThreadId , int signum )
684 if ( pthread_cancel( ThreadId ) )
686 perror("Killer pthread_cancel error") ;
691 MESSAGE(pthread_self() << "Killer : ThreadId " << ThreadId
692 << " pthread_canceled") ;
697 if ( pthread_kill( ThreadId , signum ) == -1 )
699 perror("Killer pthread_kill error") ;
704 MESSAGE(pthread_self() << "Killer : ThreadId " << ThreadId
705 << " pthread_killed(" << signum << ")") ;
712 //=============================================================================
716 //=============================================================================
720 if ( theEngines_Component )
721 theEngines_Component->SetCurCpu() ;
724 //=============================================================================
728 //=============================================================================
730 void Engines_Component_i::SetCurCpu()
732 _ThreadCpuUsed = CpuUsed() ;
733 // MESSAGE(pthread_self() <<
734 // " Engines_Component_i::SetCurCpu() _ThreadCpuUsed " << _ThreadCpuUsed) ;
737 //=============================================================================
741 //=============================================================================
743 long Engines_Component_i::CpuUsed()
747 struct rusage usage ;
748 if ( _ThreadId || _Executed )
750 if ( getrusage( RUSAGE_SELF , &usage ) == -1 )
752 perror("Engines_Component_i::CpuUsed") ;
755 cpu = usage.ru_utime.tv_sec - _StartUsed ;
756 // cout << pthread_self() << " Engines_Component_i::CpuUsed " << " "
757 // << _serviceName << usage.ru_utime.tv_sec << " - " << _StartUsed
758 // << " = " << cpu << endl ;
762 // cout << pthread_self() << "Engines_Component_i::CpuUsed _ThreadId "
763 // << _ThreadId << " " << _serviceName<< " _StartUsed "
764 // << _StartUsed << endl ;
767 // NOT implementet yet
774 void CallCancelThread()
776 if ( theEngines_Component )
777 theEngines_Component->CancelThread() ;
780 //=============================================================================
784 //=============================================================================
786 void Engines_Component_i::CancelThread()
788 _CanceledThread = true;
791 //=============================================================================
793 * C++ method: Send message to event channel
795 //=============================================================================
797 void Engines_Component_i::sendMessage(const char *event_type,
800 _notifSupplier->Send(graphName(), nodeName(), event_type, message);
803 //=============================================================================
805 * C++ method: return standard library name built on component name
807 //=============================================================================
809 string Engines_Component_i::GetDynLibraryName(const char *componentName)
817 //=============================================================================
819 * C++ method: DumpPython default implementation
821 //=============================================================================
823 Engines::TMPFile* Engines_Component_i::DumpPython(CORBA::Object_ptr theStudy,
824 CORBA::Boolean isPublished,
825 CORBA::Boolean& isValidScript)
827 char* aScript = "def RebuildData(theStudy): pass";
828 char* aBuffer = new char[strlen(aScript)+1];
829 strcpy(aBuffer, aScript);
830 CORBA::Octet* anOctetBuf = (CORBA::Octet*)aBuffer;
831 int aBufferSize = strlen(aBuffer)+1;
832 Engines::TMPFile_var aStreamFile = new Engines::TMPFile(aBufferSize, aBufferSize, anOctetBuf, 1);
833 isValidScript = true;
834 return aStreamFile._retn();