[Pyrex] Conditional compilation
David M. Cooke
cookedm at physics.mcmaster.ca
Thu Apr 7 09:53:24 CEST 2005
khinsen at cea.fr writes:
> On 05.04.2005, at 22:21, David M. Cooke wrote:
>
>> If you're using Py_BEGIN_ALLOW_THREADS/Py_END_ALLOW_THREADS, then the
>> stuff between them should be pure C code: how about making that a
>> function and throwing that into a header file, and including it?
>>
> That's what I have been doing (with macros rather than functions), but
> it's a bit of a pain with a dozen or so cases in a single module, and
> it doesn't do any good to readability.
I think for this particular case it would be better to add
functionality to Pyrex. The problem is you need to *guarantee* that
you're not jumping out of the *_ALLOW_THREADS block, and that you're
not using any of the Python API inside it.
But I came up with another solution. In a header file,
#define begin_allow_threads() Py_BEGIN_ALLOW_THREADS
#define end_allow_threads() Py_END_ALLOW_THREADS
Your Pyrex file:
cdef extern from "someheader.h":
void begin_allow_threads()
void end_allow_threads()
def some_function():
cdef int result, a, b
a = b = 1
begin_allow_threads()
result = a + b
end_allow_threads()
The relevant portions of the generated code for me looks like
static PyObject *__pyx_f_1x_some_function(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds); /*proto*/
static PyObject *__pyx_f_1x_some_function(PyObject *__pyx_self, PyObject *__pyx_args, PyObject *__pyx_kwds) {
int __pyx_v_result;
int __pyx_v_a;
int __pyx_v_b;
PyObject *__pyx_r;
static char *__pyx_argnames[] = {0};
if (!PyArg_ParseTupleAndKeywords(__pyx_args, __pyx_kwds, "", __pyx_argnames)) return 0;
/* "/home/cookedm/temp/x.pyx":11 */
__pyx_v_a = 1;
__pyx_v_b = 1;
/* "/home/cookedm/temp/x.pyx":12 */
begin_allow_threads();
/* "/home/cookedm/temp/x.pyx":13 */
__pyx_v_result = (__pyx_v_a + __pyx_v_b);
/* "/home/cookedm/temp/x.pyx":14 */
end_allow_threads();
__pyx_r = Py_None; Py_INCREF(__pyx_r);
goto __pyx_L0;
__pyx_L1:;
__Pyx_AddTraceback("x.some_function");
__pyx_r = 0;
__pyx_L0:;
return __pyx_r;
}
As required, no Python calls occur between the begin_allow_threads /
end_allow_threads calls (which should just expand to
Py_*_ALLOW_THREADS). As long as you're careful not to use C API calls
in between, you're ok. You could even write a script to scan the
generated result for the pattern Py.* in between *_allow_threads()
pairs to warn you :-)
Works with 0.9.3; whether you'll trust it to work for future versions
is something you'll have to decide ;-)
--
|>|\/|<
/--------------------------------------------------------------------------\
|David M. Cooke http://arbutus.physics.mcmaster.ca/dmc/
|cookedm at physics.mcmaster.ca
More information about the Pyrex
mailing list