The following functions and macros are available for C code that invokes
Scheme:
-
- [C function] void C_save(C_word x)
-
Saves the Scheme data object x on the temporary stack.
- [C macro] C_word C_fix(int integer)
-
- [C macro] C_word C_make_character(int char_code)
-
- [C macro] C_word C_SCHEME_END_OF_LIST
-
- [C macro] C_word C_SCHEME_END_OF_FILE
-
- [C macro] C_word C_SCHEME_FALSE
-
- [C macro] C_word C_SCHEME_TRUE
-
These macros return immediate Scheme data objects.
- [C function] C_word C_string(C_word **ptr, int length, char *string)
-
- [C function] C_word C_string2(C_word **ptr, char *zero_terminated_string)
-
- [C function] C_word C_intern2(C_word **ptr, char *zero_terminated_string)
-
- [C function] C_word C_intern3(C_word **ptr, char *zero_terminated_string, C_word initial_value)
-
- [C function] C_word C_pair[C function
- (C_word **ptr, C_word car, C_word cdr)]
- [C function] C_word C_flonum(C_word **ptr, double number)
-
- [C function] C_word C_int_to_num(C_word **ptr, int integer)
-
- [C function] C_word C_mpointer(C_word **ptr, void *pointer)
-
- [C function] C_word C_vector(C_word **ptr, int length, ...)
-
- [C function] C_word C_list(C_word **ptr, int length, ...)
-
These functions allocate memory from ptr and initialize a fresh
data object. The new data object is returned. ptr should be the
address of an allocation pointer created with C_alloc or
C_alloc_in_heap.
- [C macro] C_word *C_alloc(int words)
-
- [C function] C_word *C_alloc_in_heap(int words)
-
Allocates memory from the C stack (C_alloc) or the second generation
heap (C_alloc_in_heap) and returns a pointer to
it. words should be the number of words needed for all data
objects that are to be created in this function. Note that stack-allocated
data objects have to be passed to the Scheme function, or they will
not be seen by the garbage collector. This is really only usable for
callback procedure invocations, make sure not to use it in normal code,
because the allocated memory will be re-used after the foreign procedure
returns. When invoking Scheme callback procedures a minor garbage
collection is performed, so data allocated with C_alloc
will already have moved to a safe place.
- [C macro] int C_SIZEOF_LIST(int length)
-
- [C macro] int C_SIZEOF_STRING(int length)
-
- [C macro] int C_SIZEOF_VECTOR(int length)
-
- [C macro] int C_SIZEOF_INTERNED_SYMBOL(int length)
-
- [C macro] int C_SIZEOF_PAIR
-
- [C macro] int C_SIZEOF_FLONUM
-
- [C macro] int C_SIZEOF_POINTER
-
- [C macro] int C_SIZEOF_LOCATIVE
-
- [C macro] int C_SIZEOF_TAGGED_POINTER
-
These are macros that return the size in words needed for a data object
of a given type.
- [C macro] int C_character_code(C_word character)
-
- [C macro] int C_unfix(C_word fixnum)
-
- [C macro] double C_flonum_magnitude(C_word flonum)
-
- [C function] char *C_c_string(C_word string)
-
- [C function] int C_num_to_int(C_word fixnum_or_flonum)
-
[C function void *C_pointer_address(C_word pointer)]
These macros and functions can be used to convert Scheme data objects
back to C data.
- [C macro] int C_header_size(C_word x)
-
- [C macro] int C_header_bits(C_word x)
-
Return the number of elements and the type-bits of the non-immediate
Scheme data object x.
- [C macro] C_word C_block_item(C_word x, int index)
-
This macro can be used to access slots of the non-immediate Scheme data
object x. index specifies the index of the slot to
be fetched, starting at 0. Pairs have 2 slots, one for the car
and one for the cdr. Vectors have one slot for each element.
- [C macro] void *C_data_pointer(C_word x)
-
Returns a pointer to the data-section of a non-immediate Scheme object.
- [C macro] C_word C_make_header(C_word bits, C_word size)
-
A macro to build a Scheme object header from its bits and size parts.
- [C function] C_word C_mutate(C_word *slot, C_word val)
-
Assign the Scheme value val to the location specified by
slot. If the value points to data inside the nursery (the first
heap-generation), then the garbage collector will remember to handle the
data appropriately. Assigning nursery-pointers directly will otherwise
result in lost data.
- [C macro] C_word C_symbol_value(C_word symbol)
-
Returns the global value of the variable with the name symbol.
- [C function] void C_gc_protect(C_word *ptrs[], int n)
-
Registers n variables at address ptrs to be garbage collection roots.
The locations should not contain pointers to data allocated in the nursery, only
immediate values or pointers to heap-data are valid. Any
assignment of potential nursery data into a root-array should be done
via C_mutate(). The variables have to be initialized to sensible values
before the next garbage collection starts (when in doubt, set all locations
in ptrs to C_SCHEME_UNDEFINED)
- [C function] void C_gc_unprotect(int n)
-
Removes the last n registered variables from the set of
root variables.
An example:
% cat foo.scm
#>
extern int callout(int, int, int);
<#
(define callout (foreign-callback-lambda int "callout" int int int))
(define-external (callin (scheme-object xyz)) int
(print "This is 'callin': " xyz)
123)
(print (callout 1 2 3))
% cat bar.c
#include <stdio.h>
#include "chicken.h"
extern int callout(int, int, int);
extern int callin(C_word x);
int callout(int x, int y, int z)
{
C_word *ptr = C_alloc(C_SIZEOF_LIST(3));
C_word lst;
printf("This is 'callout': %d, %d, %d\n", x, y, z);
lst = C_list(&ptr, 3, C_fix(x), C_fix(y), C_fix(z));
return callin(lst); /* Note: `callin' will have GC'd the data in `ptr' */
}
% chicken foo.scm -quiet
% gcc foo.c bar.c -o foo `chicken-config -cflags -libs`
% foo
This is 'callout': 1, 2, 3
This is 'callin': (1 2 3)
123
Notes:
-
Scheme procedures can call C functions, and C functions can call
Scheme procedures, but for every pending C stack frame, the available
size of the first heap generation (the ``nursery'') will be decreased,
because the C stack is identical to the nursery. On systems with a small
nursery this might result in thrashing, since the C code between the
invocation of C from Scheme and the actual calling back to Scheme might
build up several stack-frames or allocates large amounts of stack data.
To prevent this it is advisable to increase the default nursery size,
either when compiling the file (using the -nursery option)
or when running the executable (using the -:s runtime option).
-
Calls to Scheme/C may be nested arbitrarily, and Scheme
continuations can be invoked as usual, but keep in mind that C stack
frames will not be recovered, when a Scheme procedure call from C does
not return normally.
-
When multiple threads are running concurrently, and control switches
from one thread to another, then the continuation of the current thread
is captured and saved. Any pending C stack frame still active from a
callback will remain on the stack until the threads is re-activated
again. This means that in a multithreading situation, when C callbacks
are involved, the available nursery space can be smaller than expected.
So doing many nested Scheme->C->Scheme calls can reduce the available
memory up to the point of thrashing. It is advisable to have only a
single thread with pending C stack-frames at any given time.
-
Pointers to Scheme data objects should not be stored in local or
global variables while calling back to Scheme. Any Scheme object not
passed back to Scheme will be reclaimed or moved by the garbage collector.
-
Calls from C to Scheme are never tail-recursive.
-
Continuations captured via call-with-current-continuation
and passed to C code can be invoked like any other Scheme procedure.