Salome HOME
CCAR: add some lacking declarations
[modules/kernel.git] / src / Container / Container_i.cxx
1 //  Copyright (C) 2007-2008  CEA/DEN, EDF R&D, OPEN CASCADE
2 //
3 //  Copyright (C) 2003-2007  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.salome-platform.org/ or email : webmaster.salome@opencascade.com
21 //
22 //  SALOME Container : implementation of container and engine for Kernel
23 //  File   : Container_i.cxx
24 //  Author : Paul RASCLE, EDF - MARC TAJCHMAN, CEA 
25 //  Module : SALOME
26 //  $Header$
27 //#define private public
28 //
29 #include <string.h>
30 #include <stdio.h>
31 #include <time.h>
32 #include <sys/types.h>
33 #ifndef WIN32
34 #include <sys/time.h>
35 #include <dlfcn.h>
36 #include <unistd.h>
37 #include <sys/wait.h>
38 #else
39 #include <signal.h>
40 #include <process.h>
41 #include <direct.h>
42 int SIGUSR1 = 1000;
43 #endif
44
45 #include "utilities.h"
46 #include <SALOMEconfig.h>
47 #include CORBA_SERVER_HEADER(SALOME_Component)
48 #include CORBA_SERVER_HEADER(SALOME_Exception)
49 #include <pthread.h>  // must be before Python.h !
50 #include "SALOME_Container_i.hxx"
51 #include "SALOME_Component_i.hxx"
52 #include "SALOME_FileRef_i.hxx"
53 #include "SALOME_FileTransfer_i.hxx"
54 #include "Salome_file_i.hxx"
55 #include "SALOME_NamingService.hxx"
56 #include "Basics_Utils.hxx"
57
58 #include <Python.h>
59 #include "Container_init_python.hxx"
60
61 using namespace std;
62
63 bool _Sleeping = false ;
64
65 // // Needed by multi-threaded Python --- Supervision
66 int _ArgC ;
67 char ** _ArgV ;
68
69 extern "C" {void ActSigIntHandler() ; }
70 #ifndef WIN32
71 extern "C" {void SigIntHandler(int, siginfo_t *, void *) ; }
72 #else
73 extern "C" {void SigIntHandler( int ) ; }
74 #endif
75
76 #ifdef WIN32
77 # define separator '\\'
78 #else
79 # define separator '/'
80 #endif
81
82
83 map<std::string, int> Engines_Container_i::_cntInstances_map;
84 map<std::string, void *> Engines_Container_i::_library_map;
85 map<std::string, void *> Engines_Container_i::_toRemove_map;
86 omni_mutex Engines_Container_i::_numInstanceMutex ;
87
88 static PyObject* _pyCont;
89
90 int checkifexecutable(const std::string&);
91 int findpathof(std::string&, const std::string&);
92
93 /*! \class Engines_Container_i
94  *  \brief C++ implementation of Engines::Container interface
95  *
96  */
97
98
99 //=============================================================================
100 /*! 
101 *  Default constructor, not for use
102 */
103 //=============================================================================
104
105 Engines_Container_i::Engines_Container_i () :
106 _numInstance(0),_id(0),_NS(0)
107 {
108 }
109
110 //=============================================================================
111 /*! 
112 *  Construtor to use
113 */
114 //=============================================================================
115
116 Engines_Container_i::Engines_Container_i (CORBA::ORB_ptr orb, 
117                                           PortableServer::POA_ptr poa,
118                                           char *containerName ,
119                                           int argc , char* argv[],
120                                           bool activAndRegist,
121                                           bool isServantAloneInProcess
122                                           ) :
123   _numInstance(0),_isServantAloneInProcess(isServantAloneInProcess),_id(0),_NS(0)
124 {
125   _pid = (long)getpid();
126
127   if(activAndRegist)
128     ActSigIntHandler() ;
129
130   _argc = argc ;
131   _argv = argv ;
132
133   string hostname = Kernel_Utils::GetHostname();
134 #ifndef WIN32
135   MESSAGE(hostname << " " << getpid() << 
136     " Engines_Container_i starting argc " <<
137     _argc << " Thread " << pthread_self() ) ;
138 #else
139   MESSAGE(hostname << " " << _getpid() << 
140     " Engines_Container_i starting argc " << _argc<< " Thread " << pthread_self().p ) ;
141 #endif
142
143   int i = 0 ;
144   while ( _argv[ i ] )
145   {
146     MESSAGE("           argv" << i << " " << _argv[ i ]) ;
147     i++ ;
148   }
149
150   if ( argc < 2 )
151   {
152     INFOS("SALOME_Container usage : SALOME_Container ServerName");
153     ASSERT(0) ;
154   }
155   SCRUTE(argv[1]);
156   _isSupervContainer = false;
157   if (strcmp(argv[1],"SuperVisionContainer") == 0) _isSupervContainer = true;
158
159   if (_isSupervContainer)
160   {
161     _ArgC = argc ;
162     _ArgV = argv ;
163   }
164
165   _orb = CORBA::ORB::_duplicate(orb) ;
166   _poa = PortableServer::POA::_duplicate(poa) ;
167
168   // Pour les containers paralleles: il ne faut pas enregistrer et activer
169   // le container generique, mais le container specialise
170
171   if(activAndRegist)
172   {
173     _id = _poa->activate_object(this);
174     _NS = new SALOME_NamingService();
175     _NS->init_orb( _orb ) ;
176     CORBA::Object_var obj=_poa->id_to_reference(*_id);
177     Engines::Container_var pCont 
178       = Engines::Container::_narrow(obj);
179     _remove_ref();
180
181     _containerName = _NS->BuildContainerNameForNS(containerName,
182       hostname.c_str());
183     SCRUTE(_containerName);
184     _NS->Register(pCont, _containerName.c_str());
185     MESSAGE("Engines_Container_i::Engines_Container_i : Container name "
186       << _containerName);
187
188     // Python: 
189     // import SALOME_Container
190     // pycont = SALOME_Container.SALOME_Container_i(containerIORStr)
191
192     CORBA::String_var sior =  _orb->object_to_string(pCont);
193     string myCommand="pyCont = SALOME_Container.SALOME_Container_i('";
194     myCommand += _containerName + "','";
195     myCommand += sior;
196     myCommand += "')\n";
197     SCRUTE(myCommand);
198
199     if (!_isSupervContainer)
200     {
201       PyGILState_STATE gstate = PyGILState_Ensure();
202
203 #ifdef WIN32
204       // mpv: this is temporary solution: there is a unregular crash if not
205       //Sleep(2000);
206       //
207       // first element is the path to Registry.dll, but it's wrong
208       PyRun_SimpleString("import sys\n");
209       PyRun_SimpleString("sys.path = sys.path[1:]\n");
210 #endif
211       PyRun_SimpleString("import SALOME_Container\n");
212       PyRun_SimpleString((char*)myCommand.c_str());
213       PyObject *mainmod = PyImport_AddModule("__main__");
214       PyObject *globals = PyModule_GetDict(mainmod);
215       _pyCont = PyDict_GetItemString(globals, "pyCont");
216
217       PyGILState_Release(gstate);
218     }
219
220     fileTransfer_i* aFileTransfer = new fileTransfer_i();
221     CORBA::Object_var obref=aFileTransfer->_this();
222     _fileTransfer = Engines::fileTransfer::_narrow(obref);
223     aFileTransfer->_remove_ref();
224   }
225 }
226
227 //=============================================================================
228 /*! 
229 *  Destructor
230 */
231 //=============================================================================
232
233 Engines_Container_i::~Engines_Container_i()
234 {
235   MESSAGE("Container_i::~Container_i()");
236   if(_id)
237     delete _id;
238   if(_NS)
239     delete _NS;
240 }
241
242 //=============================================================================
243 //! Get container name
244 /*! 
245 *  CORBA attribute: Container name (see constructor)
246 */
247 //=============================================================================
248
249 char* Engines_Container_i::name()
250 {
251   return CORBA::string_dup(_containerName.c_str()) ;
252 }
253
254 //=============================================================================
255 //! Get container working directory
256 /*! 
257 *  CORBA attribute: Container working directory 
258 */
259 //=============================================================================
260
261 char* Engines_Container_i::workingdir()
262 {
263   char wd[256];
264   getcwd (wd,256);
265   return CORBA::string_dup(wd) ;
266 }
267
268 //=============================================================================
269 //! Get container log file name
270 /*! 
271 *  CORBA attribute: Container log file name
272 */
273 //=============================================================================
274
275 char* Engines_Container_i::logfilename()
276 {
277   return CORBA::string_dup(_logfilename.c_str()) ;
278 }
279
280 //! Set container log file name
281 void Engines_Container_i::logfilename(const char* name)
282 {
283   _logfilename=name;
284 }
285
286 //=============================================================================
287 //! Get container host name
288 /*! 
289 *  CORBA method: Get the hostName of the Container (without domain extensions)
290 */
291 //=============================================================================
292
293 char* Engines_Container_i::getHostName()
294 {
295   string s = Kernel_Utils::GetHostname();
296   //  MESSAGE("Engines_Container_i::getHostName " << s);
297   return CORBA::string_dup(s.c_str()) ;
298 }
299
300 //=============================================================================
301 //! Get container PID
302 /*! 
303 *  CORBA method: Get the PID (process identification) of the Container
304 */
305 //=============================================================================
306
307 CORBA::Long Engines_Container_i::getPID()
308 {
309   return (CORBA::Long)getpid();
310 }
311
312 //=============================================================================
313 //! Ping the servant to check it is still alive
314 /*! 
315 *  CORBA method: check if servant is still alive
316 */
317 //=============================================================================
318
319 void Engines_Container_i::ping()
320 {
321   MESSAGE("Engines_Container_i::ping() pid "<< getpid());
322 }
323
324 //=============================================================================
325 //! Shutdown the container
326 /*! 
327 *  CORBA method, oneway: Server shutdown. 
328 *  - Container name removed from naming service,
329 *  - servant deactivation,
330 *  - orb shutdown if no other servants in the process 
331 */
332 //=============================================================================
333
334 void Engines_Container_i::Shutdown()
335 {
336   MESSAGE("Engines_Container_i::Shutdown()");
337
338   /* For each component contained in this container
339   * tell it to self-destroy
340   */
341   std::map<std::string, Engines::Component_var>::iterator itm;
342   for (itm = _listInstances_map.begin(); itm != _listInstances_map.end(); itm++)
343     {
344       try
345         {
346           itm->second->destroy();
347         }
348       catch(const CORBA::Exception& e)
349         {
350           // ignore this entry and continue
351         }
352       catch(...)
353         {
354           // ignore this entry and continue
355         }
356     }
357   _listInstances_map.clear();
358
359   _NS->Destroy_FullDirectory(_containerName.c_str());
360   _NS->Destroy_Name(_containerName.c_str());
361   if(_isServantAloneInProcess)
362   {
363     MESSAGE("Effective Shutdown of container Begins...");
364     if(!CORBA::is_nil(_orb))
365       _orb->shutdown(0);
366   }
367 }
368
369 /* int checkifexecutable(const char *filename)
370
371 * Return non-zero if the name is an executable file, and
372 * zero if it is not executable, or if it does not exist.
373 */
374
375 int checkifexecutable(const string& filename)
376 {
377   int result;
378   struct stat statinfo;
379
380   result = stat(filename.c_str(), &statinfo);
381   if (result < 0) return 0;
382   if (!S_ISREG(statinfo.st_mode)) return 0;
383
384 #ifdef WIN32
385   return 1;
386 #else
387   if (statinfo.st_uid == geteuid()) return statinfo.st_mode & S_IXUSR;
388   if (statinfo.st_gid == getegid()) return statinfo.st_mode & S_IXGRP;
389   return statinfo.st_mode & S_IXOTH;
390 #endif
391 }
392
393
394 /* int findpathof(char *pth, const char *exe)
395 *
396 * Find executable by searching the PATH environment variable.
397 *
398 * const char *exe - executable name to search for.
399 *       char *pth - the path found is stored here, space
400 *                   needs to be available.
401 *
402 * If a path is found, returns non-zero, and the path is stored
403 * in pth.  If exe is not found returns 0, with pth undefined.
404 */
405
406 int findpathof(string& pth, const string& exe)
407 {
408   string path( getenv("PATH") );
409   if ( path.size() == 0 )
410          return 0;
411        
412   char path_spr =
413 #ifdef WIN32
414                   ';';
415 #else
416                   ':';
417 #endif
418
419     char dir_spr = 
420 #ifdef WIN32
421                   '\\';
422 #else
423                   '/';
424 #endif
425     
426   int offset = 0;
427   int stop = 0;
428   int found = 0;
429   while(!stop && !found)
430   {
431     int pos = path.find( path_spr, offset );
432     if (pos == string::npos)
433       stop = 1;
434
435     pth = path.substr( offset, pos - offset );
436     if ( pth.size() > 0 )
437     {
438       if( pth[pth.size()-1] != dir_spr )
439         pth += dir_spr;
440       pth += exe;
441       found = checkifexecutable(pth.c_str());
442     }
443     offset = pos+1;
444   }
445
446
447 /*  char *searchpath;
448   char *beg, *end;
449   int stop, found;
450   int len;
451
452   if (strchr(exe, separator) != NULL) {
453 #ifndef WIN32
454     if (realpath(exe, pth) == NULL) return 0;
455 #endif
456     return  checkifexecutable(pth);
457   }
458
459   searchpath = getenv("PATH");
460   if (searchpath == NULL) return 0;
461   if (strlen(searchpath) <= 0) return 0;
462
463   string env_path(searchpath);
464
465   beg = searchpath;
466   stop = 0; found = 0;
467   do {
468     end = strchr(beg, ':');
469     if (end == NULL) {
470       stop = 1;
471       strncpy(pth, beg, PATH_MAX);
472       len = strlen(pth);
473     } else {
474       strncpy(pth, beg, end - beg);
475       pth[end - beg] = '\0';
476       len = end - beg;
477     }
478     if (pth[len - 1] != '/') strncat(pth, "/", 1);
479     strncat(pth, exe, PATH_MAX - len);
480     found = checkifexecutable(pth);
481     if (!stop) beg = end + 1;
482   } while (!stop && !found);
483 */
484   return found;
485 }
486
487
488
489 //=============================================================================
490 //! load a new component class
491 /*! 
492 *  CORBA method: load a new component class (Python or C++ implementation)
493 *  \param componentName like COMPONENT
494 *                          try to make a Python import of COMPONENT,
495 *                          then a lib open of libCOMPONENTEngine.so
496 *  \return true if dlopen successfull or already done, false otherwise
497 */
498 //=============================================================================
499
500 bool
501 Engines_Container_i::load_component_Library(const char* componentName)
502 {
503
504   string aCompName = componentName;
505
506   // --- try dlopen C++ component
507
508 #ifndef WIN32
509   string impl_name = string ("lib") + aCompName + string("Engine.so");
510 #else
511   string impl_name = aCompName + string("Engine.dll");
512 #endif
513   SCRUTE(impl_name);
514
515   _numInstanceMutex.lock(); // lock to be alone 
516   // (see decInstanceCnt, finalize_removal))
517   if (_toRemove_map.count(impl_name) != 0) _toRemove_map.erase(impl_name);
518   if (_library_map.count(impl_name) != 0)
519   {
520     MESSAGE("Library " << impl_name << " already loaded");
521     _numInstanceMutex.unlock();
522     return true;
523   }
524
525   std::string retso="";
526 #ifndef WIN32
527   void* handle;
528   handle = dlopen( impl_name.c_str() , RTLD_LAZY ) ;
529   if ( !handle )retso=dlerror();
530 #else
531   HINSTANCE handle;
532   handle = LoadLibrary( impl_name.c_str() );
533 #endif
534
535   if ( handle )
536   {
537     _library_map[impl_name] = handle;
538     _numInstanceMutex.unlock();
539     return true;
540   }
541   _numInstanceMutex.unlock();
542
543   // --- try import Python component
544
545   INFOS("try import Python component "<<componentName);
546   std::string retpy;
547   if (_isSupervContainer)
548   {
549     INFOS("Supervision Container does not support Python Component Engines");
550     return false;
551   }
552   if (_library_map.count(aCompName) != 0)
553   {
554     return true; // Python Component, already imported
555   }
556   else
557   {
558     PyGILState_STATE gstate = PyGILState_Ensure(); 
559     PyObject *result = PyObject_CallMethod(_pyCont,
560       (char*)"import_component",
561       (char*)"s",componentName);
562
563     retpy=PyString_AsString(result);
564     Py_XDECREF(result);
565     SCRUTE(retpy);
566     PyGILState_Release(gstate);
567
568     if (retpy=="") // import possible: Python component
569     {
570       _numInstanceMutex.lock() ; // lock to be alone (stl container write)
571       _library_map[aCompName] = (void *)_pyCont; // any non O value OK
572       _numInstanceMutex.unlock() ;
573       MESSAGE("import Python: "<<aCompName<<" OK");
574       return true;
575     }
576   }
577   // Try to find an executable
578   std::string executable=aCompName+".exe";
579   string path;
580   if (findpathof(path, executable)) 
581     return true;
582
583   INFOS( "Impossible to load component: " << componentName );
584   INFOS( "Can't load shared library: " << impl_name );
585   std::cerr << retso << std::endl;
586   INFOS( "Can't import Python module: " << componentName );
587   std::cerr << retpy << std::endl;
588   INFOS( "Can't execute program: " << executable );
589   return false;
590 }
591
592 //=============================================================================
593 //! Create a new component instance
594 /*! 
595 *  CORBA method: Creates a new servant instance of a component.
596 *  The servant registers itself to naming service and Registry.
597 *  \param genericRegisterName  Name of the component instance to register
598 *                         in Registry & Name Service (without _inst_n suffix)
599 *  \param studyId         0 for multiStudy instance, 
600 *                         study Id (>0) otherwise
601 *  \return a loaded component
602 */
603 //=============================================================================
604
605 Engines::Component_ptr
606 Engines_Container_i::create_component_instance(const char*genericRegisterName,
607                                                CORBA::Long studyId)
608 {
609   Engines::FieldsDict_var env = new Engines::FieldsDict;
610   return create_component_instance_env(genericRegisterName,studyId,env);
611 }
612
613 //=============================================================================
614 //! Create a new component instance with environment variables specified
615 /*! 
616 *  CORBA method: Creates a new servant instance of a component.
617 *  The servant registers itself to naming service and Registry.
618 *  \param genericRegisterName  Name of the component instance to register
619 *                         in Registry & Name Service (without _inst_n suffix)
620 *  \param studyId         0 for multiStudy instance, 
621 *                         study Id (>0) otherwise
622 *  \param env          dict of env variables
623 *  \return a loaded component
624 */
625 //=============================================================================
626
627 Engines::Component_ptr
628 Engines_Container_i::create_component_instance_env(const char*genericRegisterName,
629                                                CORBA::Long studyId,const Engines::FieldsDict& env)
630 {
631   if (studyId < 0)
632   {
633     INFOS("studyId must be > 0 for mono study instance, =0 for multiStudy");
634     return Engines::Component::_nil() ;
635   }
636
637   Engines::Component_var iobject = Engines::Component::_nil() ;
638
639   string aCompName = genericRegisterName;
640   if (_library_map.count(aCompName) != 0) // Python component
641   {
642     if (_isSupervContainer)
643     {
644       INFOS("Supervision Container does not support Python Component Engines");
645       return Engines::Component::_nil();
646     }
647     _numInstanceMutex.lock() ; // lock on the instance number
648     _numInstance++ ;
649     int numInstance = _numInstance ;
650     _numInstanceMutex.unlock() ;
651
652     char aNumI[12];
653     sprintf( aNumI , "%d" , numInstance ) ;
654     string instanceName = aCompName + "_inst_" + aNumI ;
655     string component_registerName =
656       _containerName + "/" + instanceName;
657
658     PyGILState_STATE gstate = PyGILState_Ensure(); 
659     PyObject *result = PyObject_CallMethod(_pyCont,
660       (char*)"create_component_instance",
661       (char*)"ssl",
662       aCompName.c_str(),
663       instanceName.c_str(),
664       studyId);
665     string iors = PyString_AsString(result);
666     Py_DECREF(result);
667     SCRUTE(iors);
668     PyGILState_Release(gstate);
669
670     if( iors!="" )
671     {
672       CORBA::Object_var obj = _orb->string_to_object(iors.c_str());
673       iobject = Engines::Component::_narrow( obj ) ;
674       _listInstances_map[instanceName] = iobject;
675     }
676     return iobject._retn();
677   }
678
679   //--- try C++
680
681 #ifndef WIN32
682   string impl_name = string ("lib") + genericRegisterName +string("Engine.so");
683 #else
684   string impl_name = genericRegisterName +string("Engine.dll");
685 #endif
686   if (_library_map.count(impl_name) != 0) // C++ component
687   {
688     void* handle = _library_map[impl_name];
689     iobject = createInstance(genericRegisterName,
690       handle,
691       studyId);
692     return iobject._retn();
693   }
694
695   // If it's not a Python or a C++ component try to launch a standalone component
696   // in a sub directory
697   // This component is implemented in an executable with name genericRegisterName.exe
698   // It must register itself in Naming Service. The container waits some time (10 s max)
699   // it's registration.
700
701   _numInstanceMutex.lock() ; // lock on the instance number
702   _numInstance++ ;
703   int numInstance = _numInstance ;
704   _numInstanceMutex.unlock() ;
705
706   char aNumI[12];
707   sprintf( aNumI , "%d" , numInstance ) ;
708   string instanceName = aCompName + "_inst_" + aNumI ;
709   string component_registerName = _containerName + "/" + instanceName;
710
711   //check if an entry exist in naming service
712   CORBA::Object_var nsobj = _NS->Resolve(component_registerName.c_str());
713   if ( !CORBA::is_nil(nsobj) )
714   {
715     // unregister the registered component
716     _NS->Destroy_Name(component_registerName.c_str());
717     //kill or shutdown it ???
718   }
719
720   // first arg container ior string
721   // second arg container name
722   // third arg instance name
723
724   Engines::Container_var pCont= _this();
725   CORBA::String_var sior =  _orb->object_to_string(pCont);
726
727   std::string command;
728   command="mkdir -p ";
729   command+=instanceName;
730   command+=";cd ";
731   command+=instanceName;
732   command+=";";
733   command+=genericRegisterName ;
734   command+=".exe";
735   command+=" ";
736   command+= sior; // container ior string
737   command+=" ";
738   command+=_containerName; //container name
739   command+=" ";
740   command+=instanceName; //instance name
741   command+=" &";
742   MESSAGE("SALOME_Container::create_component_instance command=" << command);
743
744 #ifndef WIN32
745   // use fork/execl instead of system to get finer control on env variables
746   int status;
747   pid_t pid = fork();
748   if(pid == 0) // child
749     {
750       for (CORBA::ULong i=0; i < env.length(); i++)
751         {
752           if (env[i].value.type()->kind() == CORBA::tk_string)
753             {
754               const char* value;
755               env[i].value >>= value;
756               std::string s(env[i].key);
757               s+='=';
758               s+=value;
759               putenv(strdup(s.c_str()));
760             }
761         }
762
763       execl("/bin/sh", "sh", "-c", command.c_str() , (char *)0);
764       status=-1;
765     }
766   else if(pid < 0)       // failed to fork
767     {
768       status=-1;
769     }
770   else            //parent
771     {
772       pid_t tpid;
773       do
774         {
775           tpid = wait(&status);
776         } while (tpid != pid);
777     }
778 #else
779   // launch component with a system call
780   int status=system(command.c_str());
781 #endif
782
783   if (status == -1)
784   {
785     MESSAGE("SALOME_Container::create_component_instance system failed " << "(system command status -1)");
786     return Engines::Component::_nil();
787   }
788 #ifndef WIN32
789   else if (WEXITSTATUS(status) == 217)
790   {
791     MESSAGE("SALOME_Container::create_component_instance system failed " << "(system command status 217)");
792     return Engines::Component::_nil();
793   }
794 #endif
795   else
796   {
797     int count=20;
798     CORBA::Object_var obj = CORBA::Object::_nil() ;
799     while ( CORBA::is_nil(obj) && count )
800     {
801 #ifndef WIN32
802       sleep( 1 ) ;
803 #else
804       Sleep(1000);
805 #endif
806       count-- ;
807       MESSAGE( count << ". Waiting for component " << genericRegisterName);
808       obj = _NS->Resolve(component_registerName.c_str());
809     }
810
811     if(CORBA::is_nil(obj))
812     {
813       MESSAGE("SALOME_Container::create_component_instance failed");
814       return Engines::Component::_nil();
815     }
816     else
817     {
818       MESSAGE("SALOME_Container::create_component_instance successful");
819       iobject=Engines::Component::_narrow(obj);
820       _listInstances_map[instanceName] = iobject;
821       return iobject._retn();
822     }
823   }
824 }
825
826 //=============================================================================
827 //! Find an existing (in the container) component instance
828 /*! 
829 *  CORBA method: Finds a servant instance of a component
830 *  \param registeredName  Name of the component in Registry or Name Service,
831 *                         without instance suffix number
832 *  \param studyId         0 if instance is not associated to a study, 
833 *                         >0 otherwise (== study id)
834 *  \return the first instance found with same studyId
835 */
836 //=============================================================================
837
838 Engines::Component_ptr
839 Engines_Container_i::find_component_instance( const char* registeredName,
840                                              CORBA::Long studyId)
841 {
842   Engines::Component_var anEngine = Engines::Component::_nil();
843   map<string,Engines::Component_var>::iterator itm =_listInstances_map.begin();
844   while (itm != _listInstances_map.end())
845   {
846     string instance = (*itm).first;
847     SCRUTE(instance);
848     if (instance.find(registeredName) == 0)
849     {
850       anEngine = (*itm).second;
851       if (studyId == anEngine->getStudyId())
852       {
853         return anEngine._retn();
854       }
855     }
856     itm++;
857   }
858   return anEngine._retn();  
859 }
860
861 //=============================================================================
862 //! Find or create a new component instance
863 /*! 
864 *  CORBA method: find or create an instance of the component (servant),
865 *  load a new component class (dynamic library) if required,
866 *
867 *  ---- FOR COMPATIBILITY WITH 2.2 ---- 
868 *
869 *  ---- USE ONLY FOR MULTISTUDY INSTANCES ! --------
870 *
871 *  The servant registers itself to naming service and Registry.
872 *  \param genericRegisterName  Name of the component to register
873 *                              in Registry & Name Service
874 *  \param componentName       Name of the constructed library of the component
875 *  \return a loaded component
876 */
877 //=============================================================================
878
879 Engines::Component_ptr
880 Engines_Container_i::load_impl( const char* genericRegisterName,
881                                const char* componentName )
882 {
883   string impl_name = string ("lib") + genericRegisterName +string("Engine.so");
884   Engines::Component_var iobject = Engines::Component::_nil() ;
885   if (load_component_Library(genericRegisterName))
886     iobject = find_or_create_instance(genericRegisterName, impl_name);
887   return iobject._retn();
888 }
889
890
891 //=============================================================================
892 //! Remove the component instance from container
893 /*! 
894 *  CORBA method: Stops the component servant, and deletes all related objects
895 *  \param component_i     Component to be removed
896 */
897 //=============================================================================
898
899 void Engines_Container_i::remove_impl(Engines::Component_ptr component_i)
900 {
901   ASSERT(! CORBA::is_nil(component_i));
902   string instanceName = component_i->instanceName() ;
903   MESSAGE("unload component " << instanceName);
904   _numInstanceMutex.lock() ; // lock to be alone (stl container write)
905   _listInstances_map.erase(instanceName);
906   _numInstanceMutex.unlock() ;
907   component_i->destroy() ;
908   _NS->Destroy_Name(instanceName.c_str());
909 }
910
911 //=============================================================================
912 //! Unload component libraries from the container
913 /*! 
914 *  CORBA method: Discharges unused libraries from the container.
915 */
916 //=============================================================================
917
918 void Engines_Container_i::finalize_removal()
919 {
920   MESSAGE("finalize unload : dlclose");
921   _numInstanceMutex.lock(); // lock to be alone
922   // (see decInstanceCnt, load_component_Library)
923   map<string, void *>::iterator ith;
924   for (ith = _toRemove_map.begin(); ith != _toRemove_map.end(); ith++)
925   {
926     void *handle = (*ith).second;
927     string impl_name= (*ith).first;
928     if (handle)
929     {
930       SCRUTE(handle);
931       SCRUTE(impl_name);
932       //        dlclose(handle);                // SALOME unstable after ...
933       //        _library_map.erase(impl_name);
934     }
935   }
936   _toRemove_map.clear();
937   _numInstanceMutex.unlock();
938 }
939
940 //=============================================================================
941 //! Kill the container
942 /*! 
943 *  CORBA method: Kill the container process with exit(0).
944 *  To remove :  never returns !
945 */
946 //=============================================================================
947
948 bool Engines_Container_i::Kill_impl()
949 {
950   MESSAGE("Engines_Container_i::Kill() pid "<< getpid() << " containerName "
951     << _containerName.c_str() << " machineName "
952     << Kernel_Utils::GetHostname().c_str());
953   INFOS("===============================================================");
954   INFOS("= REMOVE calls to Kill_impl in C++ container                  =");
955   INFOS("===============================================================");
956   //exit( 0 ) ;
957   ASSERT(0);
958   return false;
959 }
960
961 //=============================================================================
962 //! Get or create a file reference object associated to a local file (to transfer it)
963 /*! 
964 *  CORBA method: get or create a fileRef object associated to a local file
965 *  (a file on the computer on which runs the container server), which stores
966 *  a list of (machine, localFileName) corresponding to copies already done.
967
968 *  \param  origFileName absolute path for a local file to copy on other
969 *          computers
970 *  \return a fileRef object associated to the file.
971 */
972 //=============================================================================
973
974 Engines::fileRef_ptr
975 Engines_Container_i::createFileRef(const char* origFileName)
976 {
977   string origName(origFileName);
978   Engines::fileRef_var theFileRef = Engines::fileRef::_nil();
979
980   if (origName[0] != '/')
981   {
982     INFOS("path of file to copy must be an absolute path begining with '/'");
983     return Engines::fileRef::_nil();
984   }
985
986   if (CORBA::is_nil(_fileRef_map[origName]))
987   {
988     CORBA::Object_var obj=_poa->id_to_reference(*_id);
989     Engines::Container_var pCont = Engines::Container::_narrow(obj);
990     fileRef_i* aFileRef = new fileRef_i(pCont, origFileName);
991     theFileRef = Engines::fileRef::_narrow(aFileRef->_this());
992     _numInstanceMutex.lock() ; // lock to be alone (stl container write)
993     _fileRef_map[origName] = theFileRef;
994     _numInstanceMutex.unlock() ;
995   }
996
997   theFileRef =  Engines::fileRef::_duplicate(_fileRef_map[origName]);
998   ASSERT(! CORBA::is_nil(theFileRef));
999   return theFileRef._retn();
1000 }
1001
1002 //=============================================================================
1003 //! Get a fileTransfer reference
1004 /*! 
1005 *  CORBA method:
1006 *  \return a reference to the fileTransfer object
1007 */
1008 //=============================================================================
1009
1010 Engines::fileTransfer_ptr
1011 Engines_Container_i::getFileTransfer()
1012 {
1013   Engines::fileTransfer_var aFileTransfer
1014     = Engines::fileTransfer::_duplicate(_fileTransfer);
1015   return aFileTransfer._retn();
1016 }
1017
1018
1019 //! Create a Salome file
1020 Engines::Salome_file_ptr 
1021 Engines_Container_i::createSalome_file(const char* origFileName) 
1022 {
1023   string origName(origFileName);
1024   if (CORBA::is_nil(_Salome_file_map[origName]))
1025   {
1026     Salome_file_i* aSalome_file = new Salome_file_i();
1027     aSalome_file->setContainer(Engines::Container::_duplicate(this->_this()));
1028     try 
1029     {
1030       aSalome_file->setLocalFile(origFileName);
1031       aSalome_file->recvFiles();
1032     }
1033     catch (const SALOME::SALOME_Exception& e)
1034     {
1035       return Engines::Salome_file::_nil();
1036     }
1037
1038     Engines::Salome_file_var theSalome_file = Engines::Salome_file::_nil();
1039     theSalome_file = Engines::Salome_file::_narrow(aSalome_file->_this());
1040     _numInstanceMutex.lock() ; // lock to be alone (stl container write)
1041     _Salome_file_map[origName] = theSalome_file;
1042     _numInstanceMutex.unlock() ;
1043   }
1044
1045   Engines::Salome_file_ptr theSalome_file =  
1046     Engines::Salome_file::_duplicate(_Salome_file_map[origName]);
1047   ASSERT(!CORBA::is_nil(theSalome_file));
1048   return theSalome_file;
1049 }
1050 //=============================================================================
1051 //! Finds an already existing component instance or create a new instance
1052 /*! 
1053 *  C++ method: Finds an already existing servant instance of a component, or
1054 *              create an instance.
1055 *  ---- USE ONLY FOR MULTISTUDY INSTANCES ! --------
1056 *  \param genericRegisterName    Name of the component instance to register
1057 *                                in Registry & Name Service,
1058 *                                (without _inst_n suffix, like "COMPONENT")
1059 *  \param componentLibraryName   like "libCOMPONENTEngine.so"
1060 *  \return a loaded component
1061
1062 *  example with names:
1063 *    - aGenRegisterName = COMPONENT (= first argument)
1064 *    - impl_name = libCOMPONENTEngine.so (= second argument)
1065 *    - _containerName = /Containers/cli76ce/FactoryServer
1066 *    - factoryName = COMPONENTEngine_factory
1067 *    - component_registerBase = /Containers/cli76ce/FactoryServer/COMPONENT
1068 *    - instanceName = COMPONENT_inst_1
1069 *    - component_registerName = /Containers/cli76ce/FactoryServer/COMPONENT_inst_1
1070 */
1071 //=============================================================================
1072
1073 Engines::Component_ptr
1074 Engines_Container_i::find_or_create_instance(std::string genericRegisterName,
1075                                              std::string componentLibraryName)
1076 {
1077   string aGenRegisterName = genericRegisterName;
1078   string impl_name = componentLibraryName;
1079   if (_library_map.count(impl_name) == 0) 
1080   {
1081     INFOS("shared library " << impl_name <<" must be loaded before creating instance");
1082     return Engines::Component::_nil() ;
1083   }
1084   else
1085   {
1086     // --- find a registered instance in naming service, or create
1087
1088     void* handle = _library_map[impl_name];
1089     string component_registerBase =
1090       _containerName + "/" + aGenRegisterName;
1091     Engines::Component_var iobject = Engines::Component::_nil() ;
1092     try
1093     {
1094       CORBA::Object_var obj =
1095         _NS->ResolveFirst( component_registerBase.c_str());
1096       if ( CORBA::is_nil( obj ) )
1097       {
1098         iobject = createInstance(genericRegisterName,
1099           handle,
1100           0); // force multiStudy instance here !
1101       }
1102       else
1103       { 
1104         iobject = Engines::Component::_narrow( obj ) ;
1105         Engines_Component_i *servant =
1106           dynamic_cast<Engines_Component_i*>
1107           (_poa->reference_to_servant(iobject));
1108         ASSERT(servant)
1109           int studyId = servant->getStudyId();
1110         ASSERT (studyId >= 0);
1111         if (studyId == 0) // multiStudy instance, OK
1112         {
1113           // No ReBind !
1114           MESSAGE(component_registerBase.c_str()<<" already bound");
1115         }
1116         else // monoStudy instance: NOK
1117         {
1118           iobject = Engines::Component::_nil();
1119           INFOS("load_impl & find_component_instance methods "
1120             << "NOT SUITABLE for mono study components");
1121         }
1122       }
1123     }
1124     catch (...)
1125     {
1126       INFOS( "Container_i::load_impl catched" ) ;
1127     }
1128     return iobject._retn();
1129   }
1130 }
1131
1132 //=============================================================================
1133 //! Create a new component instance 
1134 /*! 
1135 *  C++ method: create a servant instance of a component.
1136 *  \param genericRegisterName    Name of the component instance to register
1137 *                                in Registry & Name Service,
1138 *                                (without _inst_n suffix, like "COMPONENT")
1139 *  \param handle                 loaded library handle
1140 *  \param studyId                0 for multiStudy instance, 
1141 *                                study Id (>0) otherwise
1142 *  \return a loaded component
1143
1144 *  example with names:
1145 *    - aGenRegisterName = COMPONENT (= first argument)
1146 *    - _containerName = /Containers/cli76ce/FactoryServer
1147 *    - factoryName = COMPONENTEngine_factory
1148 *    - component_registerBase = /Containers/cli76ce/FactoryServer/COMPONENT
1149 *    - instanceName = COMPONENT_inst_1
1150 *    - component_registerName = /Containers/cli76ce/FactoryServer/COMPONENT_inst_1
1151 */
1152 //=============================================================================
1153
1154 Engines::Component_ptr
1155 Engines_Container_i::createInstance(std::string genericRegisterName,
1156                                     void *handle,
1157                                     int studyId)
1158 {
1159   // --- find the factory
1160
1161   string aGenRegisterName = genericRegisterName;
1162   string factory_name = aGenRegisterName + string("Engine_factory");
1163   SCRUTE(factory_name) ;
1164
1165   typedef  PortableServer::ObjectId * (*FACTORY_FUNCTION)
1166     (CORBA::ORB_ptr,
1167     PortableServer::POA_ptr, 
1168     PortableServer::ObjectId *, 
1169     const char *, 
1170     const char *) ;
1171
1172 #ifndef WIN32
1173   FACTORY_FUNCTION Component_factory = (FACTORY_FUNCTION)dlsym( handle, factory_name.c_str() );
1174 #else
1175   FACTORY_FUNCTION Component_factory = (FACTORY_FUNCTION)GetProcAddress( (HINSTANCE)handle, factory_name.c_str() );
1176 #endif
1177
1178   if ( !Component_factory )
1179   {
1180     INFOS( "Can't resolve symbol: " + factory_name );
1181 #ifndef WIN32
1182     SCRUTE( dlerror() );
1183 #endif
1184     return Engines::Component::_nil() ;
1185   }
1186
1187   // --- create instance
1188
1189   Engines::Component_var iobject = Engines::Component::_nil() ;
1190
1191   try
1192   {
1193     _numInstanceMutex.lock() ; // lock on the instance number
1194     _numInstance++ ;
1195     int numInstance = _numInstance ;
1196     _numInstanceMutex.unlock() ;
1197
1198     char aNumI[12];
1199     sprintf( aNumI , "%d" , numInstance ) ;
1200     string instanceName = aGenRegisterName + "_inst_" + aNumI ;
1201     string component_registerName =
1202       _containerName + "/" + instanceName;
1203
1204     // --- Instanciate required CORBA object
1205
1206     PortableServer::ObjectId *id ; //not owner, do not delete (nore use var)
1207     id = (Component_factory) ( _orb, _poa, _id, instanceName.c_str(),
1208       aGenRegisterName.c_str() ) ;
1209     if (id == NULL)
1210       return iobject._retn();
1211
1212     // --- get reference & servant from id
1213
1214     CORBA::Object_var obj = _poa->id_to_reference(*id);
1215     iobject = Engines::Component::_narrow( obj ) ;
1216
1217     Engines_Component_i *servant =
1218       dynamic_cast<Engines_Component_i*>(_poa->reference_to_servant(iobject));
1219     ASSERT(servant);
1220     //SCRUTE(servant->_refcount_value());
1221     _numInstanceMutex.lock() ; // lock to be alone (stl container write)
1222     _listInstances_map[instanceName] = iobject;
1223     _cntInstances_map[aGenRegisterName] += 1;
1224     _numInstanceMutex.unlock() ;
1225     SCRUTE(aGenRegisterName);
1226     SCRUTE(_cntInstances_map[aGenRegisterName]);
1227     servant->setStudyId(studyId);
1228     servant->_remove_ref(); // do not need servant any more (remove ref from reference_to_servant)
1229     //SCRUTE(servant->_refcount_value());
1230
1231     // --- register the engine under the name
1232     //     containerName(.dir)/instanceName(.object)
1233
1234     _NS->Register( iobject , component_registerName.c_str() ) ;
1235     MESSAGE( component_registerName.c_str() << " bound" ) ;
1236   }
1237   catch (...)
1238   {
1239     INFOS( "Container_i::createInstance exception catched" ) ;
1240   }
1241   return iobject._retn();
1242 }
1243
1244 //=============================================================================
1245 //! Decrement component instance reference count
1246 /*! 
1247 *
1248 */
1249 //=============================================================================
1250
1251 void Engines_Container_i::decInstanceCnt(std::string genericRegisterName)
1252 {
1253   if(_cntInstances_map.count(genericRegisterName)==0)
1254     return;
1255   string aGenRegisterName =genericRegisterName;
1256   MESSAGE("Engines_Container_i::decInstanceCnt " << aGenRegisterName);
1257   ASSERT(_cntInstances_map[aGenRegisterName] > 0); 
1258   _numInstanceMutex.lock(); // lock to be alone
1259   // (see finalize_removal, load_component_Library)
1260   _cntInstances_map[aGenRegisterName] -= 1;
1261   SCRUTE(_cntInstances_map[aGenRegisterName]);
1262   if (_cntInstances_map[aGenRegisterName] == 0)
1263   {
1264     string impl_name =
1265       Engines_Component_i::GetDynLibraryName(aGenRegisterName.c_str());
1266     SCRUTE(impl_name);
1267     void* handle = _library_map[impl_name];
1268     ASSERT(handle);
1269     _toRemove_map[impl_name] = handle;
1270   }
1271   _numInstanceMutex.unlock();
1272 }
1273
1274 //=============================================================================
1275 //! Indicate if container is a python one
1276 /*! 
1277 *  Retrieves only with container naming convention if it is a python container
1278 */
1279 //=============================================================================
1280
1281 bool Engines_Container_i::isPythonContainer(const char* ContainerName)
1282 {
1283   bool ret=false;
1284   int len=strlen(ContainerName);
1285   if(len>=2)
1286     if(strcmp(ContainerName+len-2,"Py")==0)
1287       ret=true;
1288   return ret;
1289 }
1290
1291 //=============================================================================
1292 /*! 
1293 *  
1294 */
1295 //=============================================================================
1296
1297 void ActSigIntHandler()
1298 {
1299 #ifndef WIN32
1300   struct sigaction SigIntAct ;
1301   SigIntAct.sa_sigaction = &SigIntHandler ;
1302   sigemptyset(&SigIntAct.sa_mask);
1303   SigIntAct.sa_flags = SA_SIGINFO ;
1304 #endif
1305
1306   // DEBUG 03.02.2005 : the first parameter of sigaction is not a mask of signals
1307   // (SIGINT | SIGUSR1) :
1308   // it must be only one signal ===> one call for SIGINT 
1309   // and an other one for SIGUSR1
1310
1311 #ifndef WIN32
1312   if ( sigaction( SIGINT , &SigIntAct, NULL ) ) 
1313   {
1314     perror("SALOME_Container main ") ;
1315     exit(0) ;
1316   }
1317   if ( sigaction( SIGUSR1 , &SigIntAct, NULL ) )
1318   {
1319     perror("SALOME_Container main ") ;
1320     exit(0) ;
1321   }
1322   if ( sigaction( SIGUSR2 , &SigIntAct, NULL ) )
1323   {
1324     perror("SALOME_Container main ") ;
1325     exit(0) ;
1326   }
1327
1328   //PAL9042 JR : during the execution of a Signal Handler (and of methods called through Signal Handlers)
1329   //             use of streams (and so on) should never be used because :
1330   //             streams of C++ are naturally thread-safe and use pthread_mutex_lock ===>
1331   //             A stream operation may be interrupted by a signal and if the Handler use stream we
1332   //             may have a "Dead-Lock" ===HangUp
1333   //==INFOS is commented
1334   //  INFOS(pthread_self() << "SigIntHandler activated") ;
1335
1336 #else  
1337   signal( SIGINT, SigIntHandler );
1338   signal( SIGUSR1, SigIntHandler );
1339 #endif
1340
1341 }
1342
1343 void SetCpuUsed() ;
1344 void CallCancelThread() ;
1345
1346 #ifndef WIN32
1347 void SigIntHandler(int what ,
1348                    siginfo_t * siginfo ,
1349                    void * toto ) 
1350 {
1351   //PAL9042 JR : during the execution of a Signal Handler (and of methods called through Signal Handlers)
1352   //             use of streams (and so on) should never be used because :
1353   //             streams of C++ are naturally thread-safe and use pthread_mutex_lock ===>
1354   //             A stream operation may be interrupted by a signal and if the Handler use stream we
1355   //             may have a "Dead-Lock" ===HangUp
1356   //==MESSAGE is commented
1357   //  MESSAGE(pthread_self() << "SigIntHandler what     " << what << endl
1358   //          << "              si_signo " << siginfo->si_signo << endl
1359   //          << "              si_code  " << siginfo->si_code << endl
1360   //          << "              si_pid   " << siginfo->si_pid) ;
1361
1362   if ( _Sleeping )
1363   {
1364     _Sleeping = false ;
1365     //     MESSAGE("SigIntHandler END sleeping.") ;
1366     return ;
1367   }
1368   else
1369   {
1370     ActSigIntHandler() ;
1371     if ( siginfo->si_signo == SIGUSR1 )
1372     {
1373       SetCpuUsed() ;
1374     }
1375     else if ( siginfo->si_signo == SIGUSR2 )
1376     {
1377       CallCancelThread() ;
1378     }
1379     else 
1380     {
1381       _Sleeping = true ;
1382       //      MESSAGE("SigIntHandler BEGIN sleeping.") ;
1383       int count = 0 ;
1384       while( _Sleeping )
1385       {
1386         sleep( 1 ) ;
1387         count += 1 ;
1388       }
1389       //      MESSAGE("SigIntHandler LEAVE sleeping after " << count << " s.") ;
1390     }
1391     return ;
1392   }
1393 }
1394 #else // Case WIN32
1395 void SigIntHandler( int what )
1396 {
1397 #ifndef WIN32
1398   MESSAGE( pthread_self() << "SigIntHandler what     " << what << endl );
1399 #else
1400   MESSAGE( "SigIntHandler what     " << what << endl );
1401 #endif
1402   if ( _Sleeping )
1403   {
1404     _Sleeping = false ;
1405     MESSAGE("SigIntHandler END sleeping.") ;
1406     return ;
1407   }
1408   else
1409   {
1410     ActSigIntHandler() ;
1411     if ( what == SIGUSR1 )
1412     {
1413       SetCpuUsed() ;
1414     }
1415     else
1416     {
1417       _Sleeping = true ;
1418       MESSAGE("SigIntHandler BEGIN sleeping.") ;
1419       int count = 0 ;
1420       while( _Sleeping ) 
1421       {
1422         Sleep( 1000 ) ;
1423         count += 1 ;
1424       }
1425       MESSAGE("SigIntHandler LEAVE sleeping after " << count << " s.") ;
1426     }
1427     return ;
1428   }
1429 }
1430 #endif
1431
1432 /*! \brief copy a file from a remote host (container) to the local host
1433  * \param container the remote container
1434  * \param remoteFile the file to copy locally from the remote host into localFile
1435  * \param localFile the local file
1436  */
1437 void Engines_Container_i::copyFile(Engines::Container_ptr container, const char* remoteFile, const char* localFile)
1438 {
1439   Engines::fileTransfer_var fileTransfer = container->getFileTransfer();
1440
1441   FILE* fp;
1442   if ((fp = fopen(localFile,"wb")) == NULL)
1443     {
1444       INFOS("file " << localFile << " cannot be open for writing");
1445       return;
1446     }
1447
1448   CORBA::Long fileId = fileTransfer->open(remoteFile);
1449   if (fileId > 0)
1450     {
1451       Engines::fileBlock* aBlock;
1452       int toFollow = 1;
1453       int ctr=0;
1454       while (toFollow)
1455         {
1456           ctr++;
1457           SCRUTE(ctr);
1458           aBlock = fileTransfer->getBlock(fileId);
1459           toFollow = aBlock->length();
1460           SCRUTE(toFollow);
1461           CORBA::Octet *buf = aBlock->get_buffer();
1462           fwrite(buf, sizeof(CORBA::Octet), toFollow, fp);
1463           delete aBlock;
1464         }
1465       fclose(fp);
1466       MESSAGE("end of transfer");
1467       fileTransfer->close(fileId);
1468     }
1469   else
1470     {
1471       INFOS("open reference file for copy impossible");
1472     }
1473 }
1474
1475 /*! \brief create a PyNode object to execute remote python code
1476  * \param nodeName the name of the node
1477  * \param code the python code to load
1478  * \return the PyNode
1479  */
1480 Engines::PyNode_ptr Engines_Container_i::createPyNode(const char* nodeName, const char* code)
1481 {
1482     Engines::PyNode_var node= Engines::PyNode::_nil();
1483
1484     PyGILState_STATE gstate = PyGILState_Ensure();
1485     PyObject *res = PyObject_CallMethod(_pyCont,
1486       (char*)"create_pynode",
1487       (char*)"ss",
1488       nodeName,
1489       code);
1490     if(res==NULL)
1491       {
1492         //internal error
1493         PyErr_Print();
1494         PyGILState_Release(gstate);
1495         SALOME::ExceptionStruct es;
1496         es.type = SALOME::INTERNAL_ERROR;
1497         es.text = "can not create a python node";
1498         throw SALOME::SALOME_Exception(es);
1499       }
1500     long ierr=PyInt_AsLong(PyTuple_GetItem(res,0));
1501     PyObject* result=PyTuple_GetItem(res,1);
1502     std::string astr=PyString_AsString(result);
1503     Py_DECREF(res);
1504     PyGILState_Release(gstate);
1505
1506     if(ierr==0)
1507       {
1508         CORBA::Object_var obj = _orb->string_to_object(astr.c_str());
1509         node = Engines::PyNode::_narrow(obj);
1510         return node._retn();
1511       }
1512     else
1513       {
1514         SALOME::ExceptionStruct es;
1515         es.type = SALOME::INTERNAL_ERROR;
1516         es.text = astr.c_str();
1517         throw SALOME::SALOME_Exception(es);
1518       }
1519
1520 }