X-Git-Url: http://git.salome-platform.org/gitweb/?a=blobdiff_plain;f=src%2FPyInterp%2FPyInterp_Interp.cxx;h=48c6a8eb5b5a2e415f0d7a90e9031ce9f788a40d;hb=e6caa123c65e3c4a3017364ec5bb4225fd898465;hp=ba1a386fdb1c4a3de2dad8778017e613059715df;hpb=02904c3728214667f919cfe06072a91e1687b12f;p=modules%2Fgui.git diff --git a/src/PyInterp/PyInterp_Interp.cxx b/src/PyInterp/PyInterp_Interp.cxx index ba1a386fd..48c6a8eb5 100644 --- a/src/PyInterp/PyInterp_Interp.cxx +++ b/src/PyInterp/PyInterp_Interp.cxx @@ -1,4 +1,4 @@ -// Copyright (C) 2007-2014 CEA/DEN, EDF R&D, OPEN CASCADE +// Copyright (C) 2007-2015 CEA/DEN, EDF R&D, OPEN CASCADE // // Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN, // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS @@ -21,10 +21,11 @@ // // File : PyInterp_Interp.cxx -// Author : Christian CAREMOLI, Paul RASCLE, EDF +// Author : Christian CAREMOLI, Paul RASCLE, Adrien BRUNETON // Module : SALOME // #include "PyInterp_Interp.h" // !!! WARNING !!! THIS INCLUDE MUST BE THE VERY FIRST !!! +#include "PyInterp_Utils.h" #include #include @@ -39,35 +40,6 @@ #define TOP_HISTORY_PY "--- top of history ---" #define BEGIN_HISTORY_PY "--- begin of history ---" -/*! - \class PyLockWrapper - \brief Python GIL wrapper. -*/ - -/*! - \brief Constructor. Automatically acquires GIL. -*/ -PyLockWrapper::PyLockWrapper() -{ - _gil_state = PyGILState_Ensure(); -} - -/*! - \brief Destructor. Automatically releases GIL. -*/ -PyLockWrapper::~PyLockWrapper() -{ -// if (myThreadState->interp == PyInterp_Interp::_interp) -// PyGILState_Release(_savestate); -// else -// PyEval_ReleaseThread(myThreadState); - - /* The destructor can never be called concurrently by two threads since it is called - * when the GIL is held - the below test should never run concurrently in two threads. - */ - PyGILState_Release(_gil_state); -} - /* The following functions are used to hook the Python interpreter output. @@ -187,9 +159,6 @@ static PyStdOut* newPyStdOut( bool iscerr ) int PyInterp_Interp::_argc = 1; char* PyInterp_Interp::_argv[] = {(char*)""}; -//PyObject* PyInterp_Interp::builtinmodule = NULL; -//PyThreadState* PyInterp_Interp::_gtstate = NULL; -//PyInterpreterState* PyInterp_Interp::_interp = NULL; /*! \brief Basic constructor. @@ -198,7 +167,7 @@ char* PyInterp_Interp::_argv[] = {(char*)""}; must call virtual method initalize(). */ PyInterp_Interp::PyInterp_Interp(): - _vout(0), _verr(0), _context(0) + _vout(0), _verr(0), _local_context(0), _global_context(0) { } @@ -209,6 +178,7 @@ PyInterp_Interp::PyInterp_Interp(): */ PyInterp_Interp::~PyInterp_Interp() { + destroy(); } /*! @@ -217,7 +187,6 @@ PyInterp_Interp::~PyInterp_Interp() This method shoud be called after construction of the interpreter. The method initialize() calls virtuals methods - initPython() to initialize global Python interpreter - - initState() to initialize embedded interpreter state - initContext() to initialize interpreter internal context - initRun() to prepare interpreter for running commands which should be implemented in the successor classes, according to the @@ -242,7 +211,6 @@ void PyInterp_Interp::initialize() PyObjWrapper m(PyImport_ImportModule("codeop")); if(!m) { PyErr_Print(); - PyEval_ReleaseLock(); return; } @@ -308,27 +276,57 @@ bool PyInterp_Interp::initRun() return true; } +/*! + * Initialize context dictionaries. GIL is held already. + * The code executed in an embedded interpreter is expected to be run at the module + * level, in which case local and global context have to be the same dictionary. + * See: http://stackoverflow.com/questions/12265756/c-python-running-python-code-within-a-context + * for an explanation. + */ +bool PyInterp_Interp::initContext() +{ + PyObject *m = PyImport_AddModule("__main__"); // interpreter main module (module context) + if(!m){ + PyErr_Print(); + return false; + } + _global_context = PyModule_GetDict(m); // get interpreter global variable context + Py_INCREF(_global_context); + _local_context = _global_context; + + int ret = PyRun_SimpleString("import salome_iapp;salome_iapp.IN_SALOME_GUI=True"); + + return ret == 0; +} + +/*! + * Destroy context dictionaries. GIL is held already. + */ void PyInterp_Interp::closeContext() { + Py_XDECREF(_global_context); + // both _global and _local point to the same Python object: + // Py_XDECREF(_local_context); } /*! \brief Compile Python command and evaluate it in the - python dictionary context if possible. This is not thread-safe. + python dictionary contexts if possible. This is not thread-safe. This is the caller's responsability to make this thread-safe. \internal \param command Python command string - \param context Python context (dictionary) \return -1 on fatal error, 1 if command is incomplete and 0 if command is executed successfully */ -static int run_command(const char *command, PyObject *context) +static int run_command(const char *command, PyObject * global_ctxt, PyObject * local_ctxt) { PyObject *m = PyImport_AddModule("codeop"); if(!m) { // Fatal error. No way to go on. PyErr_Print(); return -1; } + +// PyObjWrapper v(Py_CompileString(command, "", Py_file_input)); PyObjWrapper v(PyObject_CallMethod(m,(char*)"compile_command",(char*)"s",command)); if(!v) { // Error encountered. It should be SyntaxError, @@ -344,7 +342,7 @@ static int run_command(const char *command, PyObject *context) return 1; } else { - PyObjWrapper r(PyEval_EvalCode((PyCodeObject *)(void *)v,context,context)); + PyObjWrapper r(PyEval_EvalCode((PyCodeObject *)(void *)v,global_ctxt, local_ctxt)); if(!r) { // Execution error. We return -1 PyErr_Print(); @@ -376,7 +374,7 @@ void replaceAll(std::string& str, const std::string& from, const std::string& to \return -1 on fatal error, 1 if command is incomplete and 0 if command is executed successfully */ -static int compile_command(const char *command, PyObject *context) +static int compile_command(const char *command, PyObject * global_ctxt, PyObject * local_ctxt) { // First guess if command is execution of a script with args, or a simple Python command std::string singleCommand = command; @@ -392,7 +390,7 @@ static int compile_command(const char *command, PyObject *context) if (commandArgs.empty()) { // process command: expression // process command: execfile(r"/absolute/path/to/script.py") (no args) - return run_command(singleCommand.c_str(), context); + return run_command(singleCommand.c_str(), global_ctxt, local_ctxt); } else { // process command: execfile(r"/absolute/path/to/script.py [args:arg1,...,argn]") @@ -404,7 +402,7 @@ static int compile_command(const char *command, PyObject *context) replaceAll(commandArgs, ",", "\",\""); commandArgs = "\""+commandArgs+"\""; std::string completeCommand = preCommandBegin+"\""+script+"\","+commandArgs+preCommandEnd+singleCommand+";sys.argv=save_argv"; - return run_command(completeCommand.c_str(), context); + return run_command(completeCommand.c_str(), global_ctxt, local_ctxt); } } @@ -417,7 +415,9 @@ static int compile_command(const char *command, PyObject *context) int PyInterp_Interp::run(const char *command) { beforeRun(); - return simpleRun(command); + int ret = simpleRun(command); + afterRun(); + return ret; } /** @@ -429,6 +429,15 @@ int PyInterp_Interp::beforeRun() return 0; } +/** + * Called after a command is run (when calling run() method). Not thread-safe. Caller's responsability + * to acquire GIL if needed. + */ +int PyInterp_Interp::afterRun() +{ + return 0; +} + /*! \brief Run Python command (used internally). Not thread-safe. GIL acquisition is caller's responsability. \param command Python command @@ -453,7 +462,7 @@ int PyInterp_Interp::simpleRun(const char *command, const bool addToHistory) PySys_SetObject((char*)"stderr",_verr); PySys_SetObject((char*)"stdout",_vout); - int ier = compile_command(command,_context); + int ier = compile_command(command, _global_context, _local_context); // Outputs are redirected to what they were before PySys_SetObject((char*)"stdout",oldOut);