Salome HOME
Remove useless dependency to py2cpp.
[tools/adao_interface.git] / AdaoExchangeLayer.cxx
index 9a101a4965c916b537297ea3060e53ddefc804dd..4bc42dd0c24f2813da03752d4726d7efdc9b3864 100644 (file)
 #include "PyObjectRAII.hxx"
 #include "Python.h"
 
-#include "py2cpp/py2cpp.hxx"
-
 #include <semaphore.h>
-
 #include <iostream>
 #include <sstream>
 #include <clocale>
@@ -168,7 +165,8 @@ class AdaoExchangeLayer::Internal
 {
 public:
   Internal():_context(PyObjectRAII::FromNew(PyDict_New()))
-  { 
+  {
+    AutoGIL agil;
     PyObject *mainmod(PyImport_AddModule("__main__"));
     PyObject *globals(PyModule_GetDict(mainmod));
     PyObject *bltins(PyEval_GetBuiltins());
@@ -212,6 +210,7 @@ AdaoExchangeLayer::AdaoExchangeLayer()
 
 AdaoExchangeLayer::~AdaoExchangeLayer()
 {
+  AutoGIL agil;
   delete _internal;
 }
 
@@ -227,6 +226,38 @@ PyObject *AdaoExchangeLayer::getPythonContext() const
   return _internal->_context;
 }
 
+std::string AdaoExchangeLayer::printContext() const
+{
+  AutoGIL agil;
+  PyObject *obj(this->getPythonContext());
+  if(!PyDict_Check(obj))
+    throw AdaoExchangeLayerException("printContext : not a dict !");
+  PyObject *key(nullptr), *value(nullptr);
+  Py_ssize_t pos(0);
+  std::ostringstream oss;
+  while( PyDict_Next(obj, &pos, &key, &value) )
+    {
+      if(!PyUnicode_Check(key))
+        throw AdaoExchangeLayerException("printContext : not a string as key !");
+      oss << PyUnicode_AsUTF8(key) << " = ";
+      PyObjectRAII reprOfValue(PyObjectRAII::FromNew(PyObject_Repr(value)));
+      oss << PyUnicode_AsUTF8(reprOfValue);
+      oss << std::endl;
+    }
+  return oss.str();
+}
+
+/*!
+ * AdaoExchangeLayer is based on multithreaded paradigm.
+ * Master thread (thread calling this method) and slave thread (thread calling ADAO algo)
+ * are calling both python interpretor. Consequence all python calls have to be surrounded with AGIL.
+ *
+ * User consequence : To avoid deadlocks this method release GIL. The downstream python calls must be with AGIL.
+ * 
+ * This method initialize python interpretor if not already the case.
+ * At the end of this method the lock is released to be ready to perform RAII on GIL
+ * easily. 
+ */
 void AdaoExchangeLayer::initPythonIfNeeded()
 {
   if (!Py_IsInitialized())
@@ -239,9 +270,17 @@ void AdaoExchangeLayer::initPythonIfNeeded()
       PySys_SetArgv(1,TABW);
       FreeWChar(1,TABW);
       PyEval_InitThreads();
+      delete _internal;
+      _internal = new Internal;
+      _internal->_tstate=PyEval_SaveThread(); // release the lock acquired in AdaoExchangeLayer::initPythonIfNeeded by PyEval_InitThreads()
+    }
+  else
+    {
+      delete _internal;
+      _internal = new Internal;
+      if( PyGILState_Check() )// is the GIL already acquired (typically by a PyEval_InitThreads) ?
+        _internal->_tstate=PyEval_SaveThread(); // release the lock acquired upstream
     }
-  delete _internal;
-  _internal = new Internal;
 }
 
 class Visitor1 : public AdaoModel::PythonLeafVisitor
@@ -278,8 +317,9 @@ private:
   PyObject *_context = nullptr;
 };
 
-void AdaoExchangeLayer::loadTemplate(AdaoModel::MainModel *model)
+void AdaoExchangeLayer::setFunctionCallbackInModel(AdaoModel::MainModel *model)
 {
+  AutoGIL agil;
   const char DECORATOR_FUNC[]="def DecoratorAdao(cppFunc):\n"
       "    def evaluator( xserie ):\n"
       "        import numpy as np\n"
@@ -304,7 +344,11 @@ void AdaoExchangeLayer::loadTemplate(AdaoModel::MainModel *model)
   //
   Visitor1 visitor(this->_internal->_decorator_func,this->_internal->_context);
   model->visitPythonLeaves(&visitor);
-  //
+}
+
+void AdaoExchangeLayer::loadTemplate(AdaoModel::MainModel *model)
+{
+  AutoGIL agil;
   {
     std::string sciptPyOfModelMaker(model->pyStr());
     PyObjectRAII res(PyObjectRAII::FromNew(PyRun_String(sciptPyOfModelMaker.c_str(),Py_file_input,this->_internal->_context,this->_internal->_context)));
@@ -321,10 +365,12 @@ void AdaoExchangeLayer::loadTemplate(AdaoModel::MainModel *model)
 
 void ExecuteAsync(PyObject *pyExecuteFunction, DataExchangedBetweenThreads *data)
 {
-  AutoGIL gil; // launched in a separed thread -> protect python calls
-  PyObjectRAII args(PyObjectRAII::FromNew(PyTuple_New(0)));
-  PyObjectRAII nullRes(PyObjectRAII::FromNew(PyObject_CallObject(pyExecuteFunction,args)));// go to adaocallback_call
-  PyErr_Print();
+  {
+    AutoGIL gil; // launched in a separed thread -> protect python calls
+    PyObjectRAII args(PyObjectRAII::FromNew(PyTuple_New(0)));
+    PyObjectRAII nullRes(PyObjectRAII::FromNew(PyObject_CallObject(pyExecuteFunction,args)));// go to adaocallback_call
+    PyErr_Print();
+  }
   data->_finished = true;
   data->_data = nullptr;
   sem_post(&data->_sem);
@@ -332,7 +378,6 @@ void ExecuteAsync(PyObject *pyExecuteFunction, DataExchangedBetweenThreads *data
 
 void AdaoExchangeLayer::execute()
 {
-  _internal->_tstate=PyEval_SaveThread(); // release the lock acquired in AdaoExchangeLayer::initPythonIfNeeded by PyEval_InitThreads()
   _internal->_fut = std::async(std::launch::async,ExecuteAsync,_internal->_execute_func,&_internal->_data_btw_threads);
 }
 
@@ -361,7 +406,8 @@ void AdaoExchangeLayer::setResult(PyObject *outputAssociated)
 PyObject *AdaoExchangeLayer::getResult()
 {
   _internal->_fut.wait();
-  PyEval_RestoreThread(_internal->_tstate);
+  if(_internal->_tstate)
+    PyEval_RestoreThread(_internal->_tstate);
   AutoGIL gil;
   // now retrieve case.get("Analysis")[-1]
   PyObjectRAII get_func_of_adao_case(PyObjectRAII::FromNew(PyObject_GetAttrString(_internal->_adao_case,"get")));