Re: [pygccxml-development] Function adaptors
Brought to you by:
mbaas,
roman_yakovenko
|
From: Roman Y. <rom...@gm...> - 2009-08-11 18:39:28
|
2009/8/10 Berserker <ber...@ho...>:
>> Right now I have some free time, I suggest you to verify that the
>> committed code does what you want and report any problem with it.
>
> Hi again Roman :)
> I'm testing right now the svn version (updated to revision 1751) but
> I still have some problems in controlling the GIL (with virtual protected
> functions in particular).
> The "adaptors" implementations is working for me,
Good
> even if (because of my inexperience with Py++) I still don't understand why
> I can't
> define an adaptor in conjunction with a transformer (required to control the
> GIL in virtual functions),
The reason is ideological. A function transformation feature allows
user to do virtually anything.
If I will start to add to the feature something else, like adaptors,
it will introduce constraints and thus will break the initial idea.
> here it is the code I'm actually using:
>
> # This is code where I iterate over each exported "c" class
>> for f in c.member_functions(allow_empty=True):
>> f.adaptor = "allow_threads"
>> if f.virtuality:
>> f.add_transformation(allow_threading_transformer_creator())
>>
>
> # This code is still required since I need to "guard" the GIL
> # for virtual functions (default_controller in particular)
>> class allow_threading_transformer_t(transformer.transformer_t):
>> def __init__(self, function):
>> transformer.transformer_t.__init__(self, function)
>>
>> def __configure_sealed(self, controller):
>> controller.add_pre_call_code("allow_threading_guard guard;")
>>
>> def configure_mem_fun(self, controller):
>> self.__configure_sealed(controller)
>>
>> def configure_free_fun(self, controller):
>> self.__configure_sealed(controller)
>>
>> def configure_virtual_mem_fun(self, controller):
>> self.__configure_sealed(controller.default_controller)
>>
>> def required_headers(self):
>> return []
>
> # This code customizes the base wrapper class allowing to save a
> # reference to "PyThreadState_Get" and to restore the correct
> # interpreter later when the Python code in directly invoked from C++
>> def override_create_identifier(creator, full_name ):
>> if full_name == "::boost::python::wrapper":
>> return "osiris::PythonWrapper"
>>
>> return full_name
>
> # This is the templates customization code (getPythonThreadState
> # is a method of PythonWrapper)
>> templates.virtual_mem_fun.override = Template( os.linesep.join([
>> 'virtual $return_type $function_name( $arg_declarations )$constness
>> $throw{'
>> , ' osiris::PythonState state(getPythonThreadState());'
>> , ' namespace bpl = boost::python;'
>> , ' if( bpl::override $py_function_var = this->get_override(
>> "$function_alias" ) ){'
>> , ' $declare_py_variables'
>> , ' $py_pre_call'
>> , ' ${save_py_result}bpl::call<bpl::object>(
>> $py_function_var.ptr()$py_arg_expressions );'
>> , ' $py_post_call'
>> , ' $py_return'
>> , ' }'
>> , ' else{'
>> , ' state.leave();' #Release the lock since from here no
>> CPython API will be called
>> , ' $cpp_return$wrapped_class::$function_name(
>> $cpp_arg_expressions );'
>> , ' }'
>> , '}'
>> ]))
This is only +- 20 lines of code :-)
> # Pure virtual functions is a little more "tricky" since we need to hold the
> GIL lock during
> # the exception propagation: osiris::throw_locked_error_already_set is a
> function just
> # throw a derived boost::python::error_already_set's class holding the GIL
> lock
>>templates.pure_virtual_mem_fun.override = Template( os.linesep.join([
>> 'virtual $return_type $function_name( $arg_declarations )$constness
>> $throw{'
>> , ' boost::shared_ptr<osiris::PythonState> state(new
>> osiris::PythonState(getPythonThreadState()));'
>> , ' namespace bpl = boost::python;'
>> , ' if( bpl::override $py_function_var = this->get_override(
>> "$function_alias" ) ){'
>> , ' $declare_py_variables'
>> , ' $py_pre_call'
>> , ' ${save_py_result}bpl::call<bpl::object>(
>> $py_function_var.ptr()$py_arg_expressions );'
>> , ' $py_post_call'
>> , ' $py_return'
>> , ' }'
>> , ' else{'
>> , ' PyErr_SetString(PyExc_NotImplementedError, "Attempted
>> calling Pure Virtual function that is not implemented :$function_name");'
>> , ' osiris::throw_locked_error_already_set(state);'
>> , ' }'
>> , '}'
>> ]))
And few more lines.
In my opinion the Py++ design works. May be I need to think how to
make templates "more" accessible.
> And now problems :)
> Is it possible to customize "virtual protected functions" and
Depends. It depends on how much of Py++ internals you want to know.
Function transformation feature can only work with public functions. (
hint: the "function wrapper" is free function without friendship )
What you can do is to to change
mem_fun_protected_v_wrapper_t::create_virtual_body method.
Take a look on it, I believe it will be easy to you to find out what
should be changed.
Of course you can do it without modifying Py++ code
class H:
def xyz( self ):
....
def xyz( self ): <your code>
H.xyz = xyz
The only catch is that you are going to deal with internals and I
don't promise to be backward compatible here.
> "pure virtual protected functions" as above to have control of the GIL?
Can you show the use case?
> It seems that those templates are ignored in case of
> protected methods or I'm maybe missing something...
Yes as I explained FT feature works only for public functions. You can
always to do
#define private public
and include all your code :-))))
> Thanks again for your help,
You are welcome.
--
Roman Yakovenko
C++ Python language binding
http://www.language-binding.net/
|