[Cython] GIL handling C code
mark florisson
markflorisson88 at gmail.com
Tue Feb 28 22:08:34 CET 2012
On 28 February 2012 20:19, Stefan Behnel <stefan_ml at behnel.de> wrote:
> Stefan Behnel, 28.02.2012 20:58:
>> mark florisson, 28.02.2012 16:35:
>>> Basically, the cleanup code only needs a matching release because the
>>> corresponding acquire is in EnsureGILNode, which wraps the function
>>> body in case of a nogil function with a 'with gil' block. Any changes
>>> to the conditions in FuncDefNode will have to be reflected by the code
>>> that does that wrapping. Changing the refnanny macro for the cleanup
>>> code will not avail anything, as the GIL is already ensured.
>>
>> Regarding the "with gil" code, ISTM that the "finally" code in the with_gil
>> test is being duplicated. I noticed this when I moved the refnanny's GIL
>> state into a block local variable and that broke the C code. Basically, the
>> with-gil block had declared the variable in its own block, but was then
>> trying to access that variable in a second finally clause, further down and
>> outside of the with-gil block.
>
> Hmm, guess I got confused again...
>
> So, the code is this:
>
> """
> /*finally:*/ {
> int __pyx_why;
> __pyx_why = 0; goto __pyx_L8;
> __pyx_L7: __pyx_why = 4; goto __pyx_L8;
> __pyx_L8:;
> #ifdef WITH_THREAD
> PyGILState_Release(__pyx_gilstate_save);
> #endif
> switch (__pyx_why) {
> case 4: goto __pyx_L4;
> }
> }
> }
> }
> /*finally:*/ {
> int __pyx_why;
> __pyx_why = 0; goto __pyx_L5;
> __pyx_L4: __pyx_why = 4; goto __pyx_L5;
> __pyx_L5:;
> #ifdef WITH_THREAD
> __pyx_gilstate_save = PyGILState_Ensure();
> #endif
> switch (__pyx_why) {
> case 4: goto __pyx_L1_error;
> }
> }
>
> goto __pyx_L0;
> __pyx_L1_error:;
> __Pyx_XDECREF(__pyx_t_1);
> __Pyx_XDECREF(__pyx_t_2);
> __Pyx_WriteUnraisable("with_gil.void_nogil_ignore_exception",
> __pyx_clineno, __pyx_lineno, __pyx_filename);
> __pyx_L0:;
> #ifdef WITH_THREAD
> PyGILState_Release(__pyx_gilstate_save);
> #endif
> }
> """
>
> The first "finally" block is inside of the with-gil block, whereas the
> second is outside. In the second, the GIL is reacquired, and I guess that's
> for cleaning up temps in the error case, right? I see the problem that it
> can't be acquired after jumping to the exit labels (error/return) in the
> current code layout, but wouldn't it make sense to generate this code
> instead (starting at the second finally clause):
This code could certainly be optimized, I just never got around to
implementing it.
> """
> /*finally:*/ {
> int __pyx_why;
> __pyx_why = 0; goto __pyx_L5;
> __pyx_L4: __pyx_why = 4; goto __pyx_L5;
> __pyx_L5:;
> switch (__pyx_why) {
> case 4: goto __pyx_L1_error;
> }
> }
>
> goto __pyx_L0;
> __pyx_L1_error:;
> #ifdef WITH_THREAD
> __pyx_gilstate_save = PyGILState_Ensure();
> #endif
> __Pyx_XDECREF(__pyx_t_1);
> __Pyx_XDECREF(__pyx_t_2);
> __Pyx_WriteUnraisable("with_gil.void_nogil_ignore_exception",
> __pyx_clineno, __pyx_lineno, __pyx_filename);
> #ifdef WITH_THREAD
> PyGILState_Release(__pyx_gilstate_save);
> #endif
> return; /* <- error return here! */
> __pyx_L0:;
> }
> """
>
> Meaning: split the return code paths and let them independently acquire the
> GIL if needed? That would at least relieve the outer finally from having to
> care about the GIL and having to rely on "someone" to declare the GIL
> variable and eventually release it.
(Sorry, dinner). In this case, that would be valid. Normally though,
the exception case should fall through to the normal case, so I think
what you'd want is
...
goto L0;
L1:
PyGILState_Ensure();
/* error code */
__pyx_r = ...;
goto L2;
L0:
PyGILState_Ensure();
goto L2:
/* normal code */
return __pyx_r;
}
If the entire body is a 'with gil' block, it'd probably be easiest to
transform the nogil function into a 'with gil' function. If you want
to optimize for "paths going from with gil blocks directly into
function cleanup code" (i.e., no intermediate nogil try/finally or
nested with gil blocks), then you could use two more labels in the
code above that bypass the acquire.
> Or, alternatively, add an additional exit path to the finally block that
> jumps to a label that acquires the GIL before going on to the original
> label. Something along those lines...
>
> Stefan
> _______________________________________________
> cython-devel mailing list
> cython-devel at python.org
> http://mail.python.org/mailman/listinfo/cython-devel
More information about the cython-devel
mailing list