Salome HOME
updated copyright message
[modules/yacs.git] / src / runtime / DistributedPythonNode.cxx
index cb65eb18608d9d3a8d404c43894c80a96760d2ea..6696f3a2b23d5417901cf420d2a4470c293d13ba 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (C) 2006-2014  CEA/DEN, EDF R&D
+// Copyright (C) 2006-2023  CEA/DEN, EDF R&D
 //
 // This library is free software; you can redistribute it and/or
 // modify it under the terms of the GNU Lesser General Public
@@ -21,6 +21,9 @@
 #include "RuntimeSALOME.hxx"
 #include "SalomeContainer.hxx"
 #include "PythonNode.hxx"
+#include "SalomeHPContainer.hxx"
+#include "SalomeContainerTmpForHP.hxx"
+#include "PythonCppUtils.hxx"
 
 #include "PythonPorts.hxx"
 #include "YacsTrace.hxx"
@@ -50,168 +53,216 @@ DistributedPythonNode::DistributedPythonNode(const DistributedPythonNode& other,
 
 DistributedPythonNode::~DistributedPythonNode()
 {
-  PyGILState_STATE gstate = PyGILState_Ensure();
+  AutoGIL agil;
   Py_DECREF(_context);
-  PyGILState_Release(gstate);
 }
 
 void DistributedPythonNode::load()
 {
+  bool isContAlreadyStarted(false);
+  if(_container)
+    isContAlreadyStarted=_container->isAlreadyStarted(this);
   ServerNode::load();
-  PyGILState_STATE gstate = PyGILState_Ensure();
-  if( PyDict_SetItemString( _context, "__builtins__", getSALOMERuntime()->getBuiltins() ))
+  {
+    AutoGIL agil;
+    if( PyDict_SetItemString( _context, "__builtins__", getSALOMERuntime()->getBuiltins() ))
+      {
+        stringstream msg;
+        msg << "Impossible to set builtins" << __FILE__ << ":" << __LINE__;
+        _errorDetails=msg.str();
+        throw Exception(msg.str());
+      }
+    const char picklizeScript[]="import pickle\ndef pickleForDistPyth2009(*args,**kws):\n  return pickle.dumps((args,kws),-1)\n\ndef unPickleForDistPyth2009(st):\n  args=pickle.loads(st)\n  return args\n";
+    PyObject *res=PyRun_String(picklizeScript,Py_file_input,_context,_context);
+    if(res == NULL)
+      {
+        _errorDetails="";
+        PyObject* new_stderr = newPyStdOut(_errorDetails);
+        PySys_SetObject((char*)"stderr", new_stderr);
+        PyErr_Print();
+        PySys_SetObject((char*)"stderr", PySys_GetObject((char*)"__stderr__"));
+        Py_DECREF(new_stderr);
+        throw Exception("Error during execution");
+        return;
+      }
+    Py_DECREF(res);
+    _pyfuncSer=PyDict_GetItemString(_context,"pickleForDistPyth2009");
+    _pyfuncUnser=PyDict_GetItemString(_context,"unPickleForDistPyth2009");
+    if(_pyfuncSer == NULL)
+      {
+        _errorDetails="";
+        PyObject* new_stderr = newPyStdOut(_errorDetails);
+        PySys_SetObject((char*)"stderr", new_stderr);
+        PyErr_Print();
+        PySys_SetObject((char*)"stderr", PySys_GetObject((char*)"__stderr__"));
+        Py_DECREF(new_stderr);
+        throw Exception("Error during execution");
+      }
+    if(_pyfuncUnser == NULL)
+      {
+        _errorDetails="";
+        PyObject* new_stderr = newPyStdOut(_errorDetails);
+        PySys_SetObject((char*)"stderr", new_stderr);
+        PyErr_Print();
+        PySys_SetObject((char*)"stderr", PySys_GetObject((char*)"__stderr__"));
+        Py_DECREF(new_stderr);
+        throw Exception("Error during execution");
+      }
+
+    Engines::Container_var objContainer=Engines::Container::_nil();
+    if(!_container)
+      throw Exception("No container specified !");
+    SalomeContainer *containerCast0(dynamic_cast<SalomeContainer *>(_container));
+    SalomeHPContainer *containerCast1(dynamic_cast<SalomeHPContainer *>(_container));
+    if(containerCast0)
+      objContainer=containerCast0->getContainerPtr(this);
+    else if(containerCast1)
+      {
+        YACS::BASES::AutoCppPtr<SalomeContainerTmpForHP> tmpCont(SalomeContainerTmpForHP::BuildFrom(containerCast1,this));
+        objContainer=tmpCont->getContainerPtr(this);
+      }
+    else
+      throw Exception("Unrecognized type of container ! Salome one is expected !");
+    if(CORBA::is_nil(objContainer))
+      throw Exception("Container corba pointer is NULL !");
+
+    try
     {
-      stringstream msg;
-      msg << "Impossible to set builtins" << __FILE__ << ":" << __LINE__;
-      PyGILState_Release(gstate);
-      _errorDetails=msg.str();
-      throw Exception(msg.str());
+        if(containerCast0 || !isContAlreadyStarted)
+          {
+            _pynode = objContainer->createPyNode(getName().c_str(),getScript().c_str());
+          }
+        else
+          {
+            Engines::PyNode_var dftPyScript(objContainer->getDefaultPyNode(getName().c_str()));
+            if(CORBA::is_nil(dftPyScript))
+              _pynode = objContainer->createPyNode(getName().c_str(),getScript().c_str());
+            else
+              _pynode = dftPyScript;
+          }
     }
-  const char picklizeScript[]="import cPickle\ndef pickleForDistPyth2009(*args,**kws):\n  return cPickle.dumps((args,kws),-1)\n\ndef unPickleForDistPyth2009(st):\n  args=cPickle.loads(st)\n  return args\n";
-  PyObject *res=PyRun_String(picklizeScript,Py_file_input,_context,_context);
-  if(res == NULL)
+    catch( const SALOME::SALOME_Exception& ex )
     {
-      _errorDetails="";
-      PyObject* new_stderr = newPyStdOut(_errorDetails);
-      PySys_SetObject((char*)"stderr", new_stderr);
-      PyErr_Print();
-      PySys_SetObject((char*)"stderr", PySys_GetObject((char*)"__stderr__"));
-      Py_DECREF(new_stderr);
-
-      PyGILState_Release(gstate);
-      throw Exception("Error during execution");
-      return;
+        std::string msg="Exception on remote python node creation ";
+        msg += '\n';
+        msg += ex.details.text.in();
+        _errorDetails=msg;
+        throw Exception(msg);
     }
-  Py_DECREF(res);
-  _pyfuncSer=PyDict_GetItemString(_context,"pickleForDistPyth2009");
-  _pyfuncUnser=PyDict_GetItemString(_context,"unPickleForDistPyth2009");
-  if(_pyfuncSer == NULL)
-    {
-      _errorDetails="";
-      PyObject* new_stderr = newPyStdOut(_errorDetails);
-      PySys_SetObject((char*)"stderr", new_stderr);
-      PyErr_Print();
-      PySys_SetObject((char*)"stderr", PySys_GetObject((char*)"__stderr__"));
-      Py_DECREF(new_stderr);
 
-      PyGILState_Release(gstate);
-      throw Exception("Error during execution");
-    }
-  if(_pyfuncUnser == NULL)
-    {
-      _errorDetails="";
-      PyObject* new_stderr = newPyStdOut(_errorDetails);
-      PySys_SetObject((char*)"stderr", new_stderr);
-      PyErr_Print();
-      PySys_SetObject((char*)"stderr", PySys_GetObject((char*)"__stderr__"));
-      Py_DECREF(new_stderr);
+    if(CORBA::is_nil(_pynode))
+      throw Exception("In DistributedPythonNode the ref in NULL ! ");
 
-      PyGILState_Release(gstate);
-      throw Exception("Error during execution");
-    }
-  DEBTRACE( "---------------End PyfuncSerNode::load function---------------" );
-  PyGILState_Release(gstate);
+
+    DEBTRACE( "---------------End PyfuncSerNode::load function---------------" );
+  }
 }
 
 void DistributedPythonNode::execute()
 {
   YACSTRACE(1,"+++++++++++++++++ DistributedPythonNode::execute: " << getName() << " " << getFname() << " +++++++++++++++++" );
+  //////
+  PyObject* ob;
+  if(!_pyfuncSer)
+    throw Exception("DistributedPythonNode badly loaded");
+  Engines::pickledArgs *serializationInputCorba(0);
+  PyObject *args(0);
   {
-    Engines::Container_var objContainer=((SalomeContainer*)_container)->getContainerPtr(this);
-    Engines::PyNode_var pn=objContainer->createPyNode(getName().c_str(),getScript().c_str());
-    //////
-    int pos=0;
-    PyObject* ob;
-    if(!_pyfuncSer)
-      throw Exception("DistributedPythonNode badly loaded");
-    PyGILState_STATE gstate = PyGILState_Ensure();
-    
+    AutoGIL agil;
+
     DEBTRACE( "---------------DistributedPythonNode::inputs---------------" );
-    PyObject* args = PyTuple_New(getNumberOfInputPorts()) ;
-    list<InputPort *>::iterator iter2;
-    for(iter2 = _setOfInputPort.begin(); iter2 != _setOfInputPort.end(); iter2++)
+    args = PyTuple_New(getNumberOfInputPorts()) ;
+    int pos=0;
+    for(list<InputPort *>::iterator iter2 = _setOfInputPort.begin(); iter2 != _setOfInputPort.end(); iter2++,pos++)
       {
         InputPyPort *p=(InputPyPort *)*iter2;
         ob=p->getPyObj();
         Py_INCREF(ob);
         PyTuple_SetItem(args,pos,ob);
-        pos++;
       }
     PyObject *serializationInput=PyObject_CallObject(_pyfuncSer,args);
-    std::string serializationInputC=PyString_AsString(serializationInput);
-    Engines::pickledArgs *serializationInputCorba=new Engines::pickledArgs;
-    int len=serializationInputC.length();
-    serializationInputCorba->length(serializationInputC.length());
-    for(int i=0;i<serializationInputC.length();i++)
+    Py_ssize_t len = PyBytes_Size(serializationInput);
+    char* serializationInputC = PyBytes_AsString(serializationInput);
+    //int ret = PyBytes_AsStringAndSize(serializationInput, &serializationInputC, &len);
+    serializationInputCorba=new Engines::pickledArgs;
+    serializationInputCorba->length(len+1);
+    for(int i=0;i<len+1;i++)
       (*serializationInputCorba)[i]=serializationInputC[i];
-    //serializationInputCorba[serializationInputC.length()]='\0';
-    DEBTRACE( "-----------------DistributedPythonNode starting remote python invocation-----------------" );
-    Engines::pickledArgs *resultCorba;
-    try
-      {
-        resultCorba=pn->execute(getFname().c_str(),*serializationInputCorba);
-      }
-    catch(...)
-      {
-        std::string msg="Exception on remote python invocation";
-        PyGILState_Release(gstate);
-        _errorDetails=msg;
-        throw Exception(msg);
-      }
-    DEBTRACE( "-----------------DistributedPythonNode end of remote python invocation-----------------" );
-    //
-    delete serializationInputCorba;
-    char *resultCorbaC=new char[resultCorba->length()+1];
-    resultCorbaC[resultCorba->length()]='\0';
-    for(int i=0;i<resultCorba->length();i++)
-      resultCorbaC[i]=(*resultCorba)[i];
-    delete resultCorba;
+    Py_DECREF(serializationInput);
+  }
+  //serializationInputCorba[serializationInputC.length()]='\0';
+  DEBTRACE( "-----------------DistributedPythonNode starting remote python invocation-----------------" );
+  Engines::pickledArgs *resultCorba;
+  try
+  {
+      resultCorba=_pynode->execute(getFname().c_str(),*serializationInputCorba);
+  }
+  catch(...)
+  {
+      std::string msg="Exception on remote python invocation";
+      _errorDetails=msg;
+      throw Exception(msg);
+  }
+  DEBTRACE( "-----------------DistributedPythonNode end of remote python invocation-----------------" );
+  //
+  delete serializationInputCorba;
+  char *resultCorbaC=new char[resultCorba->length()+1];
+  resultCorbaC[resultCorba->length()]='\0';
+  for(int i=0;i<resultCorba->length();i++)
+    resultCorbaC[i]=(*resultCorba)[i];
+  int lenResCorba=resultCorba->length();
+  delete resultCorba;
+  {
+    AutoGIL agil;
     args = PyTuple_New(1);
-    PyObject* resultPython=PyString_FromString(resultCorbaC);
+    //PyObject* resultPython=PyBytes_FromString(resultCorbaC);
+    PyObject* resultPython=PyBytes_FromStringAndSize(resultCorbaC,lenResCorba);
     delete [] resultCorbaC;
     PyTuple_SetItem(args,0,resultPython);
     PyObject *finalResult=PyObject_CallObject(_pyfuncUnser,args);
     DEBTRACE( "-----------------DistributedPythonNode::outputs-----------------" );
+    if(finalResult == NULL)
+      {
+        std::stringstream msg;
+        msg << "Conversion with pickle of output ports failed !";
+        msg << " : " << __FILE__ << ":" << __LINE__;
+        _errorDetails=msg.str();
+        throw YACS::ENGINE::ConversionException(msg.str());
+      }
     int nres=1;
     if(finalResult == Py_None)
       nres=0;
     else if(PyTuple_Check(finalResult))
       nres=PyTuple_Size(finalResult);
-    
+
     if(getNumberOfOutputPorts() != nres)
       {
         std::string msg="Number of output arguments : Mismatch between definition and execution";
         Py_DECREF(finalResult);
-        PyGILState_Release(gstate);
         _errorDetails=msg;
         throw Exception(msg);
       }
-    
-    pos=0;
-    list<OutputPort *>::iterator iter;
     try
-      {
-        for(iter = _setOfOutputPort.begin(); iter != _setOfOutputPort.end(); iter++)
+    {
+        int pos(0);
+        for(list<OutputPort *>::iterator iter = _setOfOutputPort.begin(); iter != _setOfOutputPort.end(); iter++, pos++)
           {
             OutputPyPort *p=(OutputPyPort *)*iter;
             DEBTRACE( "port name: " << p->getName() );
-            DEBTRACE( "port kind: " << p->edGetType()->kind() );
+            DEBTRACE( "port kind: " << p->typeName() );
             DEBTRACE( "port pos : " << pos );
             if(PyTuple_Check(finalResult))ob=PyTuple_GetItem(finalResult,pos) ;
             else ob=finalResult;
             DEBTRACE( "ob refcnt: " << ob->ob_refcnt );
             p->put(ob);
-            pos++;
           }
-      }
+    }
     catch(ConversionException& ex)
-      {
+    {
         Py_DECREF(finalResult);
-        PyGILState_Release(gstate);
         _errorDetails=ex.what();
         throw;
-      }
-    PyGILState_Release(gstate);
+    }
   }
   DEBTRACE( "++++++++++++++ End DistributedPythonNode::execute: " << getName() << " ++++++++++++++++++++" );
 }
@@ -237,9 +288,8 @@ ServerNode *DistributedPythonNode::createNode(const std::string& name) const
 void DistributedPythonNode::initMySelf()
 {
   _implementation = DistributedPythonNode::IMPL_NAME;
-  PyGILState_STATE gstate=PyGILState_Ensure();
+  AutoGIL agil;
   _context=PyDict_New();
-  PyGILState_Release(gstate);
 }
 
 void DistributedPythonNode::dealException(CORBA::Exception *exc, const char *method, const char *ref)