]> SALOME platform Git repositories - modules/kernel.git/blob - src/Container/Component_i.cxx
Salome HOME
PR: embedded container C++ & Python, debug
[modules/kernel.git] / src / Container / Component_i.cxx
1 //  SALOME Container : implementation of container and engine for Kernel
2 //
3 //  Copyright (C) 2003  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 //  CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS 
5 // 
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. 
10 // 
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. 
15 // 
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 
19 // 
20 //  See http://www.opencascade.org/SALOME/ or email : webmaster.salome@opencascade.org 
21 //
22 //
23 //
24 //  File   : Component_i.cxx
25 //  Author : Paul RASCLE, EDF - MARC TAJCHMAN, CEA
26 //  Module : SALOME
27 //  $Header$
28
29 //#define private protected  // for pd_refCount trace
30 #include "SALOME_Component_i.hxx"
31 #include "SALOME_Container_i.hxx"
32 #include "RegistryConnexion.hxx"
33 #include "OpUtil.hxx"
34 #include <stdio.h>
35 #include <dlfcn.h>
36 #include <cstdlib>
37 #include "utilities.h"
38
39 #include <sys/time.h>
40 #include <sys/resource.h>
41 #include <unistd.h>
42
43 using namespace std;
44
45 extern bool _Sleeping ;
46 static Engines_Component_i * theEngines_Component ;
47
48 bool Engines_Component_i::_isMultiStudy = true;
49 bool Engines_Component_i::_isMultiInstance = false;
50
51 //=============================================================================
52 /*! 
53  *  Default constructor, not for use
54  */
55 //=============================================================================
56
57 Engines_Component_i::Engines_Component_i()
58 {
59   ASSERT(0);
60 }
61
62 //=============================================================================
63 /*! 
64  *  Standard Constructor for generic Component, used in derived class
65  *  Connection to Registry and Notification
66  *  \param orb Object Request broker given by Container
67  *  \parap poa Portable Object Adapter from Container (normally root_poa)
68  *  \param contId container CORBA id inside the server
69  *  \param instanceName unique instance name for this object (see Container_i)
70  *  \param interfaceName component class name
71  *  \param notif use of notification
72  */
73 //=============================================================================
74
75 Engines_Component_i::Engines_Component_i(CORBA::ORB_ptr orb,
76                                          PortableServer::POA_ptr poa, 
77                                          PortableServer::ObjectId * contId, 
78                                          const char *instanceName,
79                                          const char *interfaceName,
80                                          bool notif) :
81   _instanceName(instanceName),
82   _interfaceName(interfaceName),
83   _myConnexionToRegistry(0),
84   _ThreadId(0) ,
85   _ThreadCpuUsed(0) ,
86   _Executed(false) ,
87   _graphName("") ,
88   _nodeName(""),
89  _studyId(-1)
90 {
91   MESSAGE("Component constructor with instanceName "<< _instanceName);
92   //SCRUTE(pd_refCount);
93   _orb = CORBA::ORB::_duplicate(orb);
94   _poa = PortableServer::POA::_duplicate(poa);
95   _contId = contId ;
96   CORBA::Object_var o = _poa->id_to_reference(*contId); // container ior...
97   const CORBA::String_var ior = _orb->object_to_string(o);
98   _myConnexionToRegistry = new RegistryConnexion(0, 0, ior,"theSession",
99                                                  _instanceName.c_str());
100
101   _notifSupplier = new NOTIFICATION_Supplier(instanceName, notif);
102   //SCRUTE(pd_refCount);
103 }
104
105 //=============================================================================
106 /*! 
107  * Standard constructor for parallel component
108  *  Connection Notification (no connection to Registry !)
109  *  \param orb Object Request broker given by Container
110  *  \parap poa Portable Object Adapter from Container (normally root_poa)
111  *  \param contId container CORBA id inside the server
112  *  \param instanceName unique instance name for this object (see Container_i)
113  *  \param interfaceName component class name
114  *  \param flag not used...
115  *  \param notif use of notification
116  */
117 //=============================================================================
118
119 Engines_Component_i::Engines_Component_i(CORBA::ORB_ptr orb,
120                                          PortableServer::POA_ptr poa, 
121                                          PortableServer::ObjectId * contId, 
122                                          const char *instanceName,
123                                          const char *interfaceName,
124                                          int flag,
125                                          bool notif ) :
126  _instanceName(instanceName),
127  _interfaceName(interfaceName),
128  _myConnexionToRegistry(0),
129  _ThreadId(0) ,
130  _ThreadCpuUsed(0) ,
131  _Executed(false) ,
132  _graphName("") ,
133  _nodeName(""),
134  _studyId(-1)
135 {
136   _orb = CORBA::ORB::_duplicate(orb);
137   _poa = PortableServer::POA::_duplicate(poa);
138   _contId = contId ;
139
140   _notifSupplier = new NOTIFICATION_Supplier(instanceName, notif);
141 }
142
143 //=============================================================================
144 /*! 
145  *  Destructor: call Container for decrement of instances count.
146  *  When instances count falls to 0, the container tries to remove the
147  *  component library (dlclose)
148  */
149 //=============================================================================
150
151 Engines_Component_i::~Engines_Component_i()
152 {
153   MESSAGE("Component destructor");
154   Engines_Container_i::decInstanceCnt(_interfaceName);
155 }
156
157 //=============================================================================
158 /*! 
159  *  CORBA method: return name of the instance, unique in this Container
160  */
161 //=============================================================================
162
163 char* Engines_Component_i::instanceName()
164 {
165    return CORBA::string_dup(_instanceName.c_str()) ;
166 }
167
168 //=============================================================================
169 /*! 
170  *  CORBA method: return name of the component class
171  */
172 //=============================================================================
173
174 char* Engines_Component_i::interfaceName()
175 {
176   return CORBA::string_dup(_interfaceName.c_str()) ;
177 }
178
179 //=============================================================================
180 /*! 
181  *  CORBA method: Get study Id
182  *  \return -1: not initialised (Internal Error)
183  *           0: multistudy component instance
184  *          >0: study id associated to this instance
185  */
186 //=============================================================================
187
188 CORBA::Long Engines_Component_i::getStudyId()
189 {
190   return _studyId;
191 }
192
193 //=============================================================================
194 /*! 
195  *  CORBA method: Test if instance is alive and responds
196  */
197 //=============================================================================
198
199 void Engines_Component_i::ping()
200 {
201   MESSAGE("Engines_Component_i::ping() pid "<< getpid() << " threadid "
202           << pthread_self());
203 }
204
205 //=============================================================================
206 /*! 
207  *  CORBA method: Deactivate this instance. CORBA object is deactivated (do not
208  *  respond any more to CORBA calls), the connection to Regsitry is removed
209  *  (Registry informed of deactivation), internal server reference counter on
210  *  the derived servant class is decremented, to allow destruction of the class
211  *  (delete) by POA, when there are no more references.
212  *  -- TO BE USED BY CONTAINER ONLY (Container housekeeping) --
213  */
214 //=============================================================================
215
216 void Engines_Component_i::destroy()
217 {
218   MESSAGE("Engines_Component_i::destroy()");
219   //SCRUTE(pd_refCount);
220
221   delete _notifSupplier;
222   _notifSupplier = 0;
223
224   delete _myConnexionToRegistry;
225   _myConnexionToRegistry = 0 ;
226   _poa->deactivate_object(*_id) ;
227   CORBA::release(_poa) ;
228   delete(_id) ;
229   //SCRUTE(pd_refCount);
230   _thisObj->_remove_ref();
231   //SCRUTE(pd_refCount);
232   MESSAGE("Engines_Component_i::destroyed") ;
233 }
234
235 //=============================================================================
236 /*! 
237  *  CORBA method: return CORBA reference of the Container
238  *
239  */
240 //=============================================================================
241
242 Engines::Container_ptr Engines_Component_i::GetContainerRef()
243 {
244   MESSAGE("Engines_Component_i::GetContainerRef");
245   CORBA::Object_ptr o = _poa->id_to_reference(*_contId) ;
246   return Engines::Container::_narrow(o);
247 }
248
249 //=============================================================================
250 /*! 
251  *  CORBA method: 
252  *  Gives a sequence of (key=string,value=any) to the component. 
253  *  Base class component stores the sequence in a map.
254  *  The map is cleared before.
255  *  This map is for use by derived classes. 
256  *  \param dico sequence of (key=string,value=any)
257  */
258 //=============================================================================
259
260 void Engines_Component_i::setProperties(const Engines::FieldsDict& dico)
261 {
262   _fieldsDict.clear();
263   for (CORBA::ULong i=0; i<dico.length(); i++)
264     {
265       std::string cle(dico[i].key);
266       _fieldsDict[cle] = dico[i].value;
267     }
268 }
269
270 //=============================================================================
271 /*! 
272  *  CORBA method: 
273  *  returns a previously stored map (key=string,value=any) as a sequence.
274  *  (see setProperties)
275  */
276 //=============================================================================
277
278 Engines::FieldsDict* Engines_Component_i::getProperties()
279 {
280   Engines::FieldsDict_var copie = new Engines::FieldsDict;
281   copie->length(_fieldsDict.size());
282   map<std::string,CORBA::Any>::iterator it;
283   CORBA::ULong i = 0;
284   for (it = _fieldsDict.begin(); it != _fieldsDict.end(); it++, i++)
285     {
286       std::string cle((*it).first);
287       copie[i].key = CORBA::string_dup(cle.c_str());
288       copie[i].value = _fieldsDict[cle];
289     }
290   return copie._retn();
291 }
292
293 //=============================================================================
294 /*! 
295  *  CORBA method: used by Supervision to give names to this instance
296  */
297 //=============================================================================
298
299 void Engines_Component_i::Names( const char * graphName ,
300                                  const char * nodeName )
301 {
302   _graphName = graphName ;
303   _nodeName = nodeName ;
304   //  MESSAGE("Engines_Component_i::Names( '" << _graphName << "' , '"
305   //          << _nodeName << "' )");
306 }
307
308 //=============================================================================
309 /*! 
310  *  CORBA method: used in Supervision
311  */
312 //=============================================================================
313
314 bool Engines_Component_i::Kill_impl() 
315 {
316 //  MESSAGE("Engines_Component_i::Kill_i() pthread_t "<< pthread_self()
317 //          << " pid " << getpid() << " instanceName "
318 //          << _instanceName.c_str() << " interface " << _interfaceName.c_str()
319 //          << " machineName " << GetHostname().c_str()<< " _id " << hex << _id
320 //          << dec << " _ThreadId " << _ThreadId << " this " << hex << this
321 //          << dec ) ;
322
323   bool RetVal = false ;
324   if ( _ThreadId > 0 && pthread_self() != _ThreadId )
325     {
326       RetVal = Killer( _ThreadId , 0 ) ;
327       _ThreadId = (pthread_t ) -1 ;
328     }
329   return RetVal ;
330 }
331
332 //=============================================================================
333 /*! 
334  *  CORBA method: used in Supervision
335  */
336 //=============================================================================
337
338 bool Engines_Component_i::Stop_impl()
339 {
340   MESSAGE("Engines_Component_i::Stop_i() pthread_t "<< pthread_self()
341           << " pid " << getpid() << " instanceName "
342           << _instanceName.c_str() << " interface " << _interfaceName.c_str()
343           << " machineName " << GetHostname().c_str()<< " _id " << hex << _id
344           << dec << " _ThreadId " << _ThreadId );
345   
346
347   bool RetVal = false ;
348   if ( _ThreadId > 0 && pthread_self() != _ThreadId )
349     {
350       RetVal = Killer( _ThreadId , 0 ) ;
351       _ThreadId = (pthread_t ) -1 ;
352     }
353   return RetVal ;
354 }
355
356 //=============================================================================
357 /*! 
358  *  CORBA method: used in Supervision
359  */
360 //=============================================================================
361
362 bool Engines_Component_i::Suspend_impl()
363 {
364   MESSAGE("Engines_Component_i::Suspend_i() pthread_t "<< pthread_self()
365           << " pid " << getpid() << " instanceName "
366           << _instanceName.c_str() << " interface " << _interfaceName.c_str()
367           << " machineName " << GetHostname().c_str()<< " _id " << hex << _id
368           << dec << " _ThreadId " << _ThreadId );
369
370   bool RetVal = false ;
371   if ( _ThreadId > 0 && pthread_self() != _ThreadId )
372     {
373       if ( _Sleeping )
374         {
375           return false ;
376         }
377     else 
378       {
379         RetVal = Killer( _ThreadId ,SIGINT ) ;
380       }
381     }
382   return RetVal ;
383 }
384
385 //=============================================================================
386 /*! 
387  *  CORBA method: used in Supervision
388  */
389 //=============================================================================
390
391 bool Engines_Component_i::Resume_impl()
392 {
393   MESSAGE("Engines_Component_i::Resume_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 );
398   bool RetVal = false ;
399   if ( _ThreadId > 0 && pthread_self() != _ThreadId )
400     {
401     if ( _Sleeping ) 
402       {
403         _Sleeping = false ;
404         RetVal = true ;
405       }
406     else
407       {
408         RetVal = false ;
409       }
410     }
411   return RetVal ;
412 }
413
414 //=============================================================================
415 /*! 
416  *  CORBA method: 
417  */
418 //=============================================================================
419
420 CORBA::Long Engines_Component_i::CpuUsed_impl()
421 {
422   long cpu = 0 ;
423   if ( _ThreadId || _Executed )
424     {
425     if ( _ThreadId > 0 )
426       {
427       if ( pthread_self() != _ThreadId )
428         {
429         if ( _Sleeping )
430           {
431           }
432         else
433           {
434             // Get Cpu in the appropriate thread with that object !...
435             theEngines_Component = this ;
436             Killer( _ThreadId ,SIGUSR1 ) ;
437           }
438         cpu = _ThreadCpuUsed ;
439         }
440       else
441         {
442           _ThreadCpuUsed = CpuUsed() ;
443           cpu = _ThreadCpuUsed ;
444           // cout << pthread_self() << " Engines_Component_i::CpuUsed_impl "
445           //      << _serviceName << " " << cpu << endl ;
446       }
447     }
448     else 
449       {
450         cpu = _ThreadCpuUsed ;
451         // cout << pthread_self() << " Engines_Component_i::CpuUsed_impl "
452         //      << _serviceName << " " << cpu<< endl ;
453       }
454     }
455   else
456     {
457       // cout<< pthread_self()<<"Engines_Component_i::CpuUsed_impl _ThreadId "
458       //     <<_ThreadId <<" "<<_serviceName<<" _StartUsed "<<_StartUsed<<endl;
459     }
460   return cpu ;
461 }
462
463 //=============================================================================
464 /*! 
465  *  C++ method: set study Id
466  *  \param studyId         0 if instance is not associated to a study, 
467  *                         >0 otherwise (== study id)
468  *  \return true if the set of study Id is OK
469  *  must be set once by Container, and cannot be changed after.
470  */
471 //=============================================================================
472
473 CORBA::Boolean Engines_Component_i::setStudyId(CORBA::Long studyId)
474 {
475   ASSERT( studyId >= 0);
476   CORBA::Boolean ret = false;
477   if (_studyId < 0)
478     {
479       _studyId = studyId;
480       ret = true;
481     }
482   else
483     if ( _studyId == studyId) ret = true;
484   return ret;
485 }
486
487 //=============================================================================
488 /*! 
489  *  C++ method: return CORBA instance id, the id is set in derived class
490  *  constructor, when instance is activated.
491  */
492 //=============================================================================
493
494 PortableServer::ObjectId * Engines_Component_i::getId()
495 {
496 //  MESSAGE("PortableServer::ObjectId * Engines_Component_i::getId()");
497   return _id ;
498 }
499
500 //=============================================================================
501 /*! 
502  *  C++ method: used by derived classes for supervision
503  */
504 //=============================================================================
505
506 void Engines_Component_i::beginService(const char *serviceName)
507 {
508   MESSAGE(pthread_self() << "Send BeginService notification for " <<serviceName
509           << endl << "Component instance : " << _instanceName << endl << endl);
510   _ThreadId = pthread_self() ;
511   _StartUsed = 0 ;
512   _StartUsed = CpuUsed_impl() ;
513   _ThreadCpuUsed = 0 ;
514   _Executed = true ;
515   _serviceName = serviceName ;
516   if ( pthread_setcanceltype( PTHREAD_CANCEL_ASYNCHRONOUS , NULL ) )
517     {
518       perror("pthread_setcanceltype ") ;
519       exit(0) ;
520     }
521   if ( pthread_setcancelstate( PTHREAD_CANCEL_ENABLE , NULL ) )
522     {
523       perror("pthread_setcancelstate ") ;
524       exit(0) ;
525     }
526 //  MESSAGE(pthread_self() << " Return from BeginService for " << serviceName
527 //          << " ThreadId " << _ThreadId << " StartUsed " << _StartUsed
528 //          << " _graphName " << _graphName << " _nodeName " << _nodeName );
529
530   // --- for supervisor : all strings given with setProperties
531   //     are set in environment
532   bool overwrite = true;
533   map<std::string,CORBA::Any>::iterator it;
534   for (it = _fieldsDict.begin(); it != _fieldsDict.end(); it++)
535     {
536       std::string cle((*it).first);
537       if ((*it).second.type()->kind() == CORBA::tk_string)
538         {
539           const char* value;
540           (*it).second >>= value;
541           // ---todo: replace __GNUC__ test by an autoconf macro AC_CHECK_FUNC.
542 #if defined __GNUC__
543           int ret = setenv(cle.c_str(), value, overwrite);
544 #else
545           //CCRT porting : setenv not defined in stdlib.h
546           std::string s(cle);
547           s+='=';
548           s+=value;
549           // char* cast because 1st arg of linux putenv function
550           // is not a const char* !
551           int ret=putenv((char *)s.c_str());
552           //End of CCRT porting
553 #endif
554           MESSAGE("--- setenv: "<<cle<<" = "<< value);
555         }
556     }
557 }
558
559 //=============================================================================
560 /*! 
561  *  C++ method: used by derived classes for supervision
562  */
563 //=============================================================================
564
565 void Engines_Component_i::endService(const char *serviceName)
566 {
567   _ThreadCpuUsed = CpuUsed_impl() ;
568   MESSAGE(pthread_self() << " Send EndService notification for " << serviceName
569           << endl << " Component instance : " << _instanceName << " StartUsed "
570           << _StartUsed << " _ThreadCpuUsed "<< _ThreadCpuUsed << endl <<endl);
571   _ThreadId = 0 ;
572 }
573
574 //=============================================================================
575 /*! 
576  *  C++ method: -- CHECK IF USED --
577  */
578 //=============================================================================
579
580 char* Engines_Component_i::graphName()
581 {
582   return CORBA::string_dup( _graphName.c_str() ) ;
583 }
584
585 //=============================================================================
586 /*! 
587  *  C++ method: -- CHECK IF USED --
588  */
589 //=============================================================================
590
591 char* Engines_Component_i::nodeName()
592 {
593   return CORBA::string_dup( _nodeName.c_str() ) ;
594 }
595
596 //=============================================================================
597 /*! 
598  *  C++ method: used in Supervision (see kill_impl)
599  */
600 //=============================================================================
601
602 bool Engines_Component_i::Killer( pthread_t ThreadId , int signum )
603 {
604   if ( ThreadId )
605     {
606       if ( signum == 0 )
607         {
608           if ( pthread_cancel( ThreadId ) )
609             {
610               perror("Killer pthread_cancel error") ;
611               return false ;
612             }
613           else
614             {
615               MESSAGE(pthread_self() << "Killer : ThreadId " << ThreadId
616                       << " pthread_canceled") ;
617             }
618         }
619       else
620         {
621           if ( pthread_kill( ThreadId , signum ) == -1 )
622             {
623               perror("Killer pthread_kill error") ;
624               return false ;
625             }
626           else 
627             {
628               MESSAGE(pthread_self() << "Killer : ThreadId " << ThreadId
629                       << " pthread_killed(" << signum << ")") ;
630             }
631         }
632     }
633   return true ;
634 }
635
636 //=============================================================================
637 /*! 
638  *  C++ method:
639  */ 
640 //=============================================================================
641
642 void SetCpuUsed()
643 {
644   theEngines_Component->SetCurCpu() ;
645 }
646
647 //=============================================================================
648 /*! 
649  *  C++ method:
650  */
651 //=============================================================================
652
653 void Engines_Component_i::SetCurCpu()
654 {
655   _ThreadCpuUsed =  CpuUsed() ;
656   //  MESSAGE(pthread_self() << 
657   //  " Engines_Component_i::SetCurCpu() _ThreadCpuUsed " << _ThreadCpuUsed) ;
658 }
659
660 //=============================================================================
661 /*! 
662  *  C++ method:
663  */
664 //=============================================================================
665
666 long Engines_Component_i::CpuUsed()
667 {
668   long cpu = 0 ;
669   struct rusage usage ;
670   if ( _ThreadId || _Executed )
671     {
672       if ( getrusage( RUSAGE_SELF , &usage ) == -1 )
673         {
674           perror("Engines_Component_i::CpuUsed") ;
675           return 0 ;
676         }
677       cpu = usage.ru_utime.tv_sec - _StartUsed ;
678       // cout << pthread_self() << " Engines_Component_i::CpuUsed " << " "
679       //      << _serviceName   << usage.ru_utime.tv_sec << " - " << _StartUsed
680       //      << " = " << cpu << endl ;
681     }
682   else
683     {
684       // cout << pthread_self() << "Engines_Component_i::CpuUsed _ThreadId "
685       //      << _ThreadId << " " << _serviceName<< " _StartUsed " 
686       //      << _StartUsed << endl ;
687     }
688   return cpu ;
689 }
690
691 //=============================================================================
692 /*! 
693  *  C++ method: Send message to event channel
694  */
695 //=============================================================================
696
697 void Engines_Component_i::sendMessage(const char *event_type,
698                                       const char *message)
699 {
700     _notifSupplier->Send(graphName(), nodeName(), event_type, message);
701 }
702
703 //=============================================================================
704 /*! 
705  *  C++ method:
706  */
707 //=============================================================================
708
709 string Engines_Component_i::GetDynLibraryName(const char *componentName)
710 {
711   string ret="lib";
712   ret+=componentName;
713   ret+="Engine.so";
714   return ret;
715 }
716
717 //=============================================================================
718 /*! 
719  *  C++ method:
720  */
721 //=============================================================================
722
723 string Engines_Component_i::BuildComponentNameForNS(const char *ComponentName,
724                                                     const char *ContainerName,
725                                                     const char *hostname)
726 {
727   string ret =
728     Engines_Container_i::BuildContainerNameForNS(ContainerName,hostname);
729   ret+="/";
730   ret+=ComponentName;
731   return ret;
732 }
733