fix [#28114] Render Crash

existing check for driver to use GIL was not thread safe and could cause, details in the report.

This bug was caused by a check to avoid hanging, a fix for [#27683] that worked in 2.4x because the UI didn't use python to draw while rendering.

Apply a different fix for [#27683], when calling an operator, call PyEval_SaveThread(), then PyEval_RestoreThread() so the GIL can be aquired by threads started by the operator - in this case bake starting a thread that evaluates drivers.
This commit is contained in:
Campbell Barton
2011-08-04 01:56:36 +00:00
parent 79c87852d2
commit e5e6f91856
2 changed files with 30 additions and 8 deletions

View File

@@ -41,8 +41,6 @@
#include "bpy_driver.h"
#include "../generic/py_capi_utils.h"
/* for pydrivers (drivers using one-line Python expressions to express relationships between targets) */
PyObject *bpy_pydriver_Dict= NULL;
@@ -89,7 +87,7 @@ int bpy_pydriver_create_dict(void)
void BPY_driver_reset(void)
{
PyGILState_STATE gilstate;
int use_gil= !PYC_INTERPRETER_ACTIVE;
int use_gil= 1; /* !PYC_INTERPRETER_ACTIVE; */
if(use_gil)
gilstate= PyGILState_Ensure();
@@ -120,9 +118,14 @@ static void pydriver_error(ChannelDriver *driver)
/* This evals py driver expressions, 'expr' is a Python expression that
* should evaluate to a float number, which is returned.
*
* note: PyGILState_Ensure() isnt always called because python can call the
* bake operator which intern starts a thread which calls scene update which
* does a driver update. to avoid a deadlock check PYC_INTERPRETER_ACTIVE if PyGILState_Ensure() is needed.
* (old)note: PyGILState_Ensure() isnt always called because python can call
* the bake operator which intern starts a thread which calls scene update
* which does a driver update. to avoid a deadlock check PYC_INTERPRETER_ACTIVE
* if PyGILState_Ensure() is needed - see [#27683]
*
* (new)note: checking if python is running is not threadsafe [#28114]
* now release the GIL on python operator execution instead, using
* PyEval_SaveThread() / PyEval_RestoreThread() so we dont lock up blender.
*/
float BPY_driver_exec(ChannelDriver *driver)
{
@@ -149,7 +152,7 @@ float BPY_driver_exec(ChannelDriver *driver)
return 0.0f;
}
use_gil= !PYC_INTERPRETER_ACTIVE;
use_gil= 1; /* !PYC_INTERPRETER_ACTIVE; */
if(use_gil)
gilstate= PyGILState_Ensure();

View File

@@ -55,6 +55,10 @@
#include "BKE_report.h"
#include "BKE_context.h"
/* so operators called can spawn threads which aquire the GIL */
#define BPY_RELEASE_GIL
static PyObject *pyop_poll(PyObject *UNUSED(self), PyObject *args)
{
wmOperatorType *ot;
@@ -219,7 +223,22 @@ static PyObject *pyop_call(PyObject *UNUSED(self), PyObject *args)
reports= MEM_mallocN(sizeof(ReportList), "wmOperatorReportList");
BKE_reports_init(reports, RPT_STORE | RPT_OP_HOLD); /* own so these dont move into global reports */
operator_ret= WM_operator_call_py(C, ot, context, &ptr, reports);
#ifdef BPY_RELEASE_GIL
/* release GIL, since a thread could be started from an operator
* that updates a driver */
/* note: I havve not seen any examples of code that does this
* so it may not be officially supported but seems to work ok. */
{
PyThreadState *ts= PyEval_SaveThread();
#endif
operator_ret= WM_operator_call_py(C, ot, context, &ptr, reports);
#ifdef BPY_RELEASE_GIL
/* regain GIL */
PyEval_RestoreThread(ts);
}
#endif
error_val= BPy_reports_to_error(reports, PyExc_RuntimeError, FALSE);