R3 Callbacks
Updated 11-Apr-2024/21:32:38 - press F5
Preliminary discussion: This document is a start at defining a mechanism of C-to-REBOL callbacks.
Objective
We want a method for C code to be able to call a REBOL function.
Methods
Three separate methods may be possible:
- Calling via the Reb_Do_String() function
This function takes a string, loads it, and evaluates it, returning the result on the R-stack (which must then be exported properly to isolate the value space.) - Calling via an event signal
This is how devices communicate with the REBOL kernel. They provide strong isolation between the host and kernel. These are asynchronous events, so they may be delayed until the kernel is ready to accept them. Also, they require some level of care to avoid large queues of unserviced events. - Direct calls
Such a mechanism does not yet exist, but in theory it would allow a C function to call into the REBOL lib. It would need to be determined how the callback function is identified, how arguments are provided, and how the result is returned. In addition, both kinds of error handling must be considered (unwind and throw.) There could also be some GC implications.
Critical Issues
A few important issues must be considered:
Isolation | REBOL does not allow access to its internals values, because the format of those values may change between releases. For example, even the numeric indicator of datatypes is allowed to change from at any time as new datatypes are added. |
Allocation | All REBOL series (and hence, all REBOL values) are allocated by the kernel. External values must be imported and exported in the proper way. If a component of a value is externally allocated, it must be either imported or possibly marked to allow consistent GC operation (avoiding sweeping and free values that are not part of the R3 memory pools.) |
GC Protection | Garbage collection can run anytime that the kernel code called. This means that any callbacks and values that they use must be referenced via normal REBOL values, otherwise they will be freed. (Such references must be rooted from the system root context, not floating.) |
Signals | In R3, signals are interrupts within the evaluation process. For example, pressing CTRL-C is one type of signal. Such signals cause exception handling, and may throw back the state of evaluation to a prior catch point, or completely out of the evaluator. |
Stacking | The state of evaluation is held on both the C-stack and the R-stack. Callbacks themselves may have callbacks, and improperly written code may consume a large amount of stack space, and even overflow the stack. An example of this exists today in the form of wait looping (e.g. a GUI function calls wait, that then let's additional GUI functions evaluate, that then call wait again, etc.) |