From: Eric B. <er...@go...> - 2007-11-16 14:44:42
|
I tend to agree with Manu. First, when calling Eiffel from C, I think that we should make the difference between a C program which calls some Eiffel code, and an Eiffel program which calls some C code which then calls some Eiffel code. I think that the CECIL mechanism has been designed for the first case. In the second case, Manu's example works fine without using CECIL. I think that there is a typo though in Manu's example: > c_set_address (your_eiffel_routine_callback) should probably be: c_set_address ($your_eiffel_routine_callback) Anyway, I prefer this technique better because the other one with `eif_type_id' and `eif_procedure' has the drawback that we don't get a compilation error when we rename the class or the feature. And if I remember correctly, this technique of passing $feature_name to the C side is what has already been used to implement Expat callbacks in the XML library. As for external features, you should note that gec also has a limitation when passing $feature_name to the C side. If the feature has non-expanded argument types then you may experience some weird behavior. But with expanded arguments, it seems to work. At least the example below works with gec under Windows: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ class FOO create make feature make is do c_set_address ($f) c_set_object ($Current) foo_c end c_set_address (p: POINTER) is external "C inline use <foo_c.h>" alias "signal_callback = $p;" end c_set_object (a: POINTER) is external "C inline use <foo_c.h>" alias "signal_object = eif_protect($a);" end f (i: INTEGER) is do print (i) end foo_c is external "C" end end ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ #include "ge_eiffel.h" #include "ge_gc.h" extern EIF_REFERENCE signal_object; extern void (*signal_callback)(EIF_REFERENCE, EIF_INTEGER_32); extern void foo_c(Void); ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ #include "foo_c.h" EIF_REFERENCE signal_object; void (*signal_callback)(EIF_REFERENCE, EIF_INTEGER_32); void foo_c() { (signal_callback) (eif_adopt(signal_object), 1); } ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -- Eric Bezault mailto:er...@go... http://www.gobosoft.com Emmanuel Stapf [ES] wrote: > The easiest way for doing this kind of callback is to store the eiffel > routine address by doing: > > c_set_address (p: POINTER) is > external > "C inline use <your.h>" > alias > "signal_callback = $p" > end > > where you do: > > c_set_address (your_eiffel_routine_callback) > > > To store the object needed for the call: > > c_set_object (a: POINTER) is > external > "C inline use <your.h>" > alias > "signal_object = eif_protect($a);" > end > > where you do: > > c_set_object ($Current) -- Current or any other entity > > Then the C code should simply look like: > > (signal_callback) (eif_adopt(signal_object), sig) > > That way there is no need to worry about freezing objects. > > Manu > >> -----Original Message----- >> From: gob...@li... >> [mailto:gob...@li...] On >> Behalf Of Berend de Boer >> Sent: Thursday, November 15, 2007 3:01 PM >> To: Gobo Developers Mailing List >> Subject: [gobo-eiffel-develop] Callback from C to Eiffel >> >> Hi Eric, >> >> Can I callback from C to Eiffel? Need this at a few places in >> eposix, for example to support signals. >> >> For example this the code used for ISE: >> >> EIF_TYPE_ID tid; >> EIF_OBJECT temp; >> if ( signal_switch != NULL ) { >> temp = signal_switch; >> signal_switch = NULL; >> eif_unfreeze (frozen_signal_switch); >> frozen_signal_switch = NULL; >> eif_wean (temp); >> } >> if ( a_switch != NULL ) { >> tid = eif_type_id ("STDC_SIGNAL_SWITCH"); >> signal_callback = eif_procedure ("switcher", tid); >> if (signal_callback == 0) >> { eif_panic ("switcher feature not found."); } >> frozen_signal_switch = eif_freeze (a_switch); >> signal_switch = eif_adopt (a_switch); >> } >> >> I.e. the callback pointer is "calculated" at set time and >> stored in signal_switch. When a signal occurs, this call is made: >> >> (signal_callback) (frozen_signal_switch, sig); >> >> >> SmartEiffel has a different strategy. When a feature is >> exported, SE simply generates a prototype for it in the cecil.h file: >> >> /* Available Eiffel routines via -cecil: >> */ >> void stdc_exit_switch_at_exit(void* C); >> void stdc_signal_switch_switcher(void* C,T2 a1); >> >> And within C I can simply call stdc_signal_switch_switcher to >> make the callback to Eiffel. >> >> -- >> Cheers, >> >> Berend de Boer >> |