Next: 4.9 API
Up: 4. The libonyx library
Previous: 4.7.3 Signals
Contents
Index
When embedding libonyx in an application, it is usually desirable to
add some operators so that the interpreter can interact with the rest of the
application. The libonyx source code contains hundreds of operators
that can be used as examples when writing new operators. However, there are
some very important rules that operators must follow, some of which may not be
obvious when reading the code.
- Manually managed ( malloc()/ free()) memory should not be
allocated unless the code is very careful. If a function recurses into the
interpreter (this includes calls to functions such as
nxo_thread_nerror()), there is the very
real possibility that control will never return to the operator due to an
exception. Code must either catch all exceptions and clean up allocations, or
not recurse into the interpreter.
- Composite objects should never be allocated on the C stack. The garbage
collector has no knowledge of such objects, so if the only reference to an
object is on the C stack, the object may be collected, which will lead to
unpredictable program behavior. Instead of allocating objects on the C stack,
use tstack, available via
nxo_thread_tstack_get(), which is a
per-thread stack that the garbage collector scans.
- For an object to be safe from garbage collection, there must always be at
least one reference to it inside the interpreter. So, if C code obtains a
pointer to a composite object, then destroys the last known internal Onyx
reference (pops it off a stack, redefines it in a dict, replaces an element of
an array, etc.), the pointer is no longer safe to use. The libonyx
API is structured such that it is invalid to do such a thing, for this reason.
- tstack must be cleaned up before returning from a function. This
constraint is placed on the code in order to avoid leaking space on tstack. In
debug versions of libonyx, this is enforced by assertions. The one
exception to this rule has to do with xep exceptions,
in which case the catchers of the exceptions are responsible for cleaning up
tstack. Therefore, it is not necessary to catch exceptions merely to avoid
tstack leakage.
Since Onyx type checking is dynamic, it is the responsibility of the operators
to assure objects are the correct type before calling any of the type-specific
nxo_*() functions. Failure to do so will result in unpredictable
behavior and likely crashes.
Next: 4.9 API
Up: 4. The libonyx library
Previous: 4.7.3 Signals
Contents
Index
Jason Evans
2005-03-16