Protecting objects
Having looked at code for interfacing Eiffel to C and creating callbacks from C to Eiffel, I frequently found that things were not done properly, resulting in potential memory corruption or crashes.
First, I like to point out the CECIL documentation which contains everything you need to know about interfacing C with Eiffel. It might be overwhelming so below is a simplified tutorial.
Typing
At the C level, Eiffel objects are known under 2 possible types:
EIF_REFERENCE : a direct reference to an Eiffel objectEIF_OBJECT : an indirect (or protected) reference to an Eiffel object
The reason for having 2 types lies in the garbage collector (GC) which moves objects around at runtime. As a consequence, a direct reference is not always valid, meaning that if you use an EIF_REFERENCE variable, then it might points to the previous location of the object. This is why we have EIF_OBJECT, those variable are automatically updated by the GC. To access the Eiffel objects, one has to use the
Callbacks
The corresponding C signature of an Eiffel routine is the same as the Eiffel routine except that there is an extra first argument for the target object of the call. In other words, the Eiffel code
The types used for the declaration of the C routine are simply the Eiffel types prefixed by `EIF_' for the basic types (INTEGER_XX, NATURAL_XX, POINTER, ....) and EIF_REFERENCE for all the other types. Therefore the following Eiffel routine:
Passing an Eiffel routine to a C external
Instead of using the CECIL API for getting the address of an Eiffel routine, I'm using an alternative which is much lighter and simpler to use in my opinion. This is the technique used in all the Eiffel Software libraries where a simple callback is needed.
Basically if you want to pass the function pointer of the Eiffel routine
Passing the object target of the call to C
Now, we need to store the Eiffel objects on the C side. As we have seen above, we need to provide the C side with a protected reference to the Eiffel object, otherwise the reference might not be valid after a GC cycle. So on the C side, we need another C variable
Calling the Eiffel routine from C
Then from the C code, calling the Eiffel routine is just:
When you eif_protect() something in C, is this considered a reachable reference to the GC? i.e. if the Eiffel side of code loses reachability to an object that was passed to C and eif_protect'ed, will it ever be collected?
It won't be collected until eif_wean() is called.