Callbacks (FFI 1.0)

Next: Compiling and Linking, Previous: Alien Functions, Up: FFI

## 5 Callbacks

A callback declaration must include a parameter named “ID”. The ID argument will be used to find the Scheme callback procedure. It must be the same “user data” value provided to the toolkit when the callback was registered. For example, a callback trampoline named `Scm_delete_event` might be declared like this:

    (callback gint
              delete_event
              (window (* GtkWidget))
              (event (* GdkEventAny))
              (ID gpointer))

The callback might be registered with the toolkit like this:

    (C-call "g_signal_connect" window "delete_event"
            (C-callback "delete_event")     ; e.g. &Scm_delete_event
            (C-callback                     ; e.g. 314
              (lambda (window event)
                (C-call "gtk_widget_destroy" window)
                0)))

The toolkit’s registration function, `g_signal_connect`, would be declared like this:

    (extern void
            g_signal_connect
            (object (* GtkObject))
            (name (* gchar))
            (CALLBACK GtkSignalFunc)
            (ID gpointer))

This function should have parameters named `CALLBACK` and `ID`. The callout trampoline will convert the callback argument from a Scheme alien function to an entry address. The `ID` argument will be converted to a C integer and then cast to its declared type (in this example, `gpointer`).

Note that the registered callback procedures are effectively pinned. They cannot be garbage collected. They are “on call” to handle callbacks from the toolkit until they are explicitly de-registered. A band restore automatically de-registers all callbacks.

Callback procedures are executed with thread preemption suspended. Thus Scheme will not switch to another thread, especially not one preempted in an earlier callback. Such a thread could finish its callback and return from the later callback, not to its original caller.

Scheme will not preempt a callback, but if the callback calls `suspend-thread` it will switch to a running thread. If the callback does IO (and blocks), suspends, yields, sleeps, or grabs (waits for) a mutex, the runtime system will switch to another thread, possibly a thread that blocked for IO during an earlier callback but is now recently unblocked and determined to finish and return to the wrong caller. Thus callback procedures should be written as if they were interrupt handlers. They should be short and simple because they must not wait.

The `outf-error` procedure is provided for debugging purposes. It writes one or more argument strings (and `write`s any non-strings) to the Unix “stderr” channel, atomically, via a machine primitive, bypassing the runtime’s IO buffering and thread switching. Thus trace messages from multiple threads will appear on stderr intact, uninterrupted.

Next: Compiling and Linking, Previous: Alien Functions, Up: FFI