]> SALOME platform Git repositories - modules/kernel.git/blob - src/Container/Component_i.cxx
Salome HOME
86763cb89a40a181e5621de73ec2024586b554d8
[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   INFOS("Default Constructor...");
61 }
62
63 //=============================================================================
64 /*! 
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
73  */
74 //=============================================================================
75
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,
81                                          bool notif) :
82   _instanceName(instanceName),
83   _interfaceName(interfaceName),
84   _myConnexionToRegistry(0),
85   _ThreadId(0) ,
86   _ThreadCpuUsed(0) ,
87   _Executed(false) ,
88   _graphName("") ,
89   _nodeName(""),
90  _studyId(-1)
91 {
92   MESSAGE("Component constructor with instanceName "<< _instanceName);
93   //SCRUTE(pd_refCount);
94   _orb = CORBA::ORB::_duplicate(orb);
95   _poa = PortableServer::POA::_duplicate(poa);
96   _contId = contId ;
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());
101
102   _notifSupplier = new NOTIFICATION_Supplier(instanceName, notif);
103   //SCRUTE(pd_refCount);
104 }
105
106 //=============================================================================
107 /*! 
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
117  */
118 //=============================================================================
119
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,
125                                          int flag,
126                                          bool notif ) :
127  _instanceName(instanceName),
128  _interfaceName(interfaceName),
129  _myConnexionToRegistry(0),
130  _ThreadId(0) ,
131  _ThreadCpuUsed(0) ,
132  _Executed(false) ,
133  _graphName("") ,
134  _nodeName(""),
135  _studyId(-1)
136 {
137   _orb = CORBA::ORB::_duplicate(orb);
138   _poa = PortableServer::POA::_duplicate(poa);
139   _contId = contId ;
140
141   _notifSupplier = new NOTIFICATION_Supplier(instanceName, notif);
142 }
143
144 //=============================================================================
145 /*! 
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)
149  */
150 //=============================================================================
151
152 Engines_Component_i::~Engines_Component_i()
153 {
154   MESSAGE("Component destructor");
155   Engines_Container_i::decInstanceCnt(_interfaceName);
156 }
157
158 //=============================================================================
159 /*! 
160  *  CORBA method: return name of the instance, unique in this Container
161  */
162 //=============================================================================
163
164 char* Engines_Component_i::instanceName()
165 {
166    return CORBA::string_dup(_instanceName.c_str()) ;
167 }
168
169 //=============================================================================
170 /*! 
171  *  CORBA method: return name of the component class
172  */
173 //=============================================================================
174
175 char* Engines_Component_i::interfaceName()
176 {
177   return CORBA::string_dup(_interfaceName.c_str()) ;
178 }
179
180 //=============================================================================
181 /*! 
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
186  */
187 //=============================================================================
188
189 CORBA::Long Engines_Component_i::getStudyId()
190 {
191   return _studyId;
192 }
193
194 //=============================================================================
195 /*! 
196  *  CORBA method: Test if instance is alive and responds
197  */
198 //=============================================================================
199
200 void Engines_Component_i::ping()
201 {
202   MESSAGE("Engines_Component_i::ping() pid "<< getpid() << " threadid "
203           << pthread_self());
204 }
205
206 //=============================================================================
207 /*! 
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) --
214  */
215 //=============================================================================
216
217 void Engines_Component_i::destroy()
218 {
219   MESSAGE("Engines_Component_i::destroy()");
220   //SCRUTE(pd_refCount);
221
222   delete _notifSupplier;
223   _notifSupplier = 0;
224
225   delete _myConnexionToRegistry;
226   _myConnexionToRegistry = 0 ;
227   _poa->deactivate_object(*_id) ;
228   CORBA::release(_poa) ;
229   delete(_id) ;
230   //SCRUTE(pd_refCount);
231   _thisObj->_remove_ref();
232   //SCRUTE(pd_refCount);
233   MESSAGE("Engines_Component_i::destroyed") ;
234 }
235
236 //=============================================================================
237 /*! 
238  *  CORBA method: return CORBA reference of the Container
239  *
240  */
241 //=============================================================================
242
243 Engines::Container_ptr Engines_Component_i::GetContainerRef()
244 {
245   MESSAGE("Engines_Component_i::GetContainerRef");
246   CORBA::Object_ptr o = _poa->id_to_reference(*_contId) ;
247   return Engines::Container::_narrow(o);
248 }
249
250 //=============================================================================
251 /*! 
252  *  CORBA method: 
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)
258  */
259 //=============================================================================
260
261 void Engines_Component_i::setProperties(const Engines::FieldsDict& dico)
262 {
263   _fieldsDict.clear();
264   for (CORBA::ULong i=0; i<dico.length(); i++)
265     {
266       std::string cle(dico[i].key);
267       _fieldsDict[cle] = dico[i].value;
268     }
269 }
270
271 //=============================================================================
272 /*! 
273  *  CORBA method: 
274  *  returns a previously stored map (key=string,value=any) as a sequence.
275  *  (see setProperties)
276  */
277 //=============================================================================
278
279 Engines::FieldsDict* Engines_Component_i::getProperties()
280 {
281   Engines::FieldsDict_var copie = new Engines::FieldsDict;
282   copie->length(_fieldsDict.size());
283   map<std::string,CORBA::Any>::iterator it;
284   CORBA::ULong i = 0;
285   for (it = _fieldsDict.begin(); it != _fieldsDict.end(); it++, i++)
286     {
287       std::string cle((*it).first);
288       copie[i].key = CORBA::string_dup(cle.c_str());
289       copie[i].value = _fieldsDict[cle];
290     }
291   return copie._retn();
292 }
293
294 //=============================================================================
295 /*! 
296  *  CORBA method: used by Supervision to give names to this instance
297  */
298 //=============================================================================
299
300 void Engines_Component_i::Names( const char * graphName ,
301                                  const char * nodeName )
302 {
303   _graphName = graphName ;
304   _nodeName = nodeName ;
305   //  MESSAGE("Engines_Component_i::Names( '" << _graphName << "' , '"
306   //          << _nodeName << "' )");
307 }
308
309 //=============================================================================
310 /*! 
311  *  CORBA method: used in Supervision
312  */
313 //=============================================================================
314
315 bool Engines_Component_i::Kill_impl() 
316 {
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
322 //          << dec ) ;
323
324   bool RetVal = false ;
325   if ( _ThreadId > 0 && pthread_self() != _ThreadId )
326     {
327       RetVal = Killer( _ThreadId , 0 ) ;
328       _ThreadId = (pthread_t ) -1 ;
329     }
330   return RetVal ;
331 }
332
333 //=============================================================================
334 /*! 
335  *  CORBA method: used in Supervision
336  */
337 //=============================================================================
338
339 bool Engines_Component_i::Stop_impl()
340 {
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 );
346   
347
348   bool RetVal = false ;
349   if ( _ThreadId > 0 && pthread_self() != _ThreadId )
350     {
351       RetVal = Killer( _ThreadId , 0 ) ;
352       _ThreadId = (pthread_t ) -1 ;
353     }
354   return RetVal ;
355 }
356
357 //=============================================================================
358 /*! 
359  *  CORBA method: used in Supervision
360  */
361 //=============================================================================
362
363 bool Engines_Component_i::Suspend_impl()
364 {
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 );
370
371   bool RetVal = false ;
372   if ( _ThreadId > 0 && pthread_self() != _ThreadId )
373     {
374       if ( _Sleeping )
375         {
376           return false ;
377         }
378     else 
379       {
380         RetVal = Killer( _ThreadId ,SIGINT ) ;
381       }
382     }
383   return RetVal ;
384 }
385
386 //=============================================================================
387 /*! 
388  *  CORBA method: used in Supervision
389  */
390 //=============================================================================
391
392 bool Engines_Component_i::Resume_impl()
393 {
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 )
401     {
402     if ( _Sleeping ) 
403       {
404         _Sleeping = false ;
405         RetVal = true ;
406       }
407     else
408       {
409         RetVal = false ;
410       }
411     }
412   return RetVal ;
413 }
414
415 //=============================================================================
416 /*! 
417  *  CORBA method: 
418  */
419 //=============================================================================
420
421 CORBA::Long Engines_Component_i::CpuUsed_impl()
422 {
423   long cpu = 0 ;
424   if ( _ThreadId || _Executed )
425     {
426     if ( _ThreadId > 0 )
427       {
428       if ( pthread_self() != _ThreadId )
429         {
430         if ( _Sleeping )
431           {
432           }
433         else
434           {
435             // Get Cpu in the appropriate thread with that object !...
436             theEngines_Component = this ;
437             Killer( _ThreadId ,SIGUSR1 ) ;
438           }
439         cpu = _ThreadCpuUsed ;
440         }
441       else
442         {
443           _ThreadCpuUsed = CpuUsed() ;
444           cpu = _ThreadCpuUsed ;
445           // cout << pthread_self() << " Engines_Component_i::CpuUsed_impl "
446           //      << _serviceName << " " << cpu << endl ;
447       }
448     }
449     else 
450       {
451         cpu = _ThreadCpuUsed ;
452         // cout << pthread_self() << " Engines_Component_i::CpuUsed_impl "
453         //      << _serviceName << " " << cpu<< endl ;
454       }
455     }
456   else
457     {
458       // cout<< pthread_self()<<"Engines_Component_i::CpuUsed_impl _ThreadId "
459       //     <<_ThreadId <<" "<<_serviceName<<" _StartUsed "<<_StartUsed<<endl;
460     }
461   return cpu ;
462 }
463
464 //=============================================================================
465 /*! 
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.
471  */
472 //=============================================================================
473
474 CORBA::Boolean Engines_Component_i::setStudyId(CORBA::Long studyId)
475 {
476   ASSERT( studyId >= 0);
477   CORBA::Boolean ret = false;
478   if (_studyId < 0)
479     {
480       _studyId = studyId;
481       ret = true;
482     }
483   else
484     if ( _studyId == studyId) ret = true;
485   return ret;
486 }
487
488 //=============================================================================
489 /*! 
490  *  C++ method: return CORBA instance id, the id is set in derived class
491  *  constructor, when instance is activated.
492  */
493 //=============================================================================
494
495 PortableServer::ObjectId * Engines_Component_i::getId()
496 {
497 //  MESSAGE("PortableServer::ObjectId * Engines_Component_i::getId()");
498   return _id ;
499 }
500
501 //=============================================================================
502 /*! 
503  *  C++ method: used by derived classes for supervision
504  */
505 //=============================================================================
506
507 void Engines_Component_i::beginService(const char *serviceName)
508 {
509   MESSAGE(pthread_self() << "Send BeginService notification for " <<serviceName
510           << endl << "Component instance : " << _instanceName << endl << endl);
511   _ThreadId = pthread_self() ;
512   _StartUsed = 0 ;
513   _StartUsed = CpuUsed_impl() ;
514   _ThreadCpuUsed = 0 ;
515   _Executed = true ;
516   _serviceName = serviceName ;
517   if ( pthread_setcanceltype( PTHREAD_CANCEL_ASYNCHRONOUS , NULL ) )
518     {
519       perror("pthread_setcanceltype ") ;
520       exit(0) ;
521     }
522   if ( pthread_setcancelstate( PTHREAD_CANCEL_ENABLE , NULL ) )
523     {
524       perror("pthread_setcancelstate ") ;
525       exit(0) ;
526     }
527 //  MESSAGE(pthread_self() << " Return from BeginService for " << serviceName
528 //          << " ThreadId " << _ThreadId << " StartUsed " << _StartUsed
529 //          << " _graphName " << _graphName << " _nodeName " << _nodeName );
530
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++)
536     {
537       std::string cle((*it).first);
538       if ((*it).second.type()->kind() == CORBA::tk_string)
539         {
540           const char* value;
541           (*it).second >>= value;
542           // ---todo: replace __GNUC__ test by an autoconf macro AC_CHECK_FUNC.
543 #if defined __GNUC__
544           int ret = setenv(cle.c_str(), value, overwrite);
545 #else
546           //CCRT porting : setenv not defined in stdlib.h
547           std::string s(cle);
548           s+='=';
549           s+=value;
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
554 #endif
555           MESSAGE("--- setenv: "<<cle<<" = "<< value);
556         }
557     }
558 }
559
560 //=============================================================================
561 /*! 
562  *  C++ method: used by derived classes for supervision
563  */
564 //=============================================================================
565
566 void Engines_Component_i::endService(const char *serviceName)
567 {
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);
572   _ThreadId = 0 ;
573 }
574
575 //=============================================================================
576 /*! 
577  *  C++ method: -- CHECK IF USED --
578  */
579 //=============================================================================
580
581 char* Engines_Component_i::graphName()
582 {
583   return CORBA::string_dup( _graphName.c_str() ) ;
584 }
585
586 //=============================================================================
587 /*! 
588  *  C++ method: -- CHECK IF USED --
589  */
590 //=============================================================================
591
592 char* Engines_Component_i::nodeName()
593 {
594   return CORBA::string_dup( _nodeName.c_str() ) ;
595 }
596
597 //=============================================================================
598 /*! 
599  *  C++ method: used in Supervision (see kill_impl)
600  */
601 //=============================================================================
602
603 bool Engines_Component_i::Killer( pthread_t ThreadId , int signum )
604 {
605   if ( ThreadId )
606     {
607       if ( signum == 0 )
608         {
609           if ( pthread_cancel( ThreadId ) )
610             {
611               perror("Killer pthread_cancel error") ;
612               return false ;
613             }
614           else
615             {
616               MESSAGE(pthread_self() << "Killer : ThreadId " << ThreadId
617                       << " pthread_canceled") ;
618             }
619         }
620       else
621         {
622           if ( pthread_kill( ThreadId , signum ) == -1 )
623             {
624               perror("Killer pthread_kill error") ;
625               return false ;
626             }
627           else 
628             {
629               MESSAGE(pthread_self() << "Killer : ThreadId " << ThreadId
630                       << " pthread_killed(" << signum << ")") ;
631             }
632         }
633     }
634   return true ;
635 }
636
637 //=============================================================================
638 /*! 
639  *  C++ method:
640  */ 
641 //=============================================================================
642
643 void SetCpuUsed()
644 {
645   theEngines_Component->SetCurCpu() ;
646 }
647
648 //=============================================================================
649 /*! 
650  *  C++ method:
651  */
652 //=============================================================================
653
654 void Engines_Component_i::SetCurCpu()
655 {
656   _ThreadCpuUsed =  CpuUsed() ;
657   //  MESSAGE(pthread_self() << 
658   //  " Engines_Component_i::SetCurCpu() _ThreadCpuUsed " << _ThreadCpuUsed) ;
659 }
660
661 //=============================================================================
662 /*! 
663  *  C++ method:
664  */
665 //=============================================================================
666
667 long Engines_Component_i::CpuUsed()
668 {
669   long cpu = 0 ;
670   struct rusage usage ;
671   if ( _ThreadId || _Executed )
672     {
673       if ( getrusage( RUSAGE_SELF , &usage ) == -1 )
674         {
675           perror("Engines_Component_i::CpuUsed") ;
676           return 0 ;
677         }
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 ;
682     }
683   else
684     {
685       // cout << pthread_self() << "Engines_Component_i::CpuUsed _ThreadId "
686       //      << _ThreadId << " " << _serviceName<< " _StartUsed " 
687       //      << _StartUsed << endl ;
688     }
689   return cpu ;
690 }
691
692 //=============================================================================
693 /*! 
694  *  C++ method: Send message to event channel
695  */
696 //=============================================================================
697
698 void Engines_Component_i::sendMessage(const char *event_type,
699                                       const char *message)
700 {
701     _notifSupplier->Send(graphName(), nodeName(), event_type, message);
702 }
703
704 //=============================================================================
705 /*! 
706  *  C++ method:
707  */
708 //=============================================================================
709
710 string Engines_Component_i::GetDynLibraryName(const char *componentName)
711 {
712   string ret="lib";
713   ret+=componentName;
714   ret+="Engine.so";
715   return ret;
716 }
717
718 //=============================================================================
719 /*! 
720  *  C++ method:
721  */
722 //=============================================================================
723
724 string Engines_Component_i::BuildComponentNameForNS(const char *ComponentName,
725                                                     const char *ContainerName,
726                                                     const char *hostname)
727 {
728   string ret =
729     Engines_Container_i::BuildContainerNameForNS(ContainerName,hostname);
730   ret+="/";
731   ret+=ComponentName;
732   return ret;
733 }
734 //=============================================================================
735 /*! 
736  *  C++ method: DumpPython default implementation
737  */
738 //=============================================================================
739
740 Engines::TMPFile* Engines_Component_i::DumpPython(CORBA::Object_ptr theStudy, 
741                                                   CORBA::Boolean isPublished, 
742                                                   CORBA::Boolean& isValidScript)
743 {
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(); 
752 }