chickadee » foreign » embedding

Outdated CHICKEN release

This is a manual page for an old and unsupported version of CHICKEN. If you are still using it, please consider migrating to the latest version. You can find the manual for the latest release here.

Embedding

Compiled Scheme files can be linked with C code, provided the Scheme code was compiled in embedded mode by passing -DC_EMBEDDED to the C compiler (this will disable generation of a main() function). csc will do this, when given the -embedded option.

The following C API is available:

CHICKEN_parse_command_line

[C function] void CHICKEN_parse_command_line (int argc, char *argv[], int *heap, int *stack int *symbols)

Parse the programs command-line contained in argc and argv and return the heap-, stack- and symbol table limits given by runtime options of the form -:..., or choose default limits. The library procedure argv can access the command-line only if this function has been called by the containing application.

CHICKEN_initialize

[C function] int CHICKEN_initialize (int heap, int stack, int symbols, void *toplevel) 

Initializes the Scheme execution context and memory. heap holds the number of bytes that are to be allocated for the secondary heap. stack holds the number of bytes for the primary heap. symbols contains the size of the symbol table. Passing 0 to one or more of these parameters will select a default size. toplevel should be a pointer to the toplevel entry point procedure. You should pass C_toplevel here. In any subsequent call to CHICKEN_run you can simply pass NULL. Calling this function more than once has no effect. If enough memory is available and initialization was successful, then 1 is returned, otherwise this function returns 0.

It is essential to run CHICKEN_initialize and subsequent calls to CHICKEN_run in the same native thread. The former computes a stack limit address which will not be valid if the runtime system is re-entered in a execution context where the stack is located at a different address.

CHICKEN_run

[C function] C_word CHICKEN_run (void *toplevel)

Starts the Scheme program. Call this function once to execute all toplevel expressions in your compiled Scheme program. If the runtime system was not initialized before, then CHICKEN_initialize is called with default sizes. toplevel is the toplevel entry-point procedure, you usually pass C_toplevel here. The result value is the continuation that can be used to re-invoke the Scheme code from the point after it called return-to-host (see below).

If you just need a Scheme interpreter, you can also pass CHICKEN_default_toplevel as the toplevel procedure, which just uses the default library units.

Once CHICKEN_run has been called, Scheme code is executing until all toplevel expressions have been evaluated or until return-to-host is called inside the Scheme program.

return-to-host

return-to-hostprocedure

Exits the Scheme code and returns to the invoking context that called CHICKEN_run or CHICKEN_continue.

After return-to-host has been executed and once CHICKEN_run returns, you can invoke callbacks which have been defined with define-external.

The eval library unit also provides boilerplate callbacks, that simplify invoking Scheme code embedded in a C or C++ application:

CHICKEN_eval

[C macro] int CHICKEN_eval (C_word exp, C_word *result)

Evaluates the Scheme object passed in exp, writing the result value to result. The return value is 1 if the operation succeeded, or 0 if an error occurred. Call CHICKEN_get_error_message to obtain a description of the error.

CHICKEN_eval_string

[C macro] int CHICKEN_eval_string (char *str, C_word *result)

Evaluates the Scheme expression passed in the string str, writing the result value to result.

CHICKEN_eval_to_string

[C macro] int CHICKEN_eval_to_string (C_word exp, char *result, int size)

Evaluates the Scheme expression passed in exp, writing a textual representation of the result into result. size should specify the maximal size of the result string.

CHICKEN_eval_string_to_string

[C macro] int CHICKEN_eval_string_to_string (char *str, char *result, int size)

Evaluates the Scheme expression passed in the string str, writing a textual representation of the result into result. size should specify the maximal size of the result string.

CHICKEN_apply

[C macro] int CHICKEN_apply (C_word func, C_word args, C_word *result)

Applies the procedure passed in func to the list of arguments args, writing the result value to result.

CHICKEN_apply_to_string

[C macro] int CHICKEN_apply_to_string (C_word func, C_word args, char *result, int size)

Applies the procedure passed in func to the list of arguments args, writing a textual representation of the result into result.

CHICKEN_read

[C macro] int CHICKEN_read (char *str, C_word *result)

Reads a Scheme object from the string str, writing the result value to result.

CHICKEN_load

[C macro] int CHICKEN_load (char *filename)

Loads the Scheme file filename (either in source form or compiled).

CHICKEN_get_error_message

[C macro] void CHICKEN_get_error_message (char *result, int size)

Returns a textual description of the most recent error that occurred in executing embedded Scheme code.

CHICKEN_yield

[C macro] int CHICKEN_yield (int *status)

If threads have been spawned during earlier invocations of embedded Scheme code, then this function will run the next scheduled thread for one complete time-slice. This is useful, for example, inside an idle handler in a GUI application with background Scheme threads. Note that the srfi-18 library unit has to be linked in for this.

An example:

% cat x.scm
;;; x.scm

(define (bar x) (gc) (* x x))

(define-external (baz (int i)) double
  (sqrt i))
(return-to-host)
% cat y.c
/* y.c */

#include <chicken.h>
#include <assert.h>

extern double baz(int);

int main() {
  char buffer[ 256 ];
  int status;
  C_word val = C_SCHEME_UNDEFINED;
  C_word *data[ 1 ];

  data[ 0 ] = &val;

  CHICKEN_run(C_toplevel);

  status = CHICKEN_read("(bar 99)", &val);
  assert(status);

  C_gc_protect(data, 1);

  printf("data: %08x\n", (unsigned int) val);

  status = CHICKEN_eval_string_to_string("(bar)", buffer, 255);
  assert(!status);

  CHICKEN_get_error_message(buffer, 255);
  printf("ouch: %s\n", buffer);

  status = CHICKEN_eval_string_to_string("(bar 23)", buffer, 255);
  assert(status);

  printf("-> %s\n", buffer);
  printf("data: %08x\n", (unsigned int) val);

  status = CHICKEN_eval_to_string(val, buffer, 255);
  assert(status);
  printf("-> %s\n", buffer);

  printf("->` %g\n", baz(22));

  return 0;
}

% csc x.scm y.c -embedded

It is also possible to re-enter the computation following the call to return-to-host by calling CHICKEN_continue:

CHICKEN_continue

[C function] C_word CHICKEN_continue (C_word k)

Re-enters Scheme execution. k is the continuation received from the previous invocation of CHICKEN_run or CHICKEN_continue. When return-to-host is called again, this function returns another continuation that can be used to restart again.

If you invoke callbacks prior to calling CHICKEN_continue, make sure that the continuation is not reclaimed by garbage collection. This can be avoided by using C_gc_protect or gc-roots.

Another example:

% cat x.scm
(require-extension srfi-18)

(define m (make-mutex))

(define (t)
  (mutex-lock! m)
  (thread-sleep! 1)
  (print (thread-name (current-thread)))
  (mutex-unlock! m)
  (t) )

(thread-start! (make-thread t 'PING!))
(thread-start! (make-thread t 'PONG!))

(let loop ()
  (return-to-host)
  (thread-yield!)
  (loop) )

% cat y.c
#include <chicken.h>

int main()
{
  C_word k = CHICKEN_run(C_toplevel);

  for(;;)
    k = CHICKEN_continue(k);

  return 0;
}

% csc x.scm y.c -embedded

It is advisable not to mix repeated uses of CHICKEN_continue/return-to-host (as in the example above) with callbacks. Once return-to-host is invoked, the runtime system and any Scheme code executed prior to the invocation is initialized and can be conveniently used via callbacks.

A simpler interface For handling GC-safe references to Scheme data are the so called gc-roots:

CHICKEN_new_gc_root

[C function] void* CHICKEN_new_gc_root ()

Returns a pointer to a GC root, which is an object that holds a reference to a Scheme value that will always be valid, even after a garbage collection. The content of the gc root is initialized to an unspecified value.

CHICKEN_new_finalizable_gc_root

[C function] void* CHICKEN_new_finalizable_gc_root ()

Similar to CHICKEN_new_gc_root, but allows the stored value to be finalized: if this gc root holds reference to an otherwise unreferenced data object that has a finalizer, the finalizer is still invoked.

CHICKEN_delete_gc_root

[C function] void CHICKEN_delete_gc_root (void *root)

Deletes the gc root.

CHICKEN_gc_root_ref

[C macro] C_word CHICKEN_gc_root_ref (void *root)

Returns the value stored in the gc root.

CHICKEN_gc_root_set

[C macro] void CHICKEN_gc_root_set (void *root, C_word value)

Sets the content of the GC root to a new value.

Sometimes it is handy to access global variables from C code:

CHICKEN_global_lookup

[C function] void* CHICKEN_global_lookup (char *name)

Returns a GC root that holds the global variable with the name name. If no such variable exists, NULL is returned.

CHICKEN_global_ref

[C function] C_word CHICKEN_global_ref (void *global)

Returns the value of the global variable referenced by the GC root global.

CHICKEN_global_set

[C function] void CHICKEN_global_set (void *global, C_word value)

Sets the value of the global variable referenced by the GC root global to value.


Previous: Foreign type specifiers

Next: Callbacks

Contents »