691 lines
36 KiB
HTML
691 lines
36 KiB
HTML
|
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
|
||
|
<HTML>
|
||
|
<!-- HTML file produced from file: external.tex --
|
||
|
-- using Hyperlatex v 2.3.1 (c) Otfried Cheong--
|
||
|
-- on Emacs 19.34.1, Tue Feb 23 18:21:44 1999 -->
|
||
|
<HEAD>
|
||
|
<TITLE>Mixing Scheme 48 and C</TITLE>
|
||
|
|
||
|
</HEAD><BODY>
|
||
|
|
||
|
|
||
|
<H1 ALIGN=CENTER>Using C code with Scheme 48</H1>
|
||
|
<H2 ALIGN=CENTER>Mike Sperber<BR><TT><FONT SIZE=-1>sperber@informatik.uni-tuebingen.de</FONT></TT><BR>Richard Kelsey<BR><TT><FONT SIZE=-1>kelsey@research.nj.nec.com</FONT></TT>
|
||
|
</H2>
|
||
|
<H3 ALIGN=CENTER>February 23, 1999</H3>
|
||
|
<H3 ALIGN=CENTER>Abstract</H3>
|
||
|
<BLOCKQUOTE>
|
||
|
This document describes an interface for calling C functions
|
||
|
from Scheme, calling Scheme functions from C, and allocating
|
||
|
storage in the Scheme heap.
|
||
|
These facilities are designed to link
|
||
|
existing C libraries into Scheme 48 in order to use them from Scheme.
|
||
|
To this end, Scheme 48 manages stub functions in C that
|
||
|
negotiate between the calling conventions of Scheme and C and the
|
||
|
memory allocation policies of both worlds.
|
||
|
No stub generator is available yet, but writing them is a straightforward task.
|
||
|
</BLOCKQUOTE>
|
||
|
<H1><A NAME="1">Available Facilities</A></H1>
|
||
|
|
||
|
<P>The following facilities are available for interfacing between
|
||
|
Scheme 48 and C:
|
||
|
<UL><LI>Scheme code can call C functions.
|
||
|
<LI>The external interface provides full introspection for all
|
||
|
Scheme objects. External code may inspect, modify, and allocate
|
||
|
Scheme objects arbitrarily.
|
||
|
<LI>External code may raise exceptions back to Scheme 48 to
|
||
|
signal errors.
|
||
|
<LI>External code may call back into Scheme. Scheme 48
|
||
|
correctly unrolls the process stack on non-local exits.
|
||
|
<LI>External modules may register bindings of names to values with a
|
||
|
central registry accessible from
|
||
|
Scheme. Conversely, Scheme code can register shared
|
||
|
bindings for access by C code.
|
||
|
</UL>
|
||
|
This document has three parts: the first describes how bindings are
|
||
|
moved from Scheme to C and vice versa, the second tells how to call
|
||
|
C functions from Scheme, and the third covers the C interface
|
||
|
to Scheme objects, including calling Scheme procedures, using the
|
||
|
Scheme heap, and so forth.
|
||
|
<H2><A NAME="2">Scheme structures</A></H2>
|
||
|
<P>The structure <CODE>external-calls</CODE> has
|
||
|
most of the Scheme functions described here.
|
||
|
The others are in
|
||
|
<CODE>dynamic-externals</CODE>, which has the functions for dynamic loading and
|
||
|
name lookup from
|
||
|
|
||
|
the section on <A HREF="#dynamic-externals">Dynamic Loading</A>,
|
||
|
and <CODE>shared-bindings</CODE>, which has the additional shared-binding functions
|
||
|
described in
|
||
|
|
||
|
the section on the <A HREF="#more-shared-bindings">complete shared-binding interface</A>.
|
||
|
<H2><A NAME="3">C naming conventions</A></H2>
|
||
|
<P>The names of all of Scheme 48's visible C bindings begin
|
||
|
with `<CODE>s48_</CODE>' (for procedures and variables) or
|
||
|
`<CODE>S48_</CODE>' (for macros).
|
||
|
Whenever a C name is derived from a Scheme identifier, we
|
||
|
replace `<CODE>-</CODE>' with `<CODE>_</CODE>' and convert letters to lowercase
|
||
|
for procedures and uppercase for macros.
|
||
|
A final `<CODE>?</CODE>' converted to `<CODE>_p</CODE>' (`<CODE>_P</CODE>' in C macro names).
|
||
|
A final `<CODE>!</CODE>' is dropped.
|
||
|
Thus the C macro for Scheme's <CODE>pair?</CODE> is <CODE>S48_PAIR_P</CODE> and
|
||
|
the one for <CODE>set-car!</CODE> is <CODE>S48_SET_CAR</CODE>.
|
||
|
Procedures and macros that do not check the types of their arguments
|
||
|
have `<CODE>unsafe</CODE>' in their names.
|
||
|
<P>All of the C functions and macros described have prototypes or definitions
|
||
|
in the file <CODE>c/scheme48.h</CODE>.
|
||
|
The C type for Scheme values is defined there to be <CODE>s48_value</CODE>.
|
||
|
<H1><A NAME="4">Shared bindings</A></H1>
|
||
|
|
||
|
<P>Shared bindings are the means by which named values are shared between Scheme
|
||
|
code and C code.
|
||
|
There are two separate tables of shared bindings, one for values defined in
|
||
|
Scheme and accessed from C and the other for values going the other way.
|
||
|
Shared bindings actually bind names to cells, to allow a name to be looked
|
||
|
up before it has been assigned.
|
||
|
This is necessary because C initialization code may be run before or after
|
||
|
the corresponding Scheme code, depending on whether the Scheme code is in
|
||
|
the resumed image or is run in the current session.
|
||
|
<H2><A NAME="5">Exporting Scheme values to C</A></H2>
|
||
|
<UL><LI><CODE>(define-exported-binding<I> name value</I>) -> <I>shared-binding</I></CODE>
|
||
|
</UL>
|
||
|
<UL><LI><CODE>s48_value s48_get_imported_binding(char *name)</CODE>
|
||
|
<LI><CODE>s48_value S48_SHARED_BINDING_REF(s48_value shared_binding)</CODE>
|
||
|
</UL>
|
||
|
<P><CODE>Define-exported-binding</CODE> makes <CODE><I>value</I></CODE> available to C code
|
||
|
under as <CODE><I>name</I></CODE> which must be a <CODE><I>string</I></CODE>, creating a new shared
|
||
|
binding if necessary.
|
||
|
The C function <CODE>s48_get_imported_binding</CODE> returns the shared binding
|
||
|
defined for <CODE>name</CODE>, again creating it if necessary.
|
||
|
The C macro <CODE>S48_SHARED_BINDING_REF</CODE> dereferences a shared binding,
|
||
|
returning its current value.
|
||
|
<H2><A NAME="6">Exporting C values to Scheme</A></H2>
|
||
|
<UL><LI><CODE>void s48_define_exported_binding(char *name, s48_value value)</CODE>
|
||
|
</UL>
|
||
|
<UL><LI><CODE>(lookup-imported-binding<I> string</I>) -> <I>shared-binding</I></CODE>
|
||
|
<LI><CODE>(shared-binding-ref<I> shared-binding</I>) -> <I>value</I></CODE>
|
||
|
</UL>
|
||
|
<P>These are used to define shared bindings from C and to access them
|
||
|
from Scheme.
|
||
|
Again, if a name is looked up before it has been defined, a new binding is
|
||
|
created for it.
|
||
|
<P>The common case of exporting a C function to Scheme can be done using
|
||
|
the macro <CODE>S48_EXPORT_FUNCTION(<EM>name</EM>)</CODE>.
|
||
|
This expands into
|
||
|
<P><CODE>s48_define_exported_binding("<CODE><I>name</I></CODE>", s48_enter_pointer(<CODE><I>name</I></CODE>))</CODE>
|
||
|
<P>which boxes the function into a Scheme byte vector and then
|
||
|
exports it.
|
||
|
Note that <CODE>s48_enter_pointer</CODE> allocates space in the Scheme heap
|
||
|
and might trigger a
|
||
|
<A HREF="#gc">garbage collection</A>.
|
||
|
<UL><LI><table border=0 cellspacing=0 cellpadding=0 width=80%>
|
||
|
<tr> <td><CODE>(import-definition <CODE><I>name</I></CODE>)</CODE></td> <td align=right>syntax</td></tr></table>
|
||
|
<LI><table border=0 cellspacing=0 cellpadding=0 width=80%>
|
||
|
<tr> <td><CODE>(import-definition <CODE><I>name c-name</I></CODE>)</CODE></td> <td align=right>syntax</td></tr></table>
|
||
|
</UL>
|
||
|
These macros simplify importing definitions from C to Scheme.
|
||
|
They expand into
|
||
|
<P><CODE>(define <CODE><I>name</I></CODE> (lookup-imported-binding <CODE><I>c-name</I></CODE>))</CODE>
|
||
|
<P>where <CODE><I>c-name</I></CODE> is as supplied for the second form.
|
||
|
For the first form <CODE><I>c-name</I></CODE> is derived from <CODE><I>name</I></CODE> by
|
||
|
replacing `<CODE>-</CODE>' with `<CODE>_</CODE>' and converting letters to lowercase.
|
||
|
For example, <CODE>(import-definition my-foo)</CODE> expands into
|
||
|
<P><CODE>(define my-foo (lookup-imported-binding "my_foo"))</CODE>
|
||
|
<H2><A NAME="more-shared-bindings">Complete shared binding interface</A></H2>
|
||
|
|
||
|
<P>There are a number of other Scheme functions related to shared bindings;
|
||
|
these are in the structure <CODE>shared-bindings</CODE>.
|
||
|
<UL><LI><CODE>(shared-binding?<I> x</I>) -> <I>boolean</I></CODE>
|
||
|
<LI><CODE>(shared-binding-name<I> shared-binding</I>) -> <I>string</I></CODE>
|
||
|
<LI><CODE>(shared-binding-is-import?<I> shared-binding</I>) -> <I>boolean</I></CODE>
|
||
|
<LI><CODE>(shared-binding-set!<I> shared-binding value</I>)</CODE>
|
||
|
<LI><CODE>(define-imported-binding<I> string value</I>)</CODE>
|
||
|
<LI><CODE>(lookup-exported-binding<I> string</I>)</CODE>
|
||
|
<LI><CODE>(undefine-imported-binding<I> string</I>)</CODE>
|
||
|
<LI><CODE>(undefine-exported-binding<I> string</I>)</CODE>
|
||
|
</UL>
|
||
|
<P><CODE>Shared-binding?</CODE> is the predicate for shared-bindings.
|
||
|
<CODE>Shared-binding-name</CODE> returns the name of a binding.
|
||
|
<CODE>Shared-binding-is-import?</CODE> is true if the binding was defined from C.
|
||
|
<CODE>Shared-binding-set!</CODE> changes the value of a binding.
|
||
|
<CODE>Define-imported-binding</CODE> and <CODE>lookup-exported-binding</CODE> are
|
||
|
Scheme versions of <CODE>s48_define_exported_binding</CODE>
|
||
|
and <CODE>s48_lookup_imported_binding</CODE>.
|
||
|
The two <CODE>undefine-</CODE> procedures remove bindings from the two tables.
|
||
|
They do nothing if the name is not found in the table.
|
||
|
<P>The following C macros correspond to the Scheme functions above.
|
||
|
<UL><LI><CODE>int S48_SHARED_BINDING_P(x)</CODE>
|
||
|
<LI><CODE>int S48_SHARED_BINDING_IS_IMPORT_P(s48_value s_b)</CODE>
|
||
|
<LI><CODE>s48_value S48_SHARED_BINDING_NAME(s48_value s_b)</CODE>
|
||
|
<LI><CODE>void S48_SHARED_BINDING_SET(s48_value s_b, s48_value value)</CODE>
|
||
|
</UL>
|
||
|
<H1><A NAME="8">Calling C Functions from Scheme</A></H1>
|
||
|
|
||
|
<P>There are three different ways to call C functions from Scheme, depending on
|
||
|
how the C function was obtained.
|
||
|
<UL><LI><CODE>(call-imported-binding<I> binding arg<I><sub>0</sub></I> ...</I>) -> <I>value</I></CODE>
|
||
|
<LI><CODE>(call-external<I> external arg<I><sub>0</sub></I> ...</I>) -> <I>value</I></CODE>
|
||
|
<LI><CODE>(call-external-value<I> value name arg<I><sub>0</sub></I> ...</I>) -> <I>value</I></CODE>
|
||
|
</UL>
|
||
|
Each of these applies its first argument, a C function, to the rest of
|
||
|
the arguments.
|
||
|
For <CODE>call-imported-binding</CODE> the function argument must be an
|
||
|
imported binding.
|
||
|
For <CODE>call-external</CODE> the function argument must be an external
|
||
|
bound in the current process
|
||
|
(see
|
||
|
|
||
|
the section on <A HREF="#dynamic-externals">Dynamic Loading</A>).
|
||
|
For <CODE>call-external-value</CODE> <CODE><I>value</I></CODE> must be a byte vector
|
||
|
whose contents is a pointer to a C function and <CODE><I>name</I></CODE> should be
|
||
|
a string naming the function.
|
||
|
The <CODE><I>name</I></CODE> argument is used only for printing error messages.
|
||
|
<P>For all of these, the C function is passed the <CODE><I>arg<I><sub>i</sub></I></I></CODE> values
|
||
|
and the value returned is that returned by C procedure.
|
||
|
Up to twelve arguments may be passed.
|
||
|
There is no method supplied for returning multiple values to
|
||
|
Scheme from C (or vice versa) (mainly because C does not have multiple return
|
||
|
values).
|
||
|
<P>Keyboard interrupts that occur during a call to a C function are ignored
|
||
|
until the function returns to Scheme (this is clearly a
|
||
|
problem; we are working on a solution).
|
||
|
<UL><LI><table border=0 cellspacing=0 cellpadding=0 width=80%>
|
||
|
<tr> <td><CODE>(import-lambda-definition <CODE><I>name</I></CODE> (<CODE><I>formal</I></CODE> ...))</CODE></td> <td align=right>syntax</td></tr></table>
|
||
|
<LI><table border=0 cellspacing=0 cellpadding=0 width=80%>
|
||
|
<tr> <td><CODE>(import-lambda-definition <CODE><I>name</I></CODE> (<CODE><I>formal</I></CODE> ...) <CODE><I>c-name</I></CODE>)</CODE></td> <td align=right>syntax</td></tr></table>
|
||
|
</UL>
|
||
|
These macros simplify importing functions from C.
|
||
|
They define <CODE><I>name</I></CODE> to be a function with the given formals that
|
||
|
applies those formals to the corresponding C binding.
|
||
|
<CODE><I>C-name</I></CODE>, if supplied, should be a string.
|
||
|
These expand into
|
||
|
<BLOCKQUOTE><PRE>
|
||
|
(define temp (lookup-imported-binding <CODE><I>c-name</I></CODE>))
|
||
|
(define <CODE><I>name</I></CODE>
|
||
|
(lambda (<CODE><I>formal</I></CODE> ...)
|
||
|
(external-apply temp <CODE><I>formal</I></CODE> ...)))
|
||
|
</PRE></BLOCKQUOTE>
|
||
|
<P>
|
||
|
If <CODE><I>c-name</I></CODE> is not supplied, it is derived from <CODE><I>name</I></CODE> by converting
|
||
|
all letters to lowercase and replacing `<CODE>-</CODE>' with `<CODE>_</CODE>'.
|
||
|
<H1><A NAME="9">Adding external modules to the <CODE>Makefile</CODE></A></H1>
|
||
|
|
||
|
<P>Getting access to C bindings from Scheme requires that the C code be
|
||
|
compiled an linked in with the Scheme 48 virtual machine and that the
|
||
|
relevent shared-bindings be created.
|
||
|
The Scheme 48 makefile has rules for compiling and linking external code
|
||
|
and for specifying initialization functions that should be called on
|
||
|
startup.
|
||
|
There are three Makefile variables that control which external modules are
|
||
|
included in the executable for the virutal machine (<CODE>scheme48vm</CODE>).
|
||
|
<CODE>EXTERNAL_OBJECTS</CODE> lists the object files to be included in
|
||
|
<CODE>scheme48vm</CODE>,
|
||
|
<CODE>EXTERNAL_FLAGS</CODE> is a list of <CODE>ld</CODE> flags to be used when
|
||
|
creating <CODE>scheme48vm</CODE>, and
|
||
|
<CODE>EXTERNAL_INITIALIZERS</CODE> is a list of C procedures to be called
|
||
|
on startup.
|
||
|
The procedures listed in <CODE>EXTERNAL_INITIALIZERS</CODE> should take no
|
||
|
arguments and have a return type of <CODE>void</CODE>.
|
||
|
After changing the definitions of any of these variables you should
|
||
|
do <CODE>make scheme48vm</CODE> to rebuild the virtual machine.
|
||
|
<H1><A NAME="dynamic-externals">Dynamic Loading</A></H1>
|
||
|
|
||
|
<P>External code can be loaded into a running Scheme 48 process
|
||
|
and C object-file bindings can be dereferenced at runtime and
|
||
|
their values called
|
||
|
(although not all versions of Unix support all of this).
|
||
|
The required Scheme functions are in the structure <CODE>dynamic-externals</CODE>.
|
||
|
<UL><LI><CODE>(dynamic-load<I> string</I>)</CODE>
|
||
|
</UL>
|
||
|
<CODE>Dynamic-load</CODE> loads the named file into the current
|
||
|
process, raising an exception if the file cannot be found or if dynamic
|
||
|
loading is not supported by the operating system.
|
||
|
The file must have been compiled and linked appropriately.
|
||
|
For Linux, the following commands compile <CODE>foo.c</CODE> into a
|
||
|
file <CODE>foo.so</CODE> that can be loaded dynamically.
|
||
|
<BLOCKQUOTE><PRE>
|
||
|
% gcc -c -o foo.o foo.c
|
||
|
% ld -shared -o foo.so foo.o
|
||
|
</PRE></BLOCKQUOTE>
|
||
|
<UL><LI><CODE>(get-external<I> string</I>) -> <I>external</I></CODE>
|
||
|
<LI><CODE>(external?<I> x</I>) -> <I>boolean</I></CODE>
|
||
|
<LI><CODE>(external-name<I> external</I>) -> <I>string</I></CODE>
|
||
|
<LI><CODE>(external-value<I> external</I>) -> <I>byte-vector</I></CODE>
|
||
|
</UL>
|
||
|
These functions give access to values bound in the current process, and
|
||
|
are used for retrieving values from dynamically-loaded files.
|
||
|
<CODE>Get-external</CODE> returns an <I>external</I> object that contains the
|
||
|
value of <CODE><I>name</I></CODE>, raising an exception if there is no such
|
||
|
value in the current process.
|
||
|
<CODE>External?</CODE> is the predicate for externals, and
|
||
|
<CODE>external-name</CODE> and <CODE>external-value</CODE> return the name and
|
||
|
value of an external.
|
||
|
The value is returned as byte vector of length four (on 32-bit
|
||
|
architectures).
|
||
|
The value is that which was extant when <CODE>get-external</CODE> was
|
||
|
called.
|
||
|
The following two functions can be used to update the values of
|
||
|
externals.
|
||
|
<UL><LI><CODE>(lookup-external<I> external</I>) -> <I>boolean</I></CODE>
|
||
|
<LI><CODE>(lookup-all-externals<I></I>) -> <I>boolean</I></CODE>
|
||
|
</UL>
|
||
|
<CODE>Lookup-external</CODE> updates the value of <CODE><I>external</I></CODE> by looking its
|
||
|
name in the current process, returning <CODE>#t</CODE> if it is bound and <CODE>#f</CODE>
|
||
|
if it is not.
|
||
|
<CODE>Lookup-all-externals</CODE> calls <CODE>lookup-external</CODE> on all extant
|
||
|
externals, returning <CODE>#f</CODE> any are unbound.
|
||
|
<UL><LI><CODE>(call-external<I> external arg<I><sub>0</sub></I> ...</I>) -> <I>value</I></CODE>
|
||
|
</UL>
|
||
|
An external whose value is a C procedure can be called using
|
||
|
<CODE>call-external</CODE>.
|
||
|
See
|
||
|
|
||
|
the section on <A HREF="#8">calling C functions from Scheme</A>
|
||
|
for more information.
|
||
|
<P>In some versions of Unix retrieving a value from the current
|
||
|
process may require a non-trivial amount of computation.
|
||
|
We recommend that a dynamically-loaded file contain a single initialization
|
||
|
procedure that creates shared bindings for the values exported by the file.
|
||
|
<H1><A NAME="11">Compatibility</A></H1>
|
||
|
<P>Scheme 48's old <CODE>external-call</CODE> function is still available in the structure
|
||
|
<CODE>externals</CODE>, which now also includes <CODE>external-name</CODE> and
|
||
|
<CODE>external-value</CODE>.
|
||
|
The old <CODE>scheme48.h</CODE> file has been renamed <CODE>old-scheme48.h</CODE>.
|
||
|
<H1><A NAME="12">Accessing Scheme data from C</A></H1>
|
||
|
|
||
|
<P>The C header file <CODE>scheme48.h</CODE> provides
|
||
|
access to Scheme 48 data structures
|
||
|
(for compatibility, the old <CODE>scheme48.h</CODE> file is available
|
||
|
as <CODE>old-scheme48.h</CODE>).
|
||
|
The type <CODE>s48_value</CODE> is used for Scheme values.
|
||
|
When the type of a value is known, such as the integer returned
|
||
|
by <CODE>vector-length</CODE> or the boolean returned by <CODE>pair?</CODE>,
|
||
|
the corresponding C procedure returns a C value of the appropriate
|
||
|
type, and not a <CODE>s48_value</CODE>.
|
||
|
Predicates return <CODE>1</CODE> for true and <CODE>0</CODE> for false.
|
||
|
<H2><A NAME="13">Constants</A></H2>
|
||
|
|
||
|
<P>The following macros denote Scheme constants:
|
||
|
<DL><DT><B><CODE>S48_FALSE</CODE></B><DD> is <CODE>#f</CODE>.
|
||
|
<DT><B><CODE>S48_TRUE</CODE></B><DD> is <CODE>#t</CODE>.
|
||
|
<DT><B><CODE>S48_NULL</CODE></B><DD> is the empty list.
|
||
|
<DT><B><CODE>S48_UNSPECIFIC</CODE></B><DD> is a value used for functions which have no
|
||
|
meaningful return value
|
||
|
(in Scheme this value returned by the nullary procedure <CODE>unspecific</CODE>
|
||
|
in the structure <CODE>util</CODE>).
|
||
|
<DT><B><CODE>S48_EOF</CODE></B><DD> is the end-of-file object
|
||
|
(in Scheme this value is returned by the nullary procedure <CODE>eof-object</CODE>
|
||
|
in the structure <CODE>i/o-internal</CODE>).
|
||
|
</DL>
|
||
|
<H2><A NAME="14">Converting values</A></H2>
|
||
|
<P>The following functions convert values between Scheme and C
|
||
|
representations.
|
||
|
The `extract' ones convert from Scheme to C and the `enter's go the other
|
||
|
way.
|
||
|
<UL><LI><CODE>unsigned char s48_extract_char(s48_value)</CODE>
|
||
|
<LI><CODE>char * s48_extract_string(s48_value)</CODE>
|
||
|
<LI><CODE>long s48_extract_integer(s48_value)</CODE>
|
||
|
<LI><CODE>double s48_extract_double(s48_value)</CODE>
|
||
|
<LI><CODE>s48_value s48_enter_char(unsigned char)</CODE>
|
||
|
<LI><table border=0 cellspacing=0 cellpadding=0 width=80%>
|
||
|
<tr> <td><CODE>s48_value s48_enter_string(char *)</CODE></td> <td align=right>(may GC)</td></tr></table>
|
||
|
<LI><table border=0 cellspacing=0 cellpadding=0 width=80%>
|
||
|
<tr> <td><CODE>s48_value s48_enter_integer(long)</CODE></td> <td align=right>(may GC)</td></tr></table>
|
||
|
<LI><table border=0 cellspacing=0 cellpadding=0 width=80%>
|
||
|
<tr> <td><CODE>s48_value s48_enter_double(double)</CODE></td> <td align=right>(may GC)</td></tr></table>
|
||
|
</UL>
|
||
|
<P>The value returned by <CODE>s48_extract_string</CODE> points to the actual
|
||
|
storage used by the string; it is valid only until the next
|
||
|
<A HREF="#gc">garbage collection</A>.
|
||
|
<P><CODE>s48_enter_integer()</CODE> needs to allocate storage when
|
||
|
its argument is too large to fit in a Scheme 48 fixnum.
|
||
|
In cases where the number is known to fit within a fixnum (currently 30 bits
|
||
|
including the sign), the following procedures can be used.
|
||
|
These have the disadvantage of only having a limited range, but
|
||
|
the advantage of never causing a garbage collection.
|
||
|
<UL><LI><CODE>long s48_extract_fixnum(s48_value)</CODE>
|
||
|
<LI><CODE>s48_value s48_enter_fixnum(long)</CODE>
|
||
|
<LI><CODE>long S48_MAX_FIXNUM_VALUE</CODE>
|
||
|
<LI><CODE>long S48_MIN_FIXNUM_VALUE</CODE>
|
||
|
</UL>
|
||
|
<P>An error is signalled if <CODE>s48_extract_fixnum</CODE>'s argument
|
||
|
is not a fixnum or if the argument to <CODE>s48_enter_fixnum</CODE> is less than
|
||
|
<CODE>S48_MIN_FIXNUM_VALUE</CODE> or greater than <CODE>S48_MAX_FIXNUM_VALUE</CODE>
|
||
|
(<I>-2<sup>29</sup></I> and <I>2<sup>29</sup>-1</I> in the current system).
|
||
|
<H2><A NAME="15">C versions of Scheme procedures</A></H2>
|
||
|
<P>The following macros and procedures are C versions of Scheme procedures.
|
||
|
The names were derived by replacing `<CODE>-</CODE>' with `<CODE>_</CODE>',
|
||
|
`<CODE>?</CODE>' with `<CODE>p</CODE>', and dropping `<CODE>!</CODE>.
|
||
|
<UL><LI><CODE>int S48_EQ_P(s48_value)</CODE>
|
||
|
<LI><CODE>int S48_CHAR_P(s48_value)</CODE>
|
||
|
<LI><CODE>int S48_INTEGER_P(s48_value)</CODE>
|
||
|
</UL>
|
||
|
<UL><LI><CODE>int S48_PAIR_P(s48_value)</CODE>
|
||
|
<LI><CODE>s48_value S48_CAR(s48_value)</CODE>
|
||
|
<LI><CODE>s48_value S48_CDR(s48_value)</CODE>
|
||
|
<LI><CODE>void S48_SET_CAR(s48_value, s48_value)</CODE>
|
||
|
<LI><CODE>void S48_SET_CDR(s48_value, s48_value)</CODE>
|
||
|
<LI><table border=0 cellspacing=0 cellpadding=0 width=80%>
|
||
|
<tr> <td><CODE>s48_value s48_cons(s48_value, s48_value)</CODE></td> <td align=right>(may GC)</td></tr></table>
|
||
|
<LI><CODE>long s48_length(s48_value)</CODE>
|
||
|
</UL>
|
||
|
<UL><LI><CODE>int S48_VECTOR_P(s48_value)</CODE>
|
||
|
<LI><CODE>long S48_VECTOR_LENGTH(s48_value)</CODE>
|
||
|
<LI><CODE>s48_value S48_VECTOR_REF(s48_value, long)</CODE>
|
||
|
<LI><CODE>void S48_VECTOR_SET(s48_value, long, s48_value)</CODE>
|
||
|
<LI><table border=0 cellspacing=0 cellpadding=0 width=80%>
|
||
|
<tr> <td><CODE>s48_value s48_make_vector(long, s48_value)</CODE></td> <td align=right>(may GC)</td></tr></table>
|
||
|
</UL>
|
||
|
<UL><LI><CODE>int S48_STRING_P(s48_value)</CODE>
|
||
|
<LI><CODE>long S48_STRING_LENGTH(s48_value)</CODE>
|
||
|
<LI><CODE>char S48_STRING_REF(s48_value, long)</CODE>
|
||
|
<LI><CODE>void S48_STRING_SET(s48_value, long, char)</CODE>
|
||
|
<LI><table border=0 cellspacing=0 cellpadding=0 width=80%>
|
||
|
<tr> <td><CODE>s48_value s48_make_string(long, char)</CODE></td> <td align=right>(may GC)</td></tr></table>
|
||
|
</UL>
|
||
|
<UL><LI><CODE>int S48_SYMBOL_P(s48_value)</CODE>
|
||
|
<LI><CODE>s48_value s48_SYMBOL_TO_STRING(s48_value)</CODE>
|
||
|
</UL>
|
||
|
<UL><LI><CODE>int S48_BYTE_VECTOR_P(s48_value)</CODE>
|
||
|
<LI><CODE>long S48_BYTE_VECTOR_LENGTH(s48_value)</CODE>
|
||
|
<LI><CODE>char S48_BYTE_VECTOR_REF(s48_value, long)</CODE>
|
||
|
<LI><CODE>void S48_BYTE_VECTOR_SET(s48_value, long, int)</CODE>
|
||
|
<LI><table border=0 cellspacing=0 cellpadding=0 width=80%>
|
||
|
<tr> <td><CODE>s48_value s48_make_byte_vector(long, int)</CODE></td> <td align=right>(may GC)</td></tr></table>
|
||
|
</UL>
|
||
|
<H1><A NAME="16">Calling Scheme functions from C</A></H1>
|
||
|
|
||
|
<P>External code that has been called from Scheme can call back to Scheme
|
||
|
procedures using the following function.
|
||
|
<UL><LI><CODE>scheme_value s48_call_scheme(s48_value proc, long nargs, ...)</CODE>
|
||
|
</UL>
|
||
|
This calls the Scheme procedure <CODE>proc</CODE> on <CODE>nargs</CODE>
|
||
|
arguments, which are passed as additional arguments to <CODE>s48_call_scheme</CODE>.
|
||
|
There may be at most ten arguments.
|
||
|
The value returned by the Scheme procedure is returned by the C procedure.
|
||
|
Invoking any Scheme procedure may potentially cause a garbage collection.
|
||
|
<P>There are some complications that occur when mixing calls from C to Scheme
|
||
|
with continuations and threads.
|
||
|
C only supports downward continuations (via <CODE>longjmp()</CODE>).
|
||
|
Scheme continuations that capture a portion of the C stack have to follow the
|
||
|
same restriction.
|
||
|
For example, suppose Scheme procedure <CODE>s0</CODE> captures continuation <CODE>a</CODE>
|
||
|
and then calls C procedure <CODE>c0</CODE>, which in turn calls Scheme procedure
|
||
|
<CODE>s1</CODE>.
|
||
|
Procedure <CODE>s1</CODE> can safely call the continuation <CODE>a</CODE>, because that
|
||
|
is a downward use.
|
||
|
When <CODE>a</CODE> is called Scheme 48 will remove the portion of the C stack used
|
||
|
by the call to <CODE>c0</CODE>.
|
||
|
On the other hand, if <CODE>s1</CODE> captures a continuation, that continuation
|
||
|
cannot be used from <CODE>s0</CODE>, because by the time control returns to
|
||
|
<CODE>s0</CODE> the C stack used by <CODE>c0</CODE> will no longer be valid.
|
||
|
An attempt to invoke an upward continuation that is closed over a portion
|
||
|
of the C stack will raise an exception.
|
||
|
<P>In Scheme 48 threads are implemented using continuations, so the downward
|
||
|
restriction applies to them as well.
|
||
|
An attempt to return from Scheme to C at a time when the appropriate
|
||
|
C frame is not on top of the C stack will cause the current thread to
|
||
|
block until the frame is available.
|
||
|
For example, suppose thread <CODE>t0</CODE> calls a C procedure which calls back
|
||
|
to Scheme, at which point control switches to thread <CODE>t1</CODE>, which also
|
||
|
calls C and then back to Scheme.
|
||
|
At this point both <CODE>t0</CODE> and <CODE>t1</CODE> have active calls to C on the
|
||
|
C stack, with <CODE>t1</CODE>'s C frame above <CODE>t0</CODE>'s.
|
||
|
If thread <CODE>t0</CODE> attempts to return from Scheme to C it will block,
|
||
|
as its frame is not accessable.
|
||
|
Once <CODE>t1</CODE> has returned to C and from there to Scheme, <CODE>t0</CODE> will
|
||
|
be able to resume.
|
||
|
The return to Scheme is required because context switches can only occur while
|
||
|
C code is running.
|
||
|
<CODE>T0</CODE> will also be able to resume if <CODE>t1</CODE> uses a continuation to
|
||
|
throw past its call to C.
|
||
|
<H1><A NAME="gc">Interacting with the Scheme Heap</A></H1>
|
||
|
|
||
|
|
||
|
<P>Scheme 48 uses a copying, precise garbage collector.
|
||
|
Any procedure that allocates objects within the Scheme 48 heap may trigger
|
||
|
a garbage collection.
|
||
|
Variables bound to values in the Scheme 48 heap need to be registered with
|
||
|
the garbage collector so that the value will be retained and so that the
|
||
|
variables will be updated if the garbage collector moves the object.
|
||
|
The garbage collector has no facility for updating pointers to the interiors
|
||
|
of objects, so such pointers, for example the ones returned by
|
||
|
<CODE>EXTRACT_STRING</CODE>, will likely become invalid when a garbage collection
|
||
|
occurs.
|
||
|
<H2><A NAME="18">Registering Objects with the GC</A></H2>
|
||
|
|
||
|
<P>A set of macros are used to manage the registration of local variables with the
|
||
|
garbage collector.
|
||
|
<UL><LI><CODE>S48_DECLARE_GC_PROTECT(<I>n</I>)</CODE>
|
||
|
<LI><CODE>void S48_GC_PROTECT_<I>n</I>(s48_value<I><sub>1</sub></I>, <I>...</I>, s48_value<I><sub>n</sub></I>)</CODE>
|
||
|
<LI><CODE>void S48_GC_UNPROTECT()</CODE>
|
||
|
</UL>
|
||
|
<P><CODE>S48_DECLARE_GC_PROTECT(<I>n</I>)</CODE>, where <I>1 <= n <= 9</I>, allocates
|
||
|
storage for registering <I>n</I> variables.
|
||
|
At most one use of <CODE>S48_DECLARE_GC_PROTECT</CODE> may occur in a block.
|
||
|
<CODE>S48_GC_PROTECT_<I>n</I>(<I>v<sub>1</sub></I>, <I>...</I>, <I>v<sub>n</sub></I>)</CODE> registers the
|
||
|
<I>n</I> variables (l-values) with the garbage collector.
|
||
|
It must be within scope of a <CODE>S48_DECLARE_GC_PROTECT(<I>n</I>)</CODE>
|
||
|
and be before any code which can cause a GC.
|
||
|
<CODE>S48_GC_UNPROTECT</CODE> removes the block's protected variables from
|
||
|
the garbage collectors list.
|
||
|
It must be called at the end of the block after
|
||
|
any code which may cause a garbage collection.
|
||
|
Omitting any of the three may cause serious and
|
||
|
hard-to-debug problems.
|
||
|
Notably, the garbage collector may relocate an object and
|
||
|
invalidate <CODE>s48_value</CODE> variables which are not protected.
|
||
|
<P>A <CODE>gc-protection-mismatch</CODE> exception is raised if, when a C
|
||
|
procedure returns to Scheme, the calls
|
||
|
to <CODE>S48_GC_PROTECT()</CODE> have not been matched by an equal number of
|
||
|
calls to <CODE>S48_GC_UNPROTECT()</CODE>.
|
||
|
<P>Global variables may also be registered with the garbage collector.
|
||
|
<UL><LI><CODE>void S48_GC_PROTECT_GLOBAL(<CODE><I>value</I></CODE>)</CODE>
|
||
|
</UL>
|
||
|
<P><CODE>S48_GC_PROTECT_GLOBAL</CODE> permanently registers the
|
||
|
variable <CODE><I>value</I></CODE> (an l-value) with the garbage collector.
|
||
|
There is no way to unregister the variable.
|
||
|
<H2><A NAME="19">Keeping C data structures in the Scheme heap</A></H2>
|
||
|
|
||
|
<P>C data structures can be kept in the Scheme heap by embedding them
|
||
|
inside byte vectors.
|
||
|
The following macros can be used to create and access embedded C objects.
|
||
|
<UL><LI><table border=0 cellspacing=0 cellpadding=0 width=80%>
|
||
|
<tr> <td><CODE>s48_value S48_MAKE_VALUE(type)</CODE></td> <td align=right>(may GC)</td></tr></table>
|
||
|
<LI><CODE>type S48_EXTRACT_VALUE(s48_value, type)</CODE>
|
||
|
<LI><CODE>type * S48_EXTRACT_VALUE_POINTER(s48_value, type)</CODE>
|
||
|
<LI><CODE>void S48_SET_VALUE(s48_value, type, value)</CODE>
|
||
|
</UL>
|
||
|
<P><CODE>S48_MAKE_VALUE</CODE> makes a byte vector large enough to hold an object
|
||
|
whose type is <CODE><I>type</I></CODE>.
|
||
|
<CODE>S48_EXTRACT_VALUE</CODE> returns the contents of a byte vector cast to
|
||
|
<CODE><I>type</I></CODE>, and <CODE>S48_EXTRACT_VALUE_POINTER</CODE> returns a pointer
|
||
|
to the contents of the byte vector.
|
||
|
The value returned by <CODE>S48_EXTRACT_VALUE_POINTER</CODE> is valid only until
|
||
|
the next <A HREF="#gc">garbage collection</A>.
|
||
|
<P><CODE>S48_SET_VALUE</CODE> stores <CODE>value</CODE> into the byte vector.
|
||
|
<H2><A NAME="20">C code and heap images</A></H2>
|
||
|
|
||
|
<P>Scheme 48 uses dumped heap images to restore a previous system state.
|
||
|
The Scheme 48 heap is written into a file in a machine-independent and
|
||
|
operating-system-independent format.
|
||
|
The procedures described above may be used to create objects in the
|
||
|
Scheme heap that contain information specific to the current
|
||
|
machine, operating system, or process.
|
||
|
A heap image containing such objects may not work correctly on
|
||
|
when resumed.
|
||
|
<P>To address this problem, a record type may be given a `resumer'
|
||
|
procedure.
|
||
|
On startup, the resumer procedure for a type is applied to each record of
|
||
|
that type in the image being restarted.
|
||
|
This procedure can update the record in a manner appropriate to
|
||
|
the machine, operating system, or process used to resume the
|
||
|
image.
|
||
|
<UL><LI><CODE>(define-record-resumer<I> record-type procedure</I>)</CODE>
|
||
|
</UL>
|
||
|
<P><CODE>Define-record-resumer</CODE> defines <CODE><I>procedure</I></CODE>,
|
||
|
which should accept one argument, to be the resumer for
|
||
|
<I>record-type</I>.
|
||
|
The order in which resumer procedures are called is not specified.
|
||
|
<P>The <CODE><I>procedure</I></CODE> argument to <CODE>define-record-resumer</CODE> may
|
||
|
be <CODE>#f</CODE>, in which case records of the given type are
|
||
|
not written out in heap images.
|
||
|
When writing a heap image any reference to such a record is replaced by
|
||
|
the value of the record's first field, and an exception is raised
|
||
|
after the image is written.
|
||
|
<H1><A NAME="21">Using Scheme records in C code</A></H1>
|
||
|
<P>External modules can create records and access their slots
|
||
|
positionally.
|
||
|
<UL><LI><table border=0 cellspacing=0 cellpadding=0 width=80%>
|
||
|
<tr> <td><CODE>s48_value S48_MAKE_RECORD(s48_value)</CODE></td> <td align=right>(may GC)</td></tr></table>
|
||
|
<LI><CODE>int S48_RECORD_P(s48_value)</CODE>
|
||
|
<LI><CODE>s48_value S48_RECORD_TYPE(s48_value)</CODE>
|
||
|
<LI><CODE>s48_value S48_RECORD_REF(s48_value, long)</CODE>
|
||
|
<LI><CODE>void S48_RECORD_SET(s48_value, long, s48_value)</CODE>
|
||
|
</UL>
|
||
|
The argument to <CODE>S48_MAKE_RECORD</CODE> should be a shared binding
|
||
|
whose value is a record type.
|
||
|
In C the fields of Scheme records are only accessible via offsets,
|
||
|
with the first field having offset zero, the second offset one, and
|
||
|
so forth.
|
||
|
If the order of the fields is changed in the Scheme definition of the
|
||
|
record type the C code must be updated as well.
|
||
|
<P>For example, given the following record-type definition
|
||
|
<BLOCKQUOTE><PRE>
|
||
|
(define-record-type thing :thing
|
||
|
(make-thing a b)
|
||
|
thing?
|
||
|
(a thing-a)
|
||
|
(b thing-b))
|
||
|
</PRE></BLOCKQUOTE>
|
||
|
the identifier <CODE>:thing</CODE> is bound to the record type and can
|
||
|
be exported to C:
|
||
|
<BLOCKQUOTE><PRE>
|
||
|
(define-exported-binding "thing-record-type" :thing)
|
||
|
</PRE></BLOCKQUOTE>
|
||
|
<CODE>Thing</CODE> records can then be made in C:
|
||
|
<BLOCKQUOTE><PRE>
|
||
|
static scheme_value thing_record_type_binding = SCHFALSE;
|
||
|
|
||
|
void initialize_things(void)
|
||
|
{
|
||
|
S48_GC_PROTECT_GLOBAL(thing_record_type_binding);
|
||
|
thing_record_type_binding =
|
||
|
s48_get_imported_binding("thing-record-type");
|
||
|
}
|
||
|
|
||
|
scheme_value make_thing(scheme_value a, scheme_value b)
|
||
|
{
|
||
|
s48_value thing;
|
||
|
s48_DECLARE_GC_PROTECT(2);
|
||
|
|
||
|
S48_GC_PROTECT_2(a, b);
|
||
|
|
||
|
thing = s48_make_record(thing_record_type_binding);
|
||
|
S48_RECORD_SET(thing, 0, a);
|
||
|
S48_RECORD_SET(thing, 1, b);
|
||
|
|
||
|
S48_GC_UNPROTECT();
|
||
|
|
||
|
return thing;
|
||
|
}
|
||
|
</PRE></BLOCKQUOTE>
|
||
|
Note that the variables <CODE>a</CODE> and <CODE>b</CODE> must be protected
|
||
|
against the possibility of a garbage collection occuring during
|
||
|
the call to <CODE>s48_make_record()</CODE>.
|
||
|
<H1><A NAME="22">Raising exceptions from external code</A></H1>
|
||
|
|
||
|
<P>The following macros explicitly raise certain errors, immediately
|
||
|
returning to Scheme 48.
|
||
|
Raising an exception performs all
|
||
|
necessary clean-up actions to properly return to Scheme 48, including
|
||
|
adjusting the stack of protected variables.
|
||
|
<UL><LI><CODE>s48_raise_scheme_exception(int type, int nargs, ...)</CODE>
|
||
|
</UL>
|
||
|
<P><CODE>s48_raise_scheme_exception</CODE> is the base procedure for
|
||
|
raising exceptions.
|
||
|
<CODE>type</CODE> is the type of exception, and should be one of the
|
||
|
<CODE>S48_EXCEPTION_</CODE>...constants defined in <CODE>scheme48arch.h</CODE>.
|
||
|
<CODE>nargs</CODE> is the number of additional values to be included in the
|
||
|
exception; these follow the <CODE>nargs</CODE> argument and should all have
|
||
|
type <CODE>s48_value</CODE>.
|
||
|
<CODE>s48_raise_scheme_exception</CODE> never returns.
|
||
|
<P>The following procedures are available for raising particular
|
||
|
types of exceptions.
|
||
|
Like <CODE>s48_raise_scheme_exception</CODE> these never return.
|
||
|
<UL><LI><CODE>s48_raise_argument_type_error(scheme_value)</CODE>
|
||
|
<LI><CODE>s48_raise_argument_number_error(int nargs, int min, int max)</CODE>
|
||
|
<LI><CODE>s48_raise_index_range_error(long value, long min, long max)</CODE>
|
||
|
<LI><CODE>s48_raise_closed_channel_error()</CODE>
|
||
|
<LI><CODE>s48_raise_os_error(int errno)</CODE>
|
||
|
<LI><CODE>s48_raise_out_of_memory_error()</CODE>
|
||
|
</UL>
|
||
|
<P>An argument type error indicates that the given value is of the wrong
|
||
|
type.
|
||
|
An argument number error is raised when the number of arguments, <CODE>nargs</CODE>,
|
||
|
should be, but isn't, between <CODE>min</CODE> and <CODE>max</CODE>, inclusive.
|
||
|
Similarly, and index range error is raised when <CODE>value</CODE> is not between
|
||
|
between <CODE>min</CODE> and <CODE>max</CODE>, inclusive.
|
||
|
<P>The following macros raise argument type errors if their argument does not
|
||
|
have the required type.
|
||
|
<UL><LI><CODE>void S48_CHECK_SYMBOL(s48_value)</CODE>
|
||
|
<LI><CODE>void S48_CHECK_PAIR(s48_value)</CODE>
|
||
|
<LI><CODE>void S48_CHECK_STRING(s48_value)</CODE>
|
||
|
<LI><CODE>void S48_CHECK_INTEGER(s48_value)</CODE>
|
||
|
<LI><CODE>void S48_CHECK_CHANNEL(s48_value)</CODE>
|
||
|
<LI><CODE>void S48_CHECK_BYTE_VECTOR(s48_value)</CODE>
|
||
|
<LI><CODE>void S48_CHECK_RECORD(s48_value)</CODE>
|
||
|
<LI><CODE>void S48_CHECK_SHARED_BINDING(s48_value)</CODE>
|
||
|
</UL>
|
||
|
<H1><A NAME="23">Unsafe functions and macros</A></H1>
|
||
|
<P>All of the C procedures and macros described above check that their
|
||
|
arguments have the appropriate types and that indexes are in range.
|
||
|
The following procedures and macros are identical to those described
|
||
|
above, except that they do not perform type and range checks.
|
||
|
They are provided for the purpose of writing more efficient code;
|
||
|
their general use is not recommended.
|
||
|
<UL><LI><CODE>char S48_UNSAFE_EXTRACT_CHAR(s48_value)</CODE>
|
||
|
<LI><CODE>char * S48_UNSAFE_EXTRACT_STRING(s48_value)</CODE>
|
||
|
<LI><CODE>long S48_UNSAFE_EXTRACT_INTEGER(s48_value)</CODE>
|
||
|
<LI><CODE>long S48_UNSAFE_EXTRACT_DOUBLE(s48_value)</CODE>
|
||
|
</UL>
|
||
|
<UL><LI><CODE>long S48_UNSAFE_EXTRACT_FIXNUM(s48_value)</CODE>
|
||
|
<LI><CODE>s48_value S48_UNSAFE_ENTER_FIXNUM(long)</CODE>
|
||
|
</UL>
|
||
|
<UL><LI><CODE>s48_value S48_UNSAFE_CAR(s48_value)</CODE>
|
||
|
<LI><CODE>s48_value S48_UNSAFE_CDR(s48_value)</CODE>
|
||
|
<LI><CODE>void S48_UNSAFE_SET_CAR(s48_value, s48_value)</CODE>
|
||
|
<LI><CODE>void S48_UNSAFE_SET_CDR(s48_value, s48_value)</CODE>
|
||
|
</UL>
|
||
|
<UL><LI><CODE>long S48_UNSAFE_VECTOR_LENGTH(s48_value)</CODE>
|
||
|
<LI><CODE>s48_value S48_UNSAFE_VECTOR_REF(s48_value, long)</CODE>
|
||
|
<LI><CODE>void S48_UNSAFE_VECTOR_SET(s48_value, long, s48_value)</CODE>
|
||
|
</UL>
|
||
|
<UL><LI><CODE>long S48_UNSAFE_STRING_LENGTH(s48_value)</CODE>
|
||
|
<LI><CODE>char S48_UNSAFE_STRING_REF(s48_value, long)</CODE>
|
||
|
<LI><CODE>void S48_UNSAFE_STRING_SET(s48_value, long, char)</CODE>
|
||
|
</UL>
|
||
|
<UL><LI><CODE>s48_value S48_UNSAFE_SYMBOL_TO_STRING(s48_value)</CODE>
|
||
|
</UL>
|
||
|
<UL><LI><CODE>long S48_UNSAFE_BYTE_VECTOR_LENGTH(s48_value)</CODE>
|
||
|
<LI><CODE>char S48_UNSAFE_BYTE_VECTOR_REF(s48_value, long)</CODE>
|
||
|
<LI><CODE>void S48_UNSAFE_BYTE_VECTOR_SET(s48_value, long, int)</CODE>
|
||
|
</UL>
|
||
|
<UL><LI><CODE>s48_value S48_UNSAFE_SHARED_BINDING_REF(s48_value s_b)</CODE>
|
||
|
<LI><CODE>int S48_UNSAFE_SHARED_BINDING_P(x)</CODE>
|
||
|
<LI><CODE>int S48_UNSAFE_SHARED_BINDING_IS_IMPORT_P(s48_value s_b)</CODE>
|
||
|
<LI><CODE>s48_value S48_UNSAFE_SHARED_BINDING_NAME(s48_value s_b)</CODE>
|
||
|
<LI><CODE>void S48_UNSAFE_SHARED_BINDING_SET(s48_value s_b, s48_value value)</CODE>
|
||
|
</UL>
|
||
|
<UL><LI><CODE>s48_value S48_UNSAFE_RECORD_TYPE(s48_value)</CODE>
|
||
|
<LI><CODE>s48_value S48_UNSAFE_RECORD_REF(s48_value, long)</CODE>
|
||
|
<LI><CODE>void S48_UNSAFE_RECORD_SET(s48_value, long, s48_value)</CODE>
|
||
|
</UL>
|
||
|
<UL><LI><CODE>type S48_UNSAFE_EXTRACT_VALUE(s48_value, type)</CODE>
|
||
|
<LI><CODE>type * S48_UNSAFE_EXTRACT_VALUE_POINTER(s48_value, type)</CODE>
|
||
|
<LI><CODE>void S48_UNSAFE_SET_VALUE(s48_value, type, value)</CODE>
|
||
|
</UL>
|
||
|
<HR ><ADDRESS><a href="http://www-pu.informatik.uni-tuebingen.de/users/sperber/">Mike
|
||
|
Sperber</a>, <a href="http://www.neci.nj.nec.com/homepages/kelsey/">Richard Kelsey</a></ADDRESS><BR>
|
||
|
</BODY></HTML>
|