[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [Chicken-users] FFI: Safe referencing and allocation of Scheme objec
Re: [Chicken-users] FFI: Safe referencing and allocation of Scheme objects from C
Sun, 09 Nov 2003 22:41:21 +0100
Opera7.11/Linux M2 build 406
On Fri, 07 Nov 2003 14:22:41 +0000, Category 5 <address@hidden>
felix <address@hidden> writes:
Right. One way to address is is to use C_gc_protect() inside the body
/* Warning: untested! */
C_word *data[ 1 ];
data[ 0 ] = &c;
result = black_box(...);
I have just tried this and the result is strange. The callback function
is called twice from black_box successfully, but the third time it's
called the assertion fails (the pointer is no longer pointing to the
procedure object). The code matches your example exactly.
Hm. Strange, indeed. You have changed the type-declaration in
to `scheme-object' for the assed data ("c"), right?
(black_box is an I/O function that sits around and receives things and
repeatedly calls scheme_callback_func with them.)
The thing to do seems to be to build another closure object from C
that's safe from being GC-invalidated. A static declaration works:
static C_word p;
p = C_make_header(C_CLOSURE_TYPE, 1);
p = C_block_item(c, 0); /* c is the original closure */
return(black_box([...], scheme_callback_func, (unsigned char *)p));
Are you making sure c is only of size 1 (+ header) ?
Well, the Data Representation section of the manual says:
procedures: special vector object (type bits C_CLOSURE_TYPE). The
first slot contains a pointer to a compiled C function.
Well, that is really not clear enough. A procedure has 1 or more data
slots, containing the free variables of the closure (if any). You can
use C_header_size() to obtain the number of slots (excluding the header).
Does this not mean that a procedure object will always be of size 1 +
No, not necessarily (see above). If the passed procedure is a toplevel
function, it will probably be of size 1 (+ header), though (since it
doesn't have any free variables).
As an aside, can you explain a little about the relationship between the
C_alloc, C_alloc_in_heap, C_gc_protect and C_gc_unprotect routines?
From what I can make out, C_alloc and C_alloc_in_heap allocate memory
from the C stack/nursery and the GC'd heap, respectively. It seems that
it's only safe to C_alloc things that will be passed on immediately to a
Scheme procedure defined with define-external, because the callback
process magically registers the allocated objects properly with the GC.
Right, once the data is passed to Scheme, it takes care of keeping it alive
(unless nobody refers to it anymore) - that is, including all arguments.
On the other hand, C_alloc_in_heap is safer in some sense because the
memory is still valid after the foreign procedure returns - but how does
the GC know when to reclaim it?
When there are no more pointers (the current continuation, the global
symbol table and any data protected via C_gc_protect()) that refer to
I couldn't guess from the documentation that C_gc_protect could be used
as in your example above. Such examples are extremely helpful. (Even
though this one doesn't seem to be working quite right yet...)
I will try to make that clearer.
Thanks for all your help! Chicken is fantastic and working with it is
quite an adventure.
Thanks, you're welcome. I'll try my best to make a little bit less of
an adventure. ;-)