#include <vector>
#include "PyInterp_base.h" // this include must be first (see PyInterp_base.h)!
+#include <pythread.h>
#include <cStringIO.h>
#include <structmember.h>
+#include <map>
-using namespace std;
+// a map to store python thread states that have been created for a given system thread (key=thread id,value=thread state)
+std::map<long,PyThreadState*> currentThreadMap;
PyLockWrapper::PyLockWrapper(PyThreadState* theThreadState):
myThreadState(theThreadState),
#endif
}
-class PyReleaseLock{
+class PyReleaseLock
+{
public:
~PyReleaseLock(){
PyEval_ReleaseLock();
};
-PyLockWrapper PyInterp_base::GetLockWrapper(){
- return _tstate;
+PyLockWrapper PyInterp_base::GetLockWrapper()
+{
+ if (_tstate->interp == PyInterp_base::_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;
}
static void
initState();
- PyLockWrapper aLock= GetLockWrapper();
+ PyEval_AcquireThread(_tstate);
initContext();
PyObjWrapper m(PyImport_ImportModule("codeop"));
if(!m){
PyErr_Print();
+ PyEval_ReleaseThread(_tstate);
return;
}
// All the initRun outputs are redirected to the standard output (console)
initRun();
+ PyEval_ReleaseThread(_tstate);
}
void PyInterp_base::init_python()
_gtstate = PyEval_SaveThread(); // Release global thread state
}
-string PyInterp_base::getbanner()
+std::string PyInterp_base::getbanner()
{
// Should we take the lock ?
// PyEval_RestoreThread(_tstate);
- string aBanner("Python ");
+ std::string aBanner("Python ");
aBanner = aBanner + Py_GetVersion() + " on " + Py_GetPlatform() ;
aBanner = aBanner + "\ntype help to get general information on environment\n";
//PyEval_SaveThread();
* 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 ...
+ *
+ * When calling initState the GIL is not held
+ * It must not be held on exit
+ *
*/
bool PythonConsole_PyInterp::initState()
{
- /*
- * The GIL is acquired on input and released on output
- */
- /*PyEval_AcquireLock();
-#ifdef WNT
- _tstate = PyGILState_GetThisThreadState();
- // if no thread state defined
- if ( _tstate )
- PyThreadState_Swap(_tstate);
- else
-#endif
- {
- _tstate = Py_NewInterpreter(); // create an interpreter and save current state
- PySys_SetArgv(PyInterp_base::_argc,PyInterp_base::_argv); // initialize sys.argv
- //if(MYDEBUG) MESSAGE("PythonConsole_PyInterp::initState - this = "<<this<<"; _tstate = "<<_tstate);
- }*/
-
- /*
- * The GIL is acquired and will be held on initState output
- * It is the caller responsability to release the lock if needed
- */
PyEval_AcquireLock();
_tstate = Py_NewInterpreter(); // create an interpreter and save current state
/*!
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
+ It is the caller responsability to acquire the GIL.
+ It must still be held on initContext() exit.
*/
bool PythonConsole_PyInterp::initContext()
{