Commit 8eb50dd2 authored by Mathieu Westphal's avatar Mathieu Westphal

Applying GIL PYTHON patch

1. Defining a gilEnsurer class to use as RAII for gil
2. Ensuring critical calls to python, where they could be concurrency, only when a cmake option is defined
3. Correcting the access to python in vtkPythonInterpreter::Initialize
4. Forcing the use of gil in the Interactive Python Interepreter for auto completion http://www.vtk.org/Bug/view.php?id=15699
5. Forcing the use of gil for prependPythonPath : http://www.vtk.org/Bug/view.php?id=15698
parent 0f6411d1
......@@ -102,4 +102,70 @@ they are system headers. Do NOT add any #undef lines here. */
#undef toupper
#endif
// Use vtkPythonScopeGilEnsurer to protect some parts of python code.
// Some classes are already protected with it (mainly used in paraview):
// vtkPythonInteractiveInterpreter
// vtkPythonInterpreter
// vtkPythonCommand
// vtkSmartPyObject
//
// others aren't:
// PyVTKObject
// PyVTKSpecialObject
// PyVTKMethodDescriptor
// vtkPythonOverload
// vtkPythonUtil
// PyVTKMutableObject
// PyVTKNamespace
// PyVTKTemplate
// vtkPythonView ( paraview )
// pqPythonDebugLeaksView (paraview)
//
// others are not protected, but can be considered not
// in need of protection for different reasons
// eg, used only in wrapping, not used, standalone executable, 3rd party :
// vtkPythonAppInit
// vtkPythonArgs
// PyVTKExtras
// vtkMatplotlibMathTextUtilities
// vtkPythonAlgorithm
// vtkWebUtilities
// vtkMPI4PyCommunicator
// vtkClientServerInterpreterPython ( paraview )
// pqPythonEventSource (QtTesting)
// pqPythonEventSourceImage (QtTesting)
// Plugin code ( xdmf2, pvblot)
class vtkPythonScopeGilEnsurer
{
public:
vtkPythonScopeGilEnsurer(bool force = false)
{
#ifdef VTK_PYTHON_FULL_THREADSAFE
this->Force = force;
this->Force = true;
#else
this->Force = force;
#endif
if (this->Force)
{
this->State = PyGILState_Ensure();
}
}
~vtkPythonScopeGilEnsurer()
{
if (this->Force)
{
PyGILState_Release(this->State);
}
}
private:
PyGILState_STATE State;
bool Force;
vtkPythonScopeGilEnsurer(const vtkPythonScopeGilEnsurer&); // Not implemented.
void operator=(const vtkPythonScopeGilEnsurer&); // Not implemented.
};
#endif
......@@ -19,6 +19,7 @@
/* E.g. on BlueGene and Cray there is no multithreading */
#cmakedefine VTK_NO_PYTHON_THREADS
#cmakedefine VTK_PYTHON_FULL_THREADSAFE
/* Whether the real python debug library has been provided. */
#cmakedefine VTK_WINDOWS_PYTHON_DEBUGGABLE
......
......@@ -45,6 +45,7 @@ public:
void CleanupPythonObjects()
{
vtkPythonScopeGilEnsurer gilEnsurer(true);
Py_XDECREF(this->InteractiveConsoleLocals);
Py_XDECREF(this->InteractiveConsole);
this->InteractiveConsole = NULL;
......@@ -65,6 +66,7 @@ public:
vtkPythonInterpreter::Initialize();
vtkPythonScopeGilEnsurer gilEnsurer(true);
// set up the code.InteractiveConsole instance that we'll use.
const char* code = "import code\n"
"__vtkConsoleLocals={'__name__':'__vtkconsole__','__doc__':None}\n"
......@@ -181,6 +183,7 @@ bool vtkPythonInteractiveInterpreter::Push(const char* const code)
i++;
}
vtkPythonScopeGilEnsurer gilEnsurer(true);
bool ret_value = false;
// The const_cast can be removed for Python 3.4 or later.
PyObject *res = PyObject_CallMethod(console,
......@@ -205,6 +208,7 @@ int vtkPythonInteractiveInterpreter::RunStringWithConsoleLocals(const char* scri
this->Internals->GetInteractiveConsole(); //ensure the console is initialized
vtkPythonScopeGilEnsurer gilEnsurer(true);
PyObject* context = this->Internals->GetInteractiveConsoleLocalsPyObject();
// The const_cast can be removed for Python 3.3 or later.
PyObject* result = PyRun_String(const_cast<char*>(script),
......
......@@ -69,6 +69,7 @@ namespace
inline void vtkPrependPythonPath(const char* pathtoadd)
{
vtkPythonScopeGilEnsurer gilEnsurer(true);
PyObject* path = PySys_GetObject(const_cast<char*>("path"));
#if PY_VERSION_HEX >= 0x03000000
PyObject* newpath = PyUnicode_FromString(pathtoadd);
......@@ -124,7 +125,6 @@ void vtkPythonInterpreter::PrintSelf(ostream& os, vtkIndent indent)
//----------------------------------------------------------------------------
bool vtkPythonInterpreter::Initialize(int initsigs /*=0*/)
{
vtkPythonInterpreter::InitializedOnce = true;
if (Py_IsInitialized() == 0)
{
#if (VTK_PYTHON_MAJOR_VERSION > 2) ||\
......@@ -139,6 +139,24 @@ bool vtkPythonInterpreter::Initialize(int initsigs /*=0*/)
// Put default SIGINT handler back after Py_Initialize/Py_InitializeEx.
signal(SIGINT, SIG_DFL);
#endif
}
if (!vtkPythonInterpreter::InitializedOnce)
{
#ifndef VTK_NO_PYTHON_THREADS
int threadInit = PyEval_ThreadsInitialized();
PyEval_InitThreads(); // safe to call this multiple time
#endif
vtkPythonInterpreter::InitializedOnce = true;
#ifndef VTK_NO_PYTHON_THREADS
if(!threadInit)
{
PyEval_SaveThread(); // release GIL
}
#endif
// HACK: Calling PyRun_SimpleString for the first time for some reason results in
// a "\n" message being generated which is causing the error dialog to
// popup. So we flush that message out of the system before setting up the
......@@ -151,7 +169,9 @@ bool vtkPythonInterpreter::Initialize(int initsigs /*=0*/)
vtkPythonStdStreamCaptureHelper* wrapperErr =
NewPythonStdStreamCaptureHelper(true);
// Redirect Python's stdout and stderr and stdin
// Redirect Python's stdout and stderr and stdin - GIL protected operation
{
vtkPythonScopeGilEnsurer gilEnsurer;
PySys_SetObject(const_cast<char*>("stdout"),
reinterpret_cast<PyObject*>(wrapperOut));
PySys_SetObject(const_cast<char*>("stderr"),
......@@ -160,6 +180,7 @@ bool vtkPythonInterpreter::Initialize(int initsigs /*=0*/)
reinterpret_cast<PyObject*>(wrapperOut));
Py_DECREF(wrapperOut);
Py_DECREF(wrapperErr);
}
for (size_t cc=0; cc < PythonPaths.size(); cc++)
{
......@@ -301,6 +322,7 @@ int vtkPythonInterpreter::PyMain(int argc, char** argv)
return 1;
}
}
vtkPythonScopeGilEnsurer gilEnsurer;
int res = Py_Main(argc, argvWide);
PyMem_Free(argv0);
for (int i = 0; i < argc; i++)
......@@ -311,6 +333,8 @@ int vtkPythonInterpreter::PyMain(int argc, char** argv)
delete [] argvWide2;
return res;
#else
vtkPythonScopeGilEnsurer gilEnsurer;
return Py_Main(argc, argv);
#endif
}
......@@ -327,7 +351,12 @@ int vtkPythonInterpreter::RunSimpleString(const char* script)
buffer.erase(std::remove(buffer.begin(), buffer.end(), '\r'), buffer.end());
// The cast is necessary because PyRun_SimpleString() hasn't always been const-correct
int pyReturn = PyRun_SimpleString(const_cast<char*>(buffer.c_str()));
int pyReturn;
{
vtkPythonScopeGilEnsurer gilEnsurer;
pyReturn = PyRun_SimpleString(const_cast<char*>(buffer.c_str()));
}
vtkPythonInterpreter::ConsoleBuffering = false;
if (! vtkPythonInterpreter::StdErrBuffer.empty())
{
......
......@@ -30,6 +30,7 @@ vtkPythonCommand::~vtkPythonCommand()
vtkPythonUtil::UnRegisterPythonCommand(this);
if (this->obj && Py_IsInitialized())
{
vtkPythonScopeGilEnsurer gilEnsurer;
Py_DECREF(this->obj);
}
this->obj = NULL;
......@@ -37,6 +38,7 @@ vtkPythonCommand::~vtkPythonCommand()
void vtkPythonCommand::SetObject(PyObject *o)
{
vtkPythonScopeGilEnsurer gilEnsurer;
Py_INCREF(o);
this->obj = o;
}
......
......@@ -30,18 +30,28 @@ vtkSmartPyObject::vtkSmartPyObject(PyObject *obj) :
vtkSmartPyObject::vtkSmartPyObject(const vtkSmartPyObject &other) :
Object(other.Object)
{
vtkPythonScopeGilEnsurer gilEnsurer;
Py_XINCREF(this->Object);
}
//--------------------------------------------------------------------
vtkSmartPyObject::~vtkSmartPyObject()
{
Py_XDECREF(this->Object);
if (Py_IsInitialized())
{
vtkPythonScopeGilEnsurer gilEnsurer;
Py_XDECREF(this->Object);
}
else
{
Py_XDECREF(this->Object);
}
}
//--------------------------------------------------------------------
vtkSmartPyObject &vtkSmartPyObject::operator=(const vtkSmartPyObject &other)
{
vtkPythonScopeGilEnsurer gilEnsurer;
Py_XDECREF(this->Object);
this->Object = other.Object;
Py_XINCREF(this->Object);
......@@ -51,6 +61,7 @@ vtkSmartPyObject &vtkSmartPyObject::operator=(const vtkSmartPyObject &other)
//--------------------------------------------------------------------
vtkSmartPyObject &vtkSmartPyObject::operator=(PyObject *obj)
{
vtkPythonScopeGilEnsurer gilEnsurer;
Py_XDECREF(this->Object);
this->Object = obj;
Py_XINCREF(this->Object);
......@@ -60,6 +71,7 @@ vtkSmartPyObject &vtkSmartPyObject::operator=(PyObject *obj)
//--------------------------------------------------------------------
void vtkSmartPyObject::TakeReference(PyObject *obj)
{
vtkPythonScopeGilEnsurer gilEnsurer;
Py_XDECREF(this->Object);
this->Object = obj;
}
......@@ -99,6 +111,7 @@ PyObject *vtkSmartPyObject::GetPointer() const
//--------------------------------------------------------------------
PyObject *vtkSmartPyObject::GetAndIncreaseReferenceCount()
{
vtkPythonScopeGilEnsurer gilEnsurer;
Py_XINCREF(this->Object);
return this->Object;
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment