From 80f32aba5aa2bf61f6278621910d3e81a443d2e8 Mon Sep 17 00:00:00 2001 From: Adrien Bruneton Date: Thu, 13 Feb 2014 10:53:44 +0100 Subject: [PATCH] Revamped Python interpreter logic in GUI. Now only uses execution contexts, no more sub interpreter. + reviewed PyInterp_Interp class and Python initialization + removed GetLockWrapper() method from PyInterp_Interp class. + interpreter member is no more requested in PyLock_Request (can be set to NULL) + reviewed PyLockWrapper class design to forbid copy ctor and assignment + more sophisticated stdout/stderr redirection for Python command: restore what was previously used after Python command execution. + get rid of "shared_modules" logic - no more necessary with a single interpreter --- src/LightApp/LightApp_PyInterp.cxx | 60 +--- src/LightApp/LightApp_PyInterp.h | 1 - src/PyConsole/PyConsole_EnhInterp.cxx | 4 +- src/PyConsole/PyConsole_Interp.cxx | 72 +---- src/PyConsole/PyConsole_Interp.h | 1 - src/PyInterp/PyInterp_Dispatcher.cxx | 6 +- src/PyInterp/PyInterp_Interp.cxx | 170 ++++------ src/PyInterp/PyInterp_Interp.h | 56 +++- src/PyInterp/PyInterp_Request.h | 2 +- .../SALOME_PYQT_GUI/SALOME_PYQT_Module.cxx | 4 +- .../SALOME_PYQT_ModuleLight.cxx | 25 +- .../SALOME_PYQT_ModuleLight.h | 6 +- .../SALOME_PYQT_PyInterp.cxx | 47 +-- .../SALOME_PYQT_PyInterp.h | 1 - .../SALOME_PYQT_PyModule.cxx | 302 +++++++++--------- .../SALOME_PYQT_PyModule.h | 4 +- src/SUITApp/SUITApp.cxx | 11 +- src/SUITApp/SUITApp_init_python.cxx | 9 +- src/SUITApp/SUITApp_init_python.hxx | 4 - src/SalomeApp/SalomeApp_Application.cxx | 13 +- src/SalomeApp/SalomeApp_DoubleSpinBox.cxx | 2 +- src/SalomeApp/SalomeApp_IntSpinBox.cxx | 2 +- src/SalomeApp/SalomeApp_NoteBook.cxx | 4 +- src/SalomeApp/SalomeApp_PyInterp.cxx | 64 +--- src/SalomeApp/SalomeApp_PyInterp.h | 1 - src/Session/SALOME_Session_Server.cxx | 94 +++--- 26 files changed, 343 insertions(+), 622 deletions(-) diff --git a/src/LightApp/LightApp_PyInterp.cxx b/src/LightApp/LightApp_PyInterp.cxx index 5bc90b951..9f88b966f 100644 --- a/src/LightApp/LightApp_PyInterp.cxx +++ b/src/LightApp/LightApp_PyInterp.cxx @@ -22,15 +22,8 @@ // #include "LightApp_PyInterp.h" -#include -#include - -#include - /*! - * constructor : multi Python interpreter, one per SALOME study. - * calls initialize method defined in base class, which calls virtual methods - * initstate & initcontext redefined here. + * constructor : Python interpreter. */ LightApp_PyInterp::LightApp_PyInterp(): PyConsole_EnhInterp() { @@ -44,59 +37,16 @@ LightApp_PyInterp::~LightApp_PyInterp() } /*!\class LightApp_PyInterp - * EDF-CCAR - * When SALOME uses multi Python interpreter feature, - * Every study has its own interpreter and thread state (_tstate = Py_NewInterpreter()) - * This is fine because every study has its own modules (sys.modules) stdout and stderr - * BUT some Python modules must be imported only once. In multi interpreter context Python - * modules (*.py) are imported several times. - * The pyqt module must be imported only once because it registers classes in a C module. - * It's quite the same with omniorb modules (internals and generated with omniidl) - * This problem is handled with "shared modules" defined in salome_shared_modules.py - * These "shared modules" are imported only once and only copied in all the other interpreters - * BUT it's not the only problem. Every interpreter has its own __builtin__ module. That's fine - * but if we have copied some modules and imported others problems may arise with operations that - * are not allowed in restricted execution environment. So we must impose that all interpreters - * have identical __builtin__ module. - * That's all, for the moment ... + * [ABN] : there is now a single Python interpreter for the whole SALOME run. + * Different execution environment are provided to emulate independent + * "virtual" Python interpreters. */ -bool LightApp_PyInterp::initContext() -{ - /*! - * The GIL is assumed to be held - * It is the caller responsability caller to acquire the GIL - * It will still be held on initContext output - */ - if ( !PyConsole_Interp::initContext() ) - return false; - - //Import special module to change the import mechanism - PyObjWrapper m1( PyImport_ImportModule( "import_hook" ) ); - if ( !m1 ) - { - PyErr_Print(); - return false; - } - - // Call init_shared_modules to initialize the shared import mechanism for modules - //that must not be imported twice - PyObjWrapper m2( PyObject_CallMethod( m1, (char*)"init_shared_modules", (char*)"O", SUIT_PYTHON::salome_shared_modules_module ) ); - if ( !m2 ) - { - PyErr_Print(); - return false; - } - return true; -} - /*! Do nothing - The initialization has been done in main + The initialization has been done in main - see SUITApp/SUITApp.cxx - main() */ void LightApp_PyInterp::initPython() { - _gtstate=SUIT_PYTHON::_gtstate; // initialisation in main - _interp=SUIT_PYTHON::_interp; } diff --git a/src/LightApp/LightApp_PyInterp.h b/src/LightApp/LightApp_PyInterp.h index d13d6bd85..9d605d398 100644 --- a/src/LightApp/LightApp_PyInterp.h +++ b/src/LightApp/LightApp_PyInterp.h @@ -33,7 +33,6 @@ public: protected: virtual void initPython(); - virtual bool initContext(); }; #endif //_LIGHTAPP_PYINTERP_H_ diff --git a/src/PyConsole/PyConsole_EnhInterp.cxx b/src/PyConsole/PyConsole_EnhInterp.cxx index c64808622..0465d08c1 100644 --- a/src/PyConsole/PyConsole_EnhInterp.cxx +++ b/src/PyConsole/PyConsole_EnhInterp.cxx @@ -73,7 +73,7 @@ int PyConsole_EnhInterp::runDirCommand(const QString & dirArgument, const QStrin if (dirArgument.trimmed() != "") cmd = dirArgument + "."; cmd += _last_matches[0] + ".__doc__"; - PyObject * str = PyRun_String(cmd.toStdString().c_str(), Py_eval_input, _g, _g); + PyObject * str = PyRun_String(cmd.toStdString().c_str(), Py_eval_input, _context, _context); if (!str || str == Py_None || !PyString_Check(str)) { if (!str) @@ -104,7 +104,7 @@ int PyConsole_EnhInterp::runDirAndExtract(const QString& dirArgument, { QRegExp re("^[A-Z].+_[A-Z]+[a-z]+.+$"); // discard SWIG static method, e.g. MEDCouplingUMesh_Blabla QString command("dir(" + dirArgument + ")"); - PyObject * plst = PyRun_String(command.toStdString().c_str(), Py_eval_input, _g, _g); + PyObject * plst = PyRun_String(command.toStdString().c_str(), Py_eval_input, _context, _context); if(!plst || plst == Py_None) { if(!plst) PyErr_Clear(); diff --git a/src/PyConsole/PyConsole_Interp.cxx b/src/PyConsole/PyConsole_Interp.cxx index 6682d4a02..9d3d996ca 100644 --- a/src/PyConsole/PyConsole_Interp.cxx +++ b/src/PyConsole/PyConsole_Interp.cxx @@ -31,38 +31,16 @@ \class PyConsole_Interp \brief Python interpreter to be embedded to the SALOME study's GUI. - Python interpreter is created one per SALOME study. + There is only one Python interpreter for the whole SALOME environment. - Call initialize method defined in the base class PyInterp_Interp, - to intialize interpreter after instance creation. + Call the initialize() method defined in the base class PyInterp_Interp, + to initialize the interpreter after instance creation. The method initialize() calls virtuals methods - initPython() to initialize global Python interpreter - - initState() to initialize embedded interpreter state + //- initState() to initialize embedded interpreter state (OBSOLETE) - initContext() to initialize interpreter internal context - initRun() to prepare interpreter for running commands - - /EDF-CCAR/ - When SALOME uses multi Python interpreter feature, - every study has its own interpreter and thread state (_tstate = Py_NewInterpreter()). - This is fine because every study has its own modules (sys.modules) stdout and stderr. - - But some Python modules must be imported only once. In multi interpreter - context Python modules (*.py) are imported several times. - For example, the PyQt module must be imported only once because - it registers classes in a C module. - - It's quite the same with omniorb modules (internals and generated with omniidl). - - This problem is handled with "shared modules" defined in salome_shared_modules.py. - These "shared modules" are imported only once and only copied in all - the other interpreters. - - But it's not the only problem. Every interpreter has its own - __builtin__ module. That's fine but if we have copied some modules - and imported others problems may arise with operations that are not allowed - in restricted execution environment. So we must impose that all interpreters - have identical __builtin__ module. */ /*! @@ -83,42 +61,6 @@ PyConsole_Interp::~PyConsole_Interp() { } -/*! - \brief Initialize internal Python interpreter state. - - When calling initState the GIL is not held - It must not be held on exit - - \return \c true on success -*/ -bool PyConsole_Interp::initState() -{ - PyEval_AcquireLock(); - _tstate = Py_NewInterpreter(); // create an interpreter and save current state - PySys_SetArgv(PyInterp_Interp::_argc,PyInterp_Interp::_argv); // initialize sys.argv - - if(!builtinmodule) // PAL18041: deepcopy function don't work in Salome - { - //builtinmodule is static member of PyInterp class - //If it is not NULL (initialized to the builtin module of the main interpreter - //all the sub interpreters will have the same builtin - //_interp is a static member and is the main interpreter - //The first time we initialized it to the builtin of main interpreter - builtinmodule=PyDict_GetItemString(_interp->modules, "__builtin__"); - } - - //If builtinmodule has been initialized all the sub interpreters - // will have the same __builtin__ module - if(builtinmodule){ - PyObject *m = PyImport_GetModuleDict(); - PyDict_SetItemString(m, "__builtin__", builtinmodule); - _tstate->interp->builtins = PyModule_GetDict(builtinmodule); - Py_INCREF(_tstate->interp->builtins); - } - PyEval_ReleaseThread(_tstate); - return true; -} - /*! \brief Initialize python interpeter context. @@ -135,10 +77,6 @@ bool PyConsole_Interp::initContext() PyErr_Print(); return false; } - _g = PyModule_GetDict(m); // get interpreter dictionnary context - - if(builtinmodule){ - PyDict_SetItemString(_g, "__builtins__", builtinmodule); // assign singleton __builtin__ module - } + _context = PyModule_GetDict(m); // get interpreter dictionnary context return true; } diff --git a/src/PyConsole/PyConsole_Interp.h b/src/PyConsole/PyConsole_Interp.h index 4bd15ba9e..2e3aee950 100644 --- a/src/PyConsole/PyConsole_Interp.h +++ b/src/PyConsole/PyConsole_Interp.h @@ -39,7 +39,6 @@ public: ~PyConsole_Interp(); protected: - virtual bool initState(); virtual bool initContext(); }; diff --git a/src/PyInterp/PyInterp_Dispatcher.cxx b/src/PyInterp/PyInterp_Dispatcher.cxx index 95938f67c..73d14db86 100755 --- a/src/PyInterp/PyInterp_Dispatcher.cxx +++ b/src/PyInterp/PyInterp_Dispatcher.cxx @@ -96,11 +96,11 @@ void PyInterp_Request::setListener( QObject* o ) void PyInterp_LockRequest::safeExecute() { - if ( getInterp() ){ - PyLockWrapper aLock = getInterp()->GetLockWrapper(); + //if ( getInterp() ){ // No need to have an interpreter now! we can simply run in a empty context + PyLockWrapper aLock; // Acquire GIL //ProcessVoidEvent( new PyInterp_ExecuteEvent( this ) ); execute(); - } + //} } PyInterp_Event::~PyInterp_Event() diff --git a/src/PyInterp/PyInterp_Interp.cxx b/src/PyInterp/PyInterp_Interp.cxx index c2dcd254a..0ee1e0173 100644 --- a/src/PyInterp/PyInterp_Interp.cxx +++ b/src/PyInterp/PyInterp_Interp.cxx @@ -39,9 +39,6 @@ #define TOP_HISTORY_PY "--- top of history ---" #define BEGIN_HISTORY_PY "--- begin of history ---" -// a map to store python thread states that have been created for a given system thread (key=thread id,value=thread state) -std::map currentThreadMap; - /*! \class PyLockWrapper \brief Python GIL wrapper. @@ -49,16 +46,10 @@ std::map currentThreadMap; /*! \brief Constructor. Automatically acquires GIL. - \param theThreadState python thread state */ -PyLockWrapper::PyLockWrapper(PyThreadState* theThreadState): - myThreadState(theThreadState), - mySaveThreadState(0) +PyLockWrapper::PyLockWrapper() { - if (myThreadState->interp == PyInterp_Interp::_interp) - _savestate = PyGILState_Ensure(); - else - PyEval_AcquireThread(myThreadState); + _gil_state = PyGILState_Ensure(); } /*! @@ -66,51 +57,15 @@ PyLockWrapper::PyLockWrapper(PyThreadState* theThreadState): */ PyLockWrapper::~PyLockWrapper() { - if (myThreadState->interp == PyInterp_Interp::_interp) - PyGILState_Release(_savestate); - else - PyEval_ReleaseThread(myThreadState); -} - -/*! - \brief Get Python GIL wrapper. - \return GIL lock wrapper (GIL is automatically acquired here) -*/ -PyLockWrapper PyInterp_Interp::GetLockWrapper() -{ - if (_tstate->interp == PyInterp_Interp::_interp) - return _tstate; - - // If we are here, we have a secondary python interpreter. Try to get a thread state synchronized with the system thread - long currentThreadid=PyThread_get_thread_ident(); // the system thread id - PyThreadState* theThreadState; - if(currentThreadMap.count(currentThreadid) != 0) - { - //a thread state exists for this thread id - PyThreadState* oldThreadState=currentThreadMap[currentThreadid]; - if(_tstate->interp ==oldThreadState->interp) - { - //The old thread state has the same python interpreter as this one : reuse the threadstate - theThreadState=oldThreadState; - } - else - { - //The old thread state has not the same python interpreter as this one : delete the old threadstate and create a new one - PyEval_AcquireLock(); - PyThreadState_Clear(oldThreadState); - PyThreadState_Delete(oldThreadState); - PyEval_ReleaseLock(); - theThreadState=PyThreadState_New(_tstate->interp); - currentThreadMap[currentThreadid]=theThreadState; - } - } - else - { - // no old thread state for this thread id : create a new one - theThreadState=PyThreadState_New(_tstate->interp); - currentThreadMap[currentThreadid]=theThreadState; - } - return theThreadState; +// 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); } /* @@ -232,9 +187,9 @@ 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; +//PyObject* PyInterp_Interp::builtinmodule = NULL; +//PyThreadState* PyInterp_Interp::_gtstate = NULL; +//PyInterpreterState* PyInterp_Interp::_interp = NULL; /*! \brief Basic constructor. @@ -243,10 +198,12 @@ PyInterpreterState* PyInterp_Interp::_interp = NULL; must call virtual method initalize(). */ PyInterp_Interp::PyInterp_Interp(): - _tstate(0), _vout(0), _verr(0), _g(0) + _vout(0), _verr(0), _context(0) { } + + /*! \brief Destructor. */ @@ -271,20 +228,21 @@ void PyInterp_Interp::initialize() _history.clear(); // start a new list of user's commands _ith = _history.begin(); - initPython(); - // Here the global lock is released + initPython(); // This also inits the multi-threading for Python (but w/o acquiring GIL) - initState(); + //initState(); // [ABN] OBSOLETE - PyEval_AcquireThread(_tstate); + // ---- The rest of the initialisation process is done hodling the GIL + PyLockWrapper lck; initContext(); - // used to interpret & compile commands + // used to interpret & compile commands - this is really imported here + // and only added again (with PyImport_AddModule) later on PyObjWrapper m(PyImport_ImportModule("codeop")); if(!m) { PyErr_Print(); - PyEval_ReleaseThread(_tstate); + PyEval_ReleaseLock(); return; } @@ -294,17 +252,16 @@ void PyInterp_Interp::initialize() // All the initRun outputs are redirected to the standard output (console) initRun(); - PyEval_ReleaseThread(_tstate); } /*! \brief Initialize Python interpreter. - In case if Python is not initialized, it sets program name, initializes the interpreter, sets program arguments, - initializes threads. - Otherwise, it just obtains the global interpreter and thread states. This is important for light SALOME configuration, + In case if Python is not initialized, it sets program name, initializes the single true Python + interpreter, sets program arguments, and initializes threads. + Otherwise, does nothing. This is important for light SALOME configuration, as in full SALOME this is done at SalomeApp level. - \sa SalomeApp_PyInterp class + \sa SalomeApp_PyInterp class and main() in SALOME_Session_Server */ void PyInterp_Interp::initPython() { @@ -313,30 +270,22 @@ void PyInterp_Interp::initPython() Py_SetProgramName(_argv[0]); Py_Initialize(); // Initialize the interpreter PySys_SetArgv(_argc, _argv); - PyEval_InitThreads(); // Create (and acquire) the interpreter lock - } - if ( _interp == NULL ) - _interp = PyThreadState_Get()->interp; - if (PyType_Ready(&PyStdOut_Type) < 0) { - PyErr_Print(); + PyEval_InitThreads(); // Create (and acquire) the Python global interpreter lock (GIL) + PyEval_ReleaseLock(); } - if ( _gtstate == NULL ) - _gtstate = PyEval_SaveThread(); // Release global thread state } /*! \brief Get embedded Python interpreter banner. \return banner string */ -std::string PyInterp_Interp::getbanner() +std::string PyInterp_Interp::getbanner() const { - // Should we take the lock ? - // PyEval_RestoreThread(_tstate); + PyLockWrapper lck; std::string aBanner("Python "); aBanner = aBanner + Py_GetVersion() + " on " + Py_GetPlatform() ; aBanner = aBanner + "\ntype help to get general information on environment\n"; - //PyEval_SaveThread(); return aBanner; } @@ -350,24 +299,13 @@ std::string PyInterp_Interp::getbanner() */ bool PyInterp_Interp::initRun() { - // - // probably all below code isn't required - // - /* - PySys_SetObject("stderr",_verr); - PySys_SetObject("stdout",_vout); - - //PyObject *m = PyImport_GetModuleDict(); - - PySys_SetObject("stdout",PySys_GetObject("__stdout__")); - PySys_SetObject("stderr",PySys_GetObject("__stderr__")); - */ return true; } /*! \brief Compile Python command and evaluate it in the - python dictionary context if possible. + python dictionary context 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) @@ -396,12 +334,7 @@ static int run_command(const char *command, PyObject *context) return 1; } else { - // Complete and correct text. We evaluate it. - //#if PY_VERSION_HEX < 0x02040000 // python version earlier than 2.4.0 - // PyObjWrapper r(PyEval_EvalCode(v,context,context)); - //#else PyObjWrapper r(PyEval_EvalCode((PyCodeObject *)(void *)v,context,context)); - //#endif if(!r) { // Execution error. We return -1 PyErr_Print(); @@ -433,7 +366,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 *context) { // First guess if command is execution of a script with args, or a simple Python command std::string singleCommand = command; @@ -466,7 +399,8 @@ static int compile_command(const char *command,PyObject *context) } /*! - \brief Run Python command. + \brief Run Python command - the command has to fit on a single line (no \n!). + Use ';' if you need multiple statements evaluated at once. \param command Python command \return command status */ @@ -476,8 +410,17 @@ int PyInterp_Interp::run(const char *command) return simpleRun(command); } +/** + * Called before a command is run (when calling run() method). Not thread-safe. Caller's responsability + * to acquire GIL if needed. + */ +int PyInterp_Interp::beforeRun() +{ + return 0; +} + /*! - \brief Run Python command (used internally). + \brief Run Python command (used internally). Not thread-safe. GIL acquisition is caller's responsability. \param command Python command \param addToHistory if \c true (default), the command is added to the commands history \return command status @@ -489,19 +432,22 @@ int PyInterp_Interp::simpleRun(const char *command, const bool addToHistory) _ith = _history.end(); } - // We come from C++ to enter Python world - // We need to acquire the Python global lock - //PyLockWrapper aLock(_tstate); // san - lock is centralized now + // Current stdout and stderr are saved + PyObject * oldOut = PySys_GetObject((char*)"stdout"); + PyObject * oldErr = PySys_GetObject((char*)"stderr"); + // Keep them alive (PySys_GetObject returned a *borrowed* ref!) + Py_INCREF(oldOut); + Py_INCREF(oldErr); - // Reset redirected outputs before treatment + // Redirect outputs to SALOME Python console before treatment PySys_SetObject((char*)"stderr",_verr); PySys_SetObject((char*)"stdout",_vout); - int ier = compile_command(command,_g); + int ier = compile_command(command,_context); - // Outputs are redirected on standards outputs (console) - PySys_SetObject((char*)"stdout",PySys_GetObject((char*)"__stdout__")); - PySys_SetObject((char*)"stderr",PySys_GetObject((char*)"__stderr__")); + // Outputs are redirected to what they were before + PySys_SetObject((char*)"stdout",oldOut); + PySys_SetObject((char*)"stderr",oldErr); return ier; } diff --git a/src/PyInterp/PyInterp_Interp.h b/src/PyInterp/PyInterp_Interp.h index 77ac9486b..55c2c7005 100644 --- a/src/PyInterp/PyInterp_Interp.h +++ b/src/PyInterp/PyInterp_Interp.h @@ -32,26 +32,42 @@ #include #include +/** + * Utility class wrappin the Python GIL acquisition. This makes use of the high level + * API (PyGILState_Ensure and PyGILState_Release), and is hence compatible with only + * one running Python interpreter (no call to Py_NewInterpreter()). + * When the class is instanciated the lock is acquired. It is released at destruction time. + * Copy construction (and hence assignation) is forbidden. + */ class PYINTERP_EXPORT PyLockWrapper { - PyThreadState* myThreadState; - PyThreadState* mySaveThreadState; - PyGILState_STATE _savestate; + PyGILState_STATE _gil_state; public: - PyLockWrapper(PyThreadState* theThreadState); + PyLockWrapper(); ~PyLockWrapper(); + +private: + // "Rule of 3" - Forbid usage of copy operator and copy-constructor + PyLockWrapper(const PyLockWrapper & another); + const PyLockWrapper & operator=(const PyLockWrapper & another); }; typedef void PyOutChanged(void* data,char * c); +/** + * Main class representing a *virtual* Python interpreter. There is really only one true + * Python interpreter in the whole application (no call to Py_NewInterpreter), + * but the use of different execution contexts allow + * to split the execution lines, and hence to emulate (relatively) independent interpreters. + * This has some consequences: modules imported in one context are not re-imported in another context + * (only there namespace is made available when importing in another context). + * See also class PyConsole_Interp. + */ class PYINTERP_EXPORT PyInterp_Interp { public: static int _argc; static char* _argv[]; - static PyObject *builtinmodule; - static PyThreadState *_gtstate; - static PyInterpreterState *_interp; PyInterp_Interp(); virtual ~PyInterp_Interp(); @@ -60,33 +76,41 @@ public: virtual int run(const char *command); - PyLockWrapper GetLockWrapper(); + // [ABN] - the PyLockWrapper is no more attached to the interpreter + // PyLockWrapper GetLockWrapper() const; - std::string getbanner(); + std::string getbanner() const; void setverrcb(PyOutChanged*,void*); void setvoutcb(PyOutChanged*,void*); const char * getPrevious(); - const char * getNext(); + const char * getNext(); protected: - PyThreadState * _tstate; + /** Redirection of stdout and stderr */ PyObject * _vout; PyObject * _verr; - PyObject * _g; + /** Execution context (local and global variables) */ + PyObject * _context; PyObject * _codeop; std::list _history; std::list::iterator _ith; - virtual int beforeRun() { return 0; } + virtual int beforeRun(); int simpleRun(const char* command, const bool addToHistory = true); - virtual bool initRun(); virtual void initPython(); - virtual bool initState() = 0; - virtual bool initContext() = 0; + /** OBSOLETE - should'nt be called anymore */ + //virtual bool initState() = 0; + + /** Initialize execution context. Must set the member _context, and return True on success. */ + virtual bool initContext() = 0; + virtual bool initRun(); }; +/** + * Utility class to properly handle the reference counting required on Python objects. + */ class PYINTERP_EXPORT PyObjWrapper { PyObject* myObject; diff --git a/src/PyInterp/PyInterp_Request.h b/src/PyInterp/PyInterp_Request.h index 9a4291b36..2c09a335c 100644 --- a/src/PyInterp/PyInterp_Request.h +++ b/src/PyInterp/PyInterp_Request.h @@ -88,7 +88,7 @@ class PYINTERP_EXPORT PyInterp_LockRequest : public PyInterp_Request { public: - PyInterp_LockRequest( PyInterp_Interp* interp, QObject* listener = 0, bool sync = false ) + PyInterp_LockRequest( PyInterp_Interp* interp, QObject* listener=0, bool sync=false ) : PyInterp_Request( listener, sync ), myInterp( interp ) {} diff --git a/src/SALOME_PYQT/SALOME_PYQT_GUI/SALOME_PYQT_Module.cxx b/src/SALOME_PYQT/SALOME_PYQT_GUI/SALOME_PYQT_Module.cxx index b1e1683f0..31439aeda 100644 --- a/src/SALOME_PYQT/SALOME_PYQT_GUI/SALOME_PYQT_Module.cxx +++ b/src/SALOME_PYQT/SALOME_PYQT_GUI/SALOME_PYQT_Module.cxx @@ -67,10 +67,8 @@ extern "C" { static bool alreadyInitialized = false; if ( !alreadyInitialized ) { - // call only once (see comment above) ! - PyEval_RestoreThread( KERNEL_PYTHON::_gtstate); + PyLockWrapper lck; // GIL acquisition INIT_FUNCTION(); - PyEval_ReleaseThread( KERNEL_PYTHON::_gtstate); alreadyInitialized = !alreadyInitialized; } diff --git a/src/SALOME_PYQT/SALOME_PYQT_GUILight/SALOME_PYQT_ModuleLight.cxx b/src/SALOME_PYQT/SALOME_PYQT_GUILight/SALOME_PYQT_ModuleLight.cxx index 886022377..7b94636db 100644 --- a/src/SALOME_PYQT/SALOME_PYQT_GUILight/SALOME_PYQT_ModuleLight.cxx +++ b/src/SALOME_PYQT/SALOME_PYQT_GUILight/SALOME_PYQT_ModuleLight.cxx @@ -37,11 +37,11 @@ // Py_ssize_t for old Pythons // This code is as recommended by" // http://www.python.org/dev/peps/pep-0353/#conversion-guidelines -#if PY_VERSION_HEX < 0x02050000 && !defined(PY_SSIZE_T_MIN) -typedef int Py_ssize_t; -# define PY_SSIZE_T_MAX INT_MAX -# define PY_SSIZE_T_MIN INT_MIN -#endif +//#if PY_VERSION_HEX < 0x02050000 && !defined(PY_SSIZE_T_MIN) +//typedef int Py_ssize_t; +//# define PY_SSIZE_T_MAX INT_MAX +//# define PY_SSIZE_T_MIN INT_MIN +//#endif // // NB: Python requests. @@ -83,21 +83,8 @@ extern "C" // make initialization only once (see comment above) ! if ( !alreadyInitialized ) { - static PyThreadState* gtstate = 0; -#ifndef GUI_DISABLE_CORBA - if ( SUIT_PYTHON::initialized ) - gtstate = SUIT_PYTHON::_gtstate; - else - gtstate = KERNEL_PYTHON::_gtstate; -#else - gtstate = SUIT_PYTHON::_gtstate; -#endif - PyEval_RestoreThread( gtstate ); - + PyLockWrapper lck; // GIL acquisition INIT_FUNCTION(); - - PyEval_ReleaseThread( gtstate ); - alreadyInitialized = !alreadyInitialized; } diff --git a/src/SALOME_PYQT/SALOME_PYQT_GUILight/SALOME_PYQT_ModuleLight.h b/src/SALOME_PYQT/SALOME_PYQT_GUILight/SALOME_PYQT_ModuleLight.h index dff9b5963..1e07b4332 100644 --- a/src/SALOME_PYQT/SALOME_PYQT_GUILight/SALOME_PYQT_ModuleLight.h +++ b/src/SALOME_PYQT/SALOME_PYQT_GUILight/SALOME_PYQT_ModuleLight.h @@ -71,9 +71,9 @@ public: // data model management QString createObject( const QString& ); QString createObject( const QString&, - const QString&, - const QString&, - const QString& ); + const QString&, + const QString&, + const QString& ); void setName( const QString&, const QString& ); QString getName( const QString& ) const; diff --git a/src/SALOME_PYQT/SALOME_PYQT_GUILight/SALOME_PYQT_PyInterp.cxx b/src/SALOME_PYQT/SALOME_PYQT_GUILight/SALOME_PYQT_PyInterp.cxx index 849ff2c7d..ab58c83d4 100644 --- a/src/SALOME_PYQT/SALOME_PYQT_GUILight/SALOME_PYQT_PyInterp.cxx +++ b/src/SALOME_PYQT/SALOME_PYQT_GUILight/SALOME_PYQT_PyInterp.cxx @@ -49,38 +49,9 @@ void SALOME_PYQT_PyInterp::initPython() * Do nothing * The initialization has been done in main */ - MESSAGE("SALOME_PYQT_PyInterp::initPython"); -#ifndef GUI_DISABLE_CORBA - if(SUIT_PYTHON::initialized) { - ASSERT(SUIT_PYTHON::_gtstate); // initialisation in main - SCRUTE(SUIT_PYTHON::_gtstate); - _tstate = SUIT_PYTHON::_gtstate; - } - else { - ASSERT(KERNEL_PYTHON::_gtstate); // initialisation in main - SCRUTE(KERNEL_PYTHON::_gtstate); - _tstate = KERNEL_PYTHON::_gtstate; - } -#else - SCRUTE(SUIT_PYTHON::_gtstate); - _tstate = SUIT_PYTHON::_gtstate; -#endif -} - -bool SALOME_PYQT_PyInterp::initState() -{ - /* - * The GIL is assumed to not be held on the call - * The GIL is acquired in initState and will be held on initState exit - * It is the caller responsability to release the lock on exit if needed - */ - PyEval_AcquireThread(_tstate); - SCRUTE(_tstate); - PyEval_ReleaseThread(_tstate); - return true; + MESSAGE("SALOME_PYQT_PyInterp::initPython - does nothing"); } - bool SALOME_PYQT_PyInterp::initContext() { /* @@ -88,10 +59,7 @@ bool SALOME_PYQT_PyInterp::initContext() * It is the caller responsability to acquire the GIL before calling initContext * It will still be held on initContext exit */ - _g = PyDict_New(); // create interpreter dictionnary context - PyObject *bimod = PyImport_ImportModule("__builtin__"); - PyDict_SetItemString(_g, "__builtins__", bimod); - Py_DECREF(bimod); + _context = PyDict_New(); // create interpreter dictionnary context return true; } @@ -100,18 +68,15 @@ int SALOME_PYQT_PyInterp::run(const char *command) MESSAGE("compile"); PyObject *code = Py_CompileString((char *)command,"PyGUI",Py_file_input); if(!code){ - // Une erreur s est produite en general SyntaxError + // An error occured - normally here a SyntaxError PyErr_Print(); return -1; } - //#if PY_VERSION_HEX < 0x02040000 // python version earlier than 2.4.0 - // PyObject *r = PyEval_EvalCode(code,_g,_g); - //#else - PyObject *r = PyEval_EvalCode((PyCodeObject *)code,_g,_g); - //#endif + PyObject *r = PyEval_EvalCode((PyCodeObject *)code,_context,_context); + Py_DECREF(code); if(!r){ - // Une erreur s est produite a l execution + // An error occured at execution PyErr_Print(); return -1 ; } diff --git a/src/SALOME_PYQT/SALOME_PYQT_GUILight/SALOME_PYQT_PyInterp.h b/src/SALOME_PYQT/SALOME_PYQT_GUILight/SALOME_PYQT_PyInterp.h index ebf5c2553..6abdde73f 100644 --- a/src/SALOME_PYQT/SALOME_PYQT_GUILight/SALOME_PYQT_PyInterp.h +++ b/src/SALOME_PYQT/SALOME_PYQT_GUILight/SALOME_PYQT_PyInterp.h @@ -38,7 +38,6 @@ class SALOME_PYQT_LIGHT_EXPORT SALOME_PYQT_PyInterp : public PyInterp_Interp protected: virtual void initPython(); - virtual bool initState(); virtual bool initContext(); }; diff --git a/src/SALOME_PYQT/SALOME_PYQT_GUILight/SALOME_PYQT_PyModule.cxx b/src/SALOME_PYQT/SALOME_PYQT_GUILight/SALOME_PYQT_PyModule.cxx index b4eba060a..a9d6ad43f 100644 --- a/src/SALOME_PYQT/SALOME_PYQT_GUILight/SALOME_PYQT_PyModule.cxx +++ b/src/SALOME_PYQT/SALOME_PYQT_GUILight/SALOME_PYQT_PyModule.cxx @@ -228,9 +228,9 @@ public: XmlHandler( PyModuleHelper* helper, const QString& fileName ); void createActions(); void createPopup( QMenu* menu, - const QString& context, - const QString& parent, - const QString& object ); + const QString& context, + const QString& parent, + const QString& object ); void activateMenus( bool ); private: @@ -238,11 +238,11 @@ private: QIcon loadIcon( const QString& fileName ); void createMenu( QDomNode& parentNode, - const int parentMenuId = -1, - QMenu* parentPopup = 0 ); + const int parentMenuId = -1, + QMenu* parentPopup = 0 ); void createToolBar( QDomNode& parentNode ); void insertPopupItems( QDomNode& parentNode, - QMenu* menu ); + QMenu* menu ); private: PyModuleHelper* myHelper; @@ -258,7 +258,7 @@ private: \param fileName path to the XML menu description file */ PyModuleHelper::XmlHandler::XmlHandler( PyModuleHelper* helper, - const QString& fileName ) + const QString& fileName ) : myHelper( helper ) { if ( !fileName.isEmpty() ) { @@ -305,9 +305,9 @@ void PyModuleHelper::XmlHandler::createActions() \param context popup menu object name */ void PyModuleHelper::XmlHandler::createPopup( QMenu* menu, - const QString& context, - const QString& parent, - const QString& object ) + const QString& context, + const QString& parent, + const QString& object ) { // get document element QDomElement aDocElem = myDoc.documentElement(); @@ -364,10 +364,10 @@ QIcon PyModuleHelper::XmlHandler::loadIcon( const QString& fileName ) if ( module() && !fileName.isEmpty() ) { SUIT_ResourceMgr* resMgr = module()->getApp()->resourceMgr(); QPixmap pixmap = resMgr->loadPixmap( module()->name(), - QApplication::translate( module()->name().toLatin1().data(), - fileName.toLatin1().data() ) ); - if ( !pixmap.isNull() ) - icon = QIcon( pixmap ); + QApplication::translate( module()->name().toLatin1().data(), + fileName.toLatin1().data() ) ); + if ( !pixmap.isNull() ) + icon = QIcon( pixmap ); } return icon; @@ -381,8 +381,8 @@ QIcon PyModuleHelper::XmlHandler::loadIcon( const QString& fileName ) \param parentPopup parent popup menu (0 for top-level menu) */ void PyModuleHelper::XmlHandler::createMenu( QDomNode& parentNode, - const int parentMenuId, - QMenu* parentPopup ) + const int parentMenuId, + QMenu* parentPopup ) { if ( !module() || parentNode.isNull() ) return; @@ -425,14 +425,14 @@ void PyModuleHelper::XmlHandler::createMenu( QDomNode& parentNode, if ( id != -1 ) { // create menu action QAction* action = module()->createAction( id, // ID - tooltip, // tooltip - icon, // icon - label, // menu text - tooltip, // status-bar text - QKeySequence( accel ), // keyboard accelerator - module(), // action owner - toggle ); // toogled action - myHelper->connectAction( action ); + tooltip, // tooltip + icon, // icon + label, // menu text + tooltip, // status-bar text + QKeySequence( accel ), // keyboard accelerator + module(), // action owner + toggle ); // toogled action + myHelper->connectAction( action ); module()->createMenu( action, // action menuId, // parent menu ID id, // ID (same as for createAction()) @@ -496,17 +496,17 @@ void PyModuleHelper::XmlHandler::createToolBar( QDomNode& parentNode ) // -1 action ID is not allowed : it means that attribute is missed in the XML file! // also check if the action with given ID is already created if ( id != -1 ) { - // create toolbar action - QAction* action = module()->createAction( id, // ID - tooltip, // tooltip - icon, // icon - label, // menu text - tooltip, // status-bar text - QKeySequence( accel ), // keyboard accelerator - module(), // action owner - toggle ); // toogled action - myHelper->connectAction( action ); - module()->createTool( action, tbId, -1, pos ); + // create toolbar action + QAction* action = module()->createAction( id, // ID + tooltip, // tooltip + icon, // icon + label, // menu text + tooltip, // status-bar text + QKeySequence( accel ), // keyboard accelerator + module(), // action owner + toggle ); // toogled action + myHelper->connectAction( action ); + module()->createTool( action, tbId, -1, pos ); } } else if ( aTagName == "separatorTB" || aTagName == "separator" ) { @@ -552,15 +552,15 @@ void PyModuleHelper::XmlHandler::insertPopupItems( QDomNode& parentNode, QMenu* // -1 action ID is not allowed : it means that attribute is missed in the XML file! // also check if the action with given ID is already created if ( id != -1 ) { - QAction* action = module()->createAction( id, // ID - tooltip, // tooltip - icon, // icon - label, // menu text - tooltip, // status-bar text - QKeySequence( accel ), // keyboard accelerator - module(), // action owner - toggle ); // toogled action - myHelper->connectAction( action ); + QAction* action = module()->createAction( id, // ID + tooltip, // tooltip + icon, // icon + label, // menu text + tooltip, // status-bar text + QKeySequence( accel ), // keyboard accelerator + module(), // action owner + toggle ); // toogled action + myHelper->connectAction( action ); QAction* before = ( pos >= 0 && pos < actions.count() ) ? actions[ pos ] : 0; menu->insertAction( before, action ); } @@ -627,7 +627,7 @@ PyModuleHelper::~PyModuleHelper() { delete myXmlHandler; if ( myInterp && myPyModule ) { - PyLockWrapper aLock = myInterp->GetLockWrapper(); + PyLockWrapper aLock; // Acquire GIL Py_XDECREF( myPyModule ); } } @@ -691,8 +691,8 @@ void PyModuleHelper::connectAction( QAction* a ) { if ( myModule && a ) QObject::connect( a, SIGNAL( triggered( bool ) ), - this, SLOT( actionActivated() ), - Qt::UniqueConnection ); + this, SLOT( actionActivated() ), + Qt::UniqueConnection ); } /*! @@ -747,11 +747,11 @@ QStringList PyModuleHelper::viewManagers() const \brief Initialization of the Python-based SALOME module. This method can be used for creation of the menus, toolbars and - other such staff. + other such stuff. There are two ways to do this: - 1) for obsolete modules implementatino this method first tries to read - _.xml resource file which contains a menu, + 1) for obsolete modules, the implementation of this method first tries to read + the _.xml resource file which contains a menu, toolbars and popup menus description; 2) new modules can create menus by direct calling of the corresponding methods of SalomePyQt Python API in the Python @@ -759,7 +759,7 @@ QStringList PyModuleHelper::viewManagers() const \note SALOME supports two modes of modules loading: - immediate (all the modules are created and initialized - immediately when the application object is created; + immediately when the application object is created); - postponed modules loading (used currently); in this mode the module is loaded only by explicit request. If postponed modules loading is not used, the active @@ -798,10 +798,10 @@ void PyModuleHelper::initialize( CAM_Application* app ) { public: InitializeReq( PyModuleHelper* _helper, - CAM_Application* _app ) + CAM_Application* _app ) : PyInterp_Request( 0, true ), // this request should be processed synchronously (sync == true) myHelper( _helper ), - myApp( _app ) + myApp( _app ) {} protected: virtual void execute() @@ -841,21 +841,21 @@ bool PyModuleHelper::activate( SUIT_Study* study ) { public: ActivateReq( PyModuleHelper* _helper, - SUIT_Study* _study, - bool _customize ) - : PyInterp_Request( 0, true ), // this request should be processed synchronously (sync == true) - myHelper( _helper ), - myStudy ( _study ), - myCustomize( _customize ) - {} + SUIT_Study* _study, + bool _customize ) + : PyInterp_Request( 0, true ), // this request should be processed synchronously (sync == true) + myHelper( _helper ), + myStudy ( _study ), + myCustomize( _customize ) + {} protected: virtual void execute() - { - if ( !myCustomize ) - myHelper->internalActivate( myStudy ); // first activation stage - else - myHelper->internalCustomize( myStudy ); // second activation stage - } + { + if ( !myCustomize ) + myHelper->internalActivate( myStudy ); // first activation stage + else + myHelper->internalCustomize( myStudy ); // second activation stage + } private: PyModuleHelper* myHelper; SUIT_Study* myStudy; @@ -881,12 +881,12 @@ bool PyModuleHelper::activate( SUIT_Study* study ) if ( myLastActivateStatus ) { // connect preferences changing signal connect( myModule->getApp(), SIGNAL( preferenceChanged( const QString&, const QString&, const QString& ) ), - this, SLOT( preferenceChanged( const QString&, const QString&, const QString& ) ) ); + this, SLOT( preferenceChanged( const QString&, const QString&, const QString& ) ) ); // connect active view change signal SUIT_Desktop* d = study->application()->desktop(); connect( d, SIGNAL( windowActivated( SUIT_ViewWindow* ) ), - this, SLOT( activeViewChanged( SUIT_ViewWindow* ) ) ); + this, SLOT( activeViewChanged( SUIT_ViewWindow* ) ) ); // if active window exists, call activeViewChanged() function; // temporary solution: if a getActiveView() in SalomePyQt available // we no longer need this @@ -924,11 +924,11 @@ bool PyModuleHelper::deactivate( SUIT_Study* study ) { public: DeactivateReq( PyInterp_Interp* _py_interp, - PyModuleHelper* _helper, + PyModuleHelper* _helper, SUIT_Study* _study ) : PyInterp_LockRequest( _py_interp, 0, true ), // this request should be processed synchronously (sync == true) myHelper( _helper ), - myStudy ( _study ) + myStudy ( _study ) {} protected: virtual void execute() @@ -950,7 +950,7 @@ bool PyModuleHelper::deactivate( SUIT_Study* study ) // disconnect the SUIT_Desktop signal windowActivated() SUIT_Desktop* d = study->application()->desktop(); disconnect( d, SIGNAL( windowActivated( SUIT_ViewWindow* ) ), - this, SLOT( activeViewChanged( SUIT_ViewWindow* ) ) ); + this, SLOT( activeViewChanged( SUIT_ViewWindow* ) ) ); // deactivate menus, toolbars, etc if ( myXmlHandler ) myXmlHandler->activateMenus( false ); @@ -1023,7 +1023,7 @@ void PyModuleHelper::modelClosed( SUIT_Study* study ) \param parameter preference resources parameter name */ void PyModuleHelper::preferencesChanged( const QString& section, - const QString& parameter ) + const QString& parameter ) { FuncMsg fmsg( "PyModuleHelper::preferencesChanged()" ); @@ -1031,9 +1031,9 @@ void PyModuleHelper::preferencesChanged( const QString& section, { public: PrefChangeReq( PyInterp_Interp* _py_interp, - PyModuleHelper* _helper, - const QString& _section, - const QString& _parameter ) + PyModuleHelper* _helper, + const QString& _section, + const QString& _parameter ) : PyInterp_LockRequest( _py_interp, 0, true ), // this request should be processed synchronously (sync == true) myHelper ( _helper ), mySection( _section ), @@ -1065,8 +1065,8 @@ void PyModuleHelper::preferencesChanged( const QString& section, \param parameter preference resources parameter name */ void PyModuleHelper::preferenceChanged( const QString& module, - const QString& section, - const QString& parameter ) + const QString& section, + const QString& parameter ) { FuncMsg fmsg( "PyModuleHelper::preferenceChanged()" ); @@ -1094,10 +1094,10 @@ void PyModuleHelper::studyActivated( SUIT_Study* study ) { public: StudyChangedReq( PyModuleHelper* _helper, - SUIT_Study* _study ) + SUIT_Study* _study ) : PyInterp_Request( 0, true ), // this request should be processed synchronously (sync == true) myHelper( _helper ), - myStudy ( _study ) + myStudy ( _study ) {} protected: virtual void execute() @@ -1130,8 +1130,8 @@ void PyModuleHelper::actionActivated() { public: ActionReq( PyInterp_Interp* _py_interp, - PyModuleHelper* _helper, - int _id ) + PyModuleHelper* _helper, + int _id ) : PyInterp_LockRequest( _py_interp, 0, true ), // this request should be processed synchronously (sync == true) myHelper( _helper ), myId ( _id ) @@ -1176,7 +1176,7 @@ void PyModuleHelper::contextMenu( const QString& context, QMenu* menu ) const QString& _context, QMenu* _menu ) : PyInterp_LockRequest( _py_interp, 0, true ), // this request should be processed synchronously (sync == true) - myHelper ( _helper ), + myHelper ( _helper ), myContext( _context ), myMenu ( _menu ) {} @@ -1214,7 +1214,7 @@ void PyModuleHelper::createPreferences() { public: CreatePrefReq( PyInterp_Interp* _py_interp, - PyModuleHelper* _helper ) + PyModuleHelper* _helper ) : PyInterp_LockRequest( _py_interp, 0, true ), // this request should be processed synchronously (sync == true) myHelper( _helper ) {} @@ -1249,11 +1249,11 @@ void PyModuleHelper::activeViewChanged( SUIT_ViewWindow* view ) { public: ActiveViewChangeReq( PyInterp_Interp* _py_interp, - PyModuleHelper* _helper, - SUIT_ViewWindow* _view ) + PyModuleHelper* _helper, + SUIT_ViewWindow* _view ) : PyInterp_LockRequest( _py_interp, 0, true ), myHelper( _helper ), - myView( _view ) + myView( _view ) {} protected: virtual void execute() @@ -1283,11 +1283,11 @@ void PyModuleHelper::tryCloseView( SUIT_ViewWindow* view ) { public: TryCloseViewReq( PyInterp_Interp* _py_interp, - PyModuleHelper* _helper, - SUIT_ViewWindow* _view ) + PyModuleHelper* _helper, + SUIT_ViewWindow* _view ) : PyInterp_LockRequest( _py_interp, 0, true ), myHelper( _helper ), - myView( _view ) + myView( _view ) {} protected: virtual void execute() @@ -1314,8 +1314,8 @@ void PyModuleHelper::closeView( SUIT_ViewWindow* view ) { public: CloseViewReq( PyInterp_Interp* _py_interp, - PyModuleHelper* _helper, - SUIT_ViewWindow* _view ) + PyModuleHelper* _helper, + SUIT_ViewWindow* _view ) : PyInterp_LockRequest( _py_interp, 0, true ), myHelper( _helper ), myView( _view ) @@ -1345,11 +1345,11 @@ void PyModuleHelper::cloneView( SUIT_ViewWindow* view ) { public: CloneViewReq( PyInterp_Interp* _py_interp, - PyModuleHelper* _helper, - SUIT_ViewWindow* _view ) + PyModuleHelper* _helper, + SUIT_ViewWindow* _view ) : PyInterp_LockRequest( _py_interp, 0, true ), myHelper( _helper ), - myView( _view ) + myView( _view ) {} protected: virtual void execute() @@ -1383,8 +1383,8 @@ void PyModuleHelper::save( QStringList& files ) { public: SaveReq( PyInterp_Interp* _py_interp, - PyModuleHelper* _helper, - QStringList& _files ) + PyModuleHelper* _helper, + QStringList& _files ) : PyInterp_LockRequest( _py_interp, 0, true ), // this request should be processed synchronously (sync == true) myHelper( _helper ) , myFiles( _files ) @@ -1420,9 +1420,9 @@ bool PyModuleHelper::load( const QStringList& files ) { public: LoadReq( PyInterp_Interp* _py_interp, - PyModuleHelper* _helper, - QStringList _files, - bool& _loaded ) + PyModuleHelper* _helper, + QStringList _files, + bool& _loaded ) : PyInterp_LockRequest( _py_interp, 0, true ), // this request should be processed synchronously (sync == true) myHelper( _helper ) , myFiles( _files ), @@ -1466,8 +1466,8 @@ void PyModuleHelper::dumpPython( QStringList& files ) { public: DumpPythonReq( PyInterp_Interp* _py_interp, - PyModuleHelper* _helper, - QStringList& _files ) + PyModuleHelper* _helper, + QStringList& _files ) : PyInterp_LockRequest( _py_interp, 0, true ), // this request should be processed synchronously (sync == true) myHelper( _helper ) , myFiles( _files ) @@ -1504,9 +1504,9 @@ bool PyModuleHelper::isDraggable( const SUIT_DataObject* what ) const { public: IsDraggableReq( PyInterp_Interp* _py_interp, - PyModuleHelper* _helper, - LightApp_DataObject* _data_object, - bool& _is_draggable ) + PyModuleHelper* _helper, + LightApp_DataObject* _data_object, + bool& _is_draggable ) : PyInterp_LockRequest( _py_interp, 0, true ), // this request should be processed synchronously (sync == true) myHelper( _helper ) , myDataObject( _data_object ), @@ -1529,9 +1529,9 @@ bool PyModuleHelper::isDraggable( const SUIT_DataObject* what ) const // Executing the request synchronously if ( !PyInterp_Dispatcher::Get()->IsBusy() ) PyInterp_Dispatcher::Get()->Exec( new IsDraggableReq( myInterp, - const_cast( this ), - const_cast( data_object ), - draggable ) ); + const_cast( this ), + const_cast( data_object ), + draggable ) ); } return draggable; @@ -1553,9 +1553,9 @@ bool PyModuleHelper::isDropAccepted( const SUIT_DataObject* where ) const { public: IsDropAcceptedReq( PyInterp_Interp* _py_interp, - PyModuleHelper* _helper, - LightApp_DataObject* _data_object, - bool& _is_drop_accepted ) + PyModuleHelper* _helper, + LightApp_DataObject* _data_object, + bool& _is_drop_accepted ) : PyInterp_LockRequest( _py_interp, 0, true ), // this request should be processed synchronously (sync == true) myHelper( _helper ) , myDataObject( _data_object ), @@ -1578,9 +1578,9 @@ bool PyModuleHelper::isDropAccepted( const SUIT_DataObject* where ) const // Executing the request synchronously if ( !PyInterp_Dispatcher::Get()->IsBusy() ) PyInterp_Dispatcher::Get()->Exec( new IsDropAcceptedReq( myInterp, - const_cast( this ), - const_cast( data_object ), - dropAccepted ) ); + const_cast( this ), + const_cast( data_object ), + dropAccepted ) ); } return dropAccepted; @@ -1594,7 +1594,7 @@ bool PyModuleHelper::isDropAccepted( const SUIT_DataObject* where ) const \param action current drop action (copy or move) */ void PyModuleHelper::dropObjects( const DataObjectList& what, SUIT_DataObject* where, - const int row, Qt::DropAction action ) + const int row, Qt::DropAction action ) { FuncMsg fmsg( "PyModuleHelper::dropObjects()" ); @@ -1603,17 +1603,17 @@ void PyModuleHelper::dropObjects( const DataObjectList& what, SUIT_DataObject* w { public: DropObjectsReq( PyInterp_Interp* _py_interp, - PyModuleHelper* _helper, - const DataObjectList& _what, - SUIT_DataObject* _where, - const int _row, - Qt::DropAction _action ) + PyModuleHelper* _helper, + const DataObjectList& _what, + SUIT_DataObject* _where, + const int _row, + Qt::DropAction _action ) : PyInterp_LockRequest( _py_interp, 0, true ), // this request should be processed synchronously (sync == true) myHelper( _helper ) , myWhat( _what ), - myWhere( _where ), - myRow( _row ), - myAction ( _action ) + myWhere( _where ), + myRow( _row ), + myAction ( _action ) {} protected: virtual void execute() @@ -1647,10 +1647,10 @@ QString PyModuleHelper::engineIOR() const public: EngineIORReq( PyInterp_Interp* _py_interp, PyModuleHelper* _helper, - QString& _ior ) + QString& _ior ) : PyInterp_LockRequest( _py_interp, 0, true ), // this request should be processed synchronously (sync == true) myHelper( _helper ), - myIOR( _ior ) + myIOR( _ior ) {} protected: virtual void execute() @@ -1667,8 +1667,8 @@ QString PyModuleHelper::engineIOR() const if ( anIOR.isEmpty() ) { // post request PyInterp_Dispatcher::Get()->Exec( new EngineIORReq( myInterp, - const_cast( this ), - anIOR ) ); + const_cast( this ), + anIOR ) ); } return anIOR; @@ -1708,7 +1708,7 @@ void PyModuleHelper::initInterp( int studyId ) // import 'salome' module and call 'salome_init' method; // do it only once on interpreter creation // ... first get python lock - PyLockWrapper aLock = myInterp->GetLockWrapper(); + PyLockWrapper aLock; // Acquire GIL // ... then import a module PyObjWrapper aMod = PyImport_ImportModule( "salome" ); if ( !aMod ) { @@ -1732,7 +1732,7 @@ void PyModuleHelper::initInterp( int studyId ) \brief Import Python GUI module and store reference to the module. \internal - Attention! initInterp() should be called first!!! + Warning! initInterp() should be called first!!! */ void PyModuleHelper::importModule() { @@ -1747,7 +1747,7 @@ void PyModuleHelper::importModule() // import Python GUI module and put it in attribute // ... first get python lock - PyLockWrapper aLock = myInterp->GetLockWrapper(); + PyLockWrapper aLock; // Acquire GIL // ... then import a module QString aMod = QString( "%1GUI" ).arg( myModule->name() ); try { @@ -1787,7 +1787,7 @@ void PyModuleHelper::setWorkSpace() // call setWorkSpace() method // ... first get python lock - PyLockWrapper aLock = myInterp->GetLockWrapper(); + PyLockWrapper aLock; // Acquire GIL // ... then try to import SalomePyQt module. If it's not possible don't go on. PyObjWrapper aQtModule( PyImport_ImportModule( "SalomePyQt" ) ); @@ -1865,7 +1865,7 @@ void PyModuleHelper::internalInitialize( CAM_Application* app ) // then call Python module's initialize() method // ... first get python lock - PyLockWrapper aLock = myInterp->GetLockWrapper(); + PyLockWrapper aLock; // Acquire GIL // ... (the Python module is already imported) // ... finally call Python module's initialize() method @@ -1969,7 +1969,7 @@ void PyModuleHelper::internalActivate( SUIT_Study* study ) } // get python lock - PyLockWrapper aLock = myInterp->GetLockWrapper(); + PyLockWrapper aLock; // Acquire GIL // call Python module's activate() method (for the new modules) if ( PyObject_HasAttrString( myPyModule , (char*)"activate" ) ) { @@ -2024,7 +2024,7 @@ void PyModuleHelper::internalCustomize( SUIT_Study* study ) setWorkSpace(); // get python lock - PyLockWrapper aLock = myInterp->GetLockWrapper(); + PyLockWrapper aLock; // Acquire GIL if ( IsCallOldMethods ) { // call Python module's setSettings() method (obsolete) @@ -2166,7 +2166,7 @@ void PyModuleHelper::internalStudyChanged( SUIT_Study* study ) setWorkSpace(); // get python lock - PyLockWrapper aLock = myInterp->GetLockWrapper(); + PyLockWrapper aLock; // Acquire GIL // call Python module's activeStudyChanged() method if ( PyObject_HasAttrString( myPyModule, (char*)"activeStudyChanged" ) ) { @@ -2552,7 +2552,7 @@ bool PyModuleHelper::internalIsDraggable( LightApp_DataObject* what ) if ( PyObject_HasAttrString(myPyModule , (char*)"isDraggable") ) { PyObjWrapper res( PyObject_CallMethod( myPyModule, (char*)"isDraggable", - (char*)"s", what->entry().toLatin1().constData() ) ); + (char*)"s", what->entry().toLatin1().constData() ) ); if( !res || !PyBool_Check( res )) { PyErr_Print(); draggable = false; @@ -2584,7 +2584,7 @@ bool PyModuleHelper::internalIsDropAccepted( LightApp_DataObject* where ) if ( PyObject_HasAttrString(myPyModule , (char*)"isDropAccepted") ) { PyObjWrapper res( PyObject_CallMethod( myPyModule, (char*)"isDropAccepted", - (char*)"s", where->entry().toLatin1().constData() ) ); + (char*)"s", where->entry().toLatin1().constData() ) ); if( !res || !PyBool_Check( res )) { PyErr_Print(); dropAccepted = false; @@ -2606,7 +2606,7 @@ bool PyModuleHelper::internalIsDropAccepted( LightApp_DataObject* where ) \param action current drop action (copy or move) */ void PyModuleHelper::internalDropObjects( const DataObjectList& what, SUIT_DataObject* where, - const int row, Qt::DropAction action ) + const int row, Qt::DropAction action ) { FuncMsg fmsg( "--- PyModuleHelper::internalDropObjects()" ); @@ -2631,10 +2631,10 @@ void PyModuleHelper::internalDropObjects( const DataObjectList& what, SUIT_DataO PyObjWrapper sipList( sipBuildResult( 0, "D", theList, sipType_QStringList, NULL) ); #endif if ( PyObject_HasAttrString(myPyModule, (char*)"dropObjects") ) { - PyObjWrapper res( PyObject_CallMethod( myPyModule, (char*)"dropObjects", (char*)"Osii", - sipList.get(), - whereObject->entry().toLatin1().constData(), - row, action ) ); + PyObjWrapper res( PyObject_CallMethod( myPyModule, (char*)"dropObjects", (char*)"Osii", + sipList.get(), + whereObject->entry().toLatin1().constData(), + row, action ) ); if( !res ) { PyErr_Print(); @@ -2663,13 +2663,13 @@ QString PyModuleHelper::internalEngineIOR() const if ( PyObject_HasAttrString( myPyModule , "engineIOR" ) ) { PyObjWrapper res( PyObject_CallMethod( myPyModule, (char*)"engineIOR", (char*)"" ) ); if ( !res ) { - PyErr_Print(); + PyErr_Print(); } else { - // parse the return value, result chould be string - if ( PyString_Check( res ) ) { - ior = PyString_AsString( res ); - } + // parse the return value, result chould be string + if ( PyString_Check( res ) ) { + ior = PyString_AsString( res ); + } } } } @@ -2688,23 +2688,23 @@ void PyModuleHelper::connectView( SUIT_ViewWindow* view ) // Connect tryCloseView() and deleteView() signals if ( viewMgr ) { connect( viewMgr, SIGNAL( tryCloseView( SUIT_ViewWindow* ) ), - this, SLOT( tryCloseView( SUIT_ViewWindow* ) ), - Qt::UniqueConnection ); + this, SLOT( tryCloseView( SUIT_ViewWindow* ) ), + Qt::UniqueConnection ); connect( viewMgr, SIGNAL( deleteView( SUIT_ViewWindow* ) ), this, SLOT( closeView( SUIT_ViewWindow* ) ), - Qt::UniqueConnection ); + Qt::UniqueConnection ); } // Connect cloneView() signal of an OCC View if ( view->inherits( "OCCViewer_ViewWindow" ) ) { connect( view, SIGNAL( viewCloned( SUIT_ViewWindow* ) ), this, SLOT( cloneView( SUIT_ViewWindow* ) ), - Qt::UniqueConnection ); + Qt::UniqueConnection ); } // Connect cloneView() signal of Plot2d View else if ( viewModel && viewModel->inherits( "Plot2d_Viewer" ) ) { connect( viewModel, SIGNAL( viewCloned( SUIT_ViewWindow* ) ), this, SLOT( cloneView( SUIT_ViewWindow* ) ), - Qt::UniqueConnection ); + Qt::UniqueConnection ); } } diff --git a/src/SALOME_PYQT/SALOME_PYQT_GUILight/SALOME_PYQT_PyModule.h b/src/SALOME_PYQT/SALOME_PYQT_GUILight/SALOME_PYQT_PyModule.h index 49c429632..4a823bc44 100644 --- a/src/SALOME_PYQT/SALOME_PYQT_GUILight/SALOME_PYQT_PyModule.h +++ b/src/SALOME_PYQT/SALOME_PYQT_GUILight/SALOME_PYQT_PyModule.h @@ -103,7 +103,7 @@ public slots: bool isDraggable( const SUIT_DataObject* ) const; bool isDropAccepted( const SUIT_DataObject* ) const; void dropObjects( const DataObjectList&, SUIT_DataObject*, - const int, Qt::DropAction ); + const int, Qt::DropAction ); QString engineIOR() const; private: @@ -131,7 +131,7 @@ private: bool internalIsDraggable( LightApp_DataObject* ); bool internalIsDropAccepted( LightApp_DataObject* ); void internalDropObjects( const DataObjectList&, SUIT_DataObject*, - const int, Qt::DropAction ); + const int, Qt::DropAction ); QString internalEngineIOR() const; void connectView( SUIT_ViewWindow* ); diff --git a/src/SUITApp/SUITApp.cxx b/src/SUITApp/SUITApp.cxx index 725a53ec1..7c5a6a262 100644 --- a/src/SUITApp/SUITApp.cxx +++ b/src/SUITApp/SUITApp.cxx @@ -277,16 +277,7 @@ int main( int argc, char* argv[] ) int _argc = 1; char* _argv[] = {(char*)""}; SUIT_PYTHON::init_python(_argc,_argv); - - PyEval_RestoreThread( SUIT_PYTHON::_gtstate ); - - if ( !SUIT_PYTHON::salome_shared_modules_module ) // import only once - SUIT_PYTHON::salome_shared_modules_module = PyImport_ImportModule( (char*)"salome_shared_modules" ); - if ( !SUIT_PYTHON::salome_shared_modules_module ) - PyErr_Print(); - - PyEval_ReleaseThread( SUIT_PYTHON::_gtstate ); - + PyEval_ReleaseLock(); #endif SUIT_Application* theApp = aSession->startApplication( argList.first() ); diff --git a/src/SUITApp/SUITApp_init_python.cxx b/src/SUITApp/SUITApp_init_python.cxx index a158de5d2..8cb014016 100644 --- a/src/SUITApp/SUITApp_init_python.cxx +++ b/src/SUITApp/SUITApp_init_python.cxx @@ -22,10 +22,6 @@ // #include "SUITApp_init_python.hxx" - -PyThreadState* SUIT_PYTHON::_gtstate = NULL; -PyObject *SUIT_PYTHON::salome_shared_modules_module = NULL; -PyInterpreterState* SUIT_PYTHON::_interp = NULL; bool SUIT_PYTHON::initialized = false; void SUIT_PYTHON::init_python(int argc, char **argv) @@ -37,9 +33,6 @@ void SUIT_PYTHON::init_python(int argc, char **argv) Py_SetProgramName(argv[0]); Py_Initialize(); // Initialize the interpreter PySys_SetArgv(argc, argv); - SUIT_PYTHON::_interp = PyThreadState_Get()->interp; - PyEval_InitThreads(); // Create (and acquire) the interpreter lock - SUIT_PYTHON::_gtstate = PyEval_SaveThread(); // Release global thread state - SUIT_PYTHON::initialized = true; + PyEval_InitThreads(); // Create (and acquire) the interpreter lock - can be called many times } diff --git a/src/SUITApp/SUITApp_init_python.hxx b/src/SUITApp/SUITApp_init_python.hxx index dcd23d285..62a9a3e7b 100644 --- a/src/SUITApp/SUITApp_init_python.hxx +++ b/src/SUITApp/SUITApp_init_python.hxx @@ -48,12 +48,8 @@ struct SUITAPP_EXPORT SUIT_PYTHON { - static PyThreadState *_gtstate; - static PyInterpreterState *_interp; - static PyObject *salome_shared_modules_module; static bool initialized; static void init_python(int argc, char **argv); - }; #endif // _SUITAPP_INIT_PYTHON_ diff --git a/src/SalomeApp/SalomeApp_Application.cxx b/src/SalomeApp/SalomeApp_Application.cxx index c7b16a8ae..25a7465da 100644 --- a/src/SalomeApp/SalomeApp_Application.cxx +++ b/src/SalomeApp/SalomeApp_Application.cxx @@ -369,12 +369,13 @@ void SalomeApp_Application::createActions() createExtraActions(); // import Python module that manages SALOME plugins - PyGILState_STATE gstate = PyGILState_Ensure(); - PyObjWrapper pluginsmanager = PyImport_ImportModule((char*)"salome_pluginsmanager"); - PyObjWrapper res = PyObject_CallMethod( pluginsmanager, (char*)"initialize", (char*)"isss",0,"salome",tr("MEN_DESK_PLUGINS_TOOLS").toStdString().c_str(),tr("MEN_DESK_PLUGINS").toStdString().c_str()); - if ( !res ) - PyErr_Print(); - PyGILState_Release(gstate); + { + PyLockWrapper lck; // acquire GIL + PyObjWrapper pluginsmanager = PyImport_ImportModule((char*)"salome_pluginsmanager"); + PyObjWrapper res = PyObject_CallMethod( pluginsmanager, (char*)"initialize", (char*)"isss",0,"salome",tr("MEN_DESK_PLUGINS_TOOLS").toStdString().c_str(),tr("MEN_DESK_PLUGINS").toStdString().c_str()); + if ( !res ) + PyErr_Print(); + } // end of SALOME plugins loading } diff --git a/src/SalomeApp/SalomeApp_DoubleSpinBox.cxx b/src/SalomeApp/SalomeApp_DoubleSpinBox.cxx index e3bf34f43..d3101ee29 100644 --- a/src/SalomeApp/SalomeApp_DoubleSpinBox.cxx +++ b/src/SalomeApp/SalomeApp_DoubleSpinBox.cxx @@ -436,7 +436,7 @@ SalomeApp_DoubleSpinBox::SearchState SalomeApp_DoubleSpinBox::findVariable( cons { PyConsole_Console* pyConsole = app->pythonConsole(); PyConsole_Interp* pyInterp = pyConsole->getInterp(); - PyLockWrapper aLock = pyInterp->GetLockWrapper(); + PyLockWrapper aLock; // Acquire GIL std::string command; command = "import salome_notebook ; "; command += "salome_notebook.notebook.setAsReal(\""; diff --git a/src/SalomeApp/SalomeApp_IntSpinBox.cxx b/src/SalomeApp/SalomeApp_IntSpinBox.cxx index 2771f44c5..cf0bd0c93 100644 --- a/src/SalomeApp/SalomeApp_IntSpinBox.cxx +++ b/src/SalomeApp/SalomeApp_IntSpinBox.cxx @@ -384,7 +384,7 @@ SalomeApp_IntSpinBox::SearchState SalomeApp_IntSpinBox::findVariable( const QStr { PyConsole_Console* pyConsole = app->pythonConsole(); PyConsole_Interp* pyInterp = pyConsole->getInterp(); - PyLockWrapper aLock = pyInterp->GetLockWrapper(); + PyLockWrapper aLock; // Acquire GIL std::string command; command = "import salome_notebook ; "; command += "salome_notebook.notebook.setAsInteger(\""; diff --git a/src/SalomeApp/SalomeApp_NoteBook.cxx b/src/SalomeApp/SalomeApp_NoteBook.cxx index 90a434582..accca5594 100644 --- a/src/SalomeApp/SalomeApp_NoteBook.cxx +++ b/src/SalomeApp/SalomeApp_NoteBook.cxx @@ -286,7 +286,7 @@ bool NoteBook_TableRow::IsValidStringValue(const QString theValue) SalomeApp_Application* app = dynamic_cast( SUIT_Session::session()->activeApplication() ); PyConsole_Console* pyConsole = app->pythonConsole(); PyConsole_Interp* pyInterp = pyConsole->getInterp(); - PyLockWrapper aLock = pyInterp->GetLockWrapper(); + PyLockWrapper aLock; // Acquire GIL std::string command = "import salome_notebook ; "; command += "salome_notebook.checkThisNoteBook("; for( int i = 0, n = aLastRowIsEmpty ? aNumRows - 1 : aNumRows; i < n; i++ ) { @@ -460,7 +460,7 @@ bool NoteBook_Table::IsValid() const SalomeApp_Application* app = dynamic_cast( SUIT_Session::session()->activeApplication() ); PyConsole_Console* pyConsole = app->pythonConsole(); PyConsole_Interp* pyInterp = pyConsole->getInterp(); - PyLockWrapper aLock = pyInterp->GetLockWrapper(); + PyLockWrapper aLock; // Acquire GIL std::string command = "import salome_notebook ; "; command += "salome_notebook.checkThisNoteBook("; for( int i = 0, n = aLastRowIsEmpty ? aNumRows - 1 : aNumRows; i < n; i++ ) diff --git a/src/SalomeApp/SalomeApp_PyInterp.cxx b/src/SalomeApp/SalomeApp_PyInterp.cxx index a0301b6ca..c2e329cc5 100755 --- a/src/SalomeApp/SalomeApp_PyInterp.cxx +++ b/src/SalomeApp/SalomeApp_PyInterp.cxx @@ -48,70 +48,14 @@ SalomeApp_PyInterp::~SalomeApp_PyInterp() { } -/*!\class SalomeApp_PyInterp - * EDF-CCAR - * When SALOME uses multi Python interpreter feature, - * Every study has its own interpreter and thread state (_tstate = Py_NewInterpreter()) - * This is fine because every study has its own modules (sys.modules) stdout and stderr - * BUT some Python modules must be imported only once. In multi interpreter context Python - * modules (*.py) are imported several times. - * The pyqt module must be imported only once because it registers classes in a C module. - * It's quite the same with omniorb modules (internals and generated with omniidl) - * This problem is handled with "shared modules" defined in salome_shared_modules.py - * These "shared modules" are imported only once and only copied in all the other interpreters - * BUT it's not the only problem. Every interpreter has its own __builtin__ module. That's fine - * but if we have copied some modules and imported others problems may arise with operations that - * are not allowed in restricted execution environment. So we must impose that all interpreters - * have identical __builtin__ module. - * That's all, for the moment ... - */ - - -bool SalomeApp_PyInterp::initContext() -{ - /*! - * The GIL is assumed to be held - * It is the caller responsability caller to acquire the GIL - * It will still be held on initContext output - */ - if ( !PyConsole_Interp::initContext() ) - return false; - - // Import special module to change the import mechanism - PyObjWrapper m1( PyImport_ImportModule( "import_hook" ) ); - if ( !m1 ) - { - MESSAGE( "initContext: problem with import_hook import" ); - PyErr_Print(); - ASSERT( 0 ); - return false; - } - - // Call init_shared_modules to initialize the shared import mechanism for modules - //that must not be imported twice - PyObjWrapper m2( PyObject_CallMethod( m1, (char*)"init_shared_modules", (char*)"O", KERNEL_PYTHON::salome_shared_modules_module ) ); - if ( !m2 ) - { - MESSAGE( "initContext: problem with init_shared_modules call" ); - PyErr_Print(); - ASSERT( 0 ); - return false; - } - - return true; -} - /*! - Do nothing - The initialization has been done in main + Do nothing (we could rely on the test done in the implementation of this method in the super + class PyInterp_Interp, but in this context we are sure the initialization has been done in main() + of SALOME_Session_Server) */ void SalomeApp_PyInterp::initPython() { - MESSAGE("SalomeApp_PyInterp::initPython"); - ASSERT(KERNEL_PYTHON::_gtstate); // initialisation in main - SCRUTE(KERNEL_PYTHON::_gtstate); - _gtstate=KERNEL_PYTHON::_gtstate; - _interp=KERNEL_PYTHON::_interp; + MESSAGE("SalomeApp_PyInterp::initPython - does nothing"); } /*! diff --git a/src/SalomeApp/SalomeApp_PyInterp.h b/src/SalomeApp/SalomeApp_PyInterp.h index d457cf763..801121239 100755 --- a/src/SalomeApp/SalomeApp_PyInterp.h +++ b/src/SalomeApp/SalomeApp_PyInterp.h @@ -38,7 +38,6 @@ public: virtual void initPython(); protected: - virtual bool initContext(); virtual int beforeRun(); private: diff --git a/src/Session/SALOME_Session_Server.cxx b/src/Session/SALOME_Session_Server.cxx index 9fbb1542d..f6ddf9d05 100755 --- a/src/Session/SALOME_Session_Server.cxx +++ b/src/Session/SALOME_Session_Server.cxx @@ -234,32 +234,32 @@ protected: QString fname = QFileInfo( _fname ).fileName(); if( exp.exactMatch( fname ) ) { - QStringList vers = exp.cap( 1 ).split( ".", QString::SkipEmptyParts ); - int major=0, minor=0; - int release = 0, dev1 = 0, dev2 = 0; - if ( vers.count() > 0 ) major = vers[0].toInt(); - if ( vers.count() > 1 ) minor = vers[1].toInt(); - if ( vers.count() > 2 ) { - if ( vers_exp.indexIn( vers[2] ) != -1 ) { - release = vers_exp.cap( 1 ).toInt(); - QString tag = vers_exp.cap( 2 ).toLower(); - if ( !tag.isEmpty() ) { - if ( tag == "rc" ) // release candidate - dev1 = 49; // 'rc'=49 - else // a, b, c, ... - dev1 = (int)( tag[ 0 ].toLatin1() ) - (int)( QChar('a').toLatin1() ) + 1; // 'a'=1, 'b'=2, ..., 'z'=26 - } - if ( !vers_exp.cap( 3 ).isEmpty() ) - dev2 = vers_exp.cap( 3 ).toInt(); - } - } - - int dev = dev1*100+dev2; - id = major; - id*=100; id+=minor; - id*=100; id+=release; - id*=10000; - if ( dev > 0 ) id-=dev; + QStringList vers = exp.cap( 1 ).split( ".", QString::SkipEmptyParts ); + int major=0, minor=0; + int release = 0, dev1 = 0, dev2 = 0; + if ( vers.count() > 0 ) major = vers[0].toInt(); + if ( vers.count() > 1 ) minor = vers[1].toInt(); + if ( vers.count() > 2 ) { + if ( vers_exp.indexIn( vers[2] ) != -1 ) { + release = vers_exp.cap( 1 ).toInt(); + QString tag = vers_exp.cap( 2 ).toLower(); + if ( !tag.isEmpty() ) { + if ( tag == "rc" ) // release candidate + dev1 = 49; // 'rc'=49 + else // a, b, c, ... + dev1 = (int)( tag[ 0 ].toLatin1() ) - (int)( QChar('a').toLatin1() ) + 1; // 'a'=1, 'b'=2, ..., 'z'=26 + } + if ( !vers_exp.cap( 3 ).isEmpty() ) + dev2 = vers_exp.cap( 3 ).toInt(); + } + } + + int dev = dev1*100+dev2; + id = major; + id*=100; id+=minor; + id*=100; id+=release; + id*=10000; + if ( dev > 0 ) id-=dev; } } return id; @@ -475,14 +475,6 @@ int main( int argc, char **argv ) int _argc = 1; char* _argv[] = {(char*)""}; KERNEL_PYTHON::init_python( _argc,_argv ); - PyEval_RestoreThread( KERNEL_PYTHON::_gtstate ); - if ( !KERNEL_PYTHON::salome_shared_modules_module ) // import only once - KERNEL_PYTHON::salome_shared_modules_module = PyImport_ImportModule( "salome_shared_modules" ); - if ( !KERNEL_PYTHON::salome_shared_modules_module ) { - INFOS( "salome_shared_modules_module == NULL" ); - PyErr_Print(); - } - PyEval_ReleaseThread( KERNEL_PYTHON::_gtstate ); // ...create ORB, get RootPOA object, NamingService, etc. ORB_INIT &init = *SINGLETON_::Instance(); @@ -631,28 +623,28 @@ int main( int argc, char **argv ) if ( splash ) splash->finish( aGUIApp->desktop() ); - + result = _qappl.exec(); splash = 0; - + if ( result == SUIT_Session::NORMAL ) { - // desktop is explicitly closed by user from GUI - // exit flags says if it's necessary to shutdown all servers - // all session server only + // desktop is explicitly closed by user from GUI + // exit flags says if it's necessary to shutdown all servers + // all session server only shutdownAll = aGUISession->exitFlags(); - } - else { - // desktop might be closed from: - // - StopSesion() /temporarily/ or - // - Shutdown() /permanently/ - stat = session->GetStatSession(); - shutdownSession = stat.state == SALOME::shutdown; - } - if ( shutdownAll || shutdownSession ) { - _SessionMutex.lock(); // lock mutex before leaving loop - it will be unlocked later - break; - } + } + else { + // desktop might be closed from: + // - StopSesion() /temporarily/ or + // - Shutdown() /permanently/ + stat = session->GetStatSession(); + shutdownSession = stat.state == SALOME::shutdown; + } + if ( shutdownAll || shutdownSession ) { + _SessionMutex.lock(); // lock mutex before leaving loop - it will be unlocked later + break; + } } delete aGUISession; -- 2.39.2