Scribble insidemz

svn: r7931
This commit is contained in:
Matthew Flatt 2007-12-09 22:59:08 +00:00
parent 0e6e742ec7
commit b7583984d8
26 changed files with 6411 additions and 14 deletions

View File

@ -0,0 +1,28 @@
#lang scribble/doc
@(require "utils.ss")
@title[#:tag "contmarks"]{Continuation Marks}
A mark can be attached to the current continuation frame using
@cppi{scheme_set_cont_mark}. To force the creation of a new frame
(e.g., during a nested function call within your function), use
@cppi{scheme_push_continuation_frame}, and then remove the frame with
@cppi{scheme_pop_continuation_frame}.
@function[(void scheme_set_cont_mark
[Scheme_Object* key]
[Scheme_Object* val])]{
Add/sets a continuation mark in the current continuation.}
@function[(void scheme_push_continuation_frame
[Scheme_Cont_Frame_Data* data])]{
Creates a new continuation frame. The @var{data} record need not be
initialized, and it can be allocated on the C stack. Supply @var{data} to
@cpp{scheme_pop_continuation_frame} to remove the continuation frame.}
@function[(void scheme_pop_continuation_frame
[Scheme_Cont_Frame_Data* data])]{
Removes a continuation frame created by @cpp{scheme_pop_continuation_frame}.}

View File

@ -0,0 +1,97 @@
#lang scribble/doc
@(require "utils.ss")
@title{Custodians}
When an extension allocates resources that must be explicitly freed
(in the same way that a port must be explicitly closed), a Scheme
object associated with the resource should be placed into the
management of the current custodian with @cppi{scheme_add_managed}.
Before allocating the resource, call
@cppi{scheme_custodian_check_available} to ensure that the relevant
custodian is not already shut down. If it is,
@cpp{scheme_custodian_check_available} will raise an exception. If
the custodian is shut down when @cpp{scheme_add_managed} is called,
the close function provided to @cpp{scheme_add_managed} will be called
immediately, and no exception will be reported.
@; ----------------------------------------------------------------------
@function[(Scheme_Custodian* scheme_make_custodian
[Scheme_Custodian* m])]{
Creates a new custodian as a subordinate of @var{m}. If @var{m} is
@cpp{NULL}, then the main custodian is used as the new custodian's
supervisor. Do not use @cpp{NULL} for @var{m} unless you intend to
create an especially privileged custodian.}
@function[(Scheme_Custodian_Reference* scheme_add_managed
[Scheme_Custodian* m]
[Scheme_Object* o]
[Scheme_Close_Custodian_Client* f]
[void* data]
[int strong])]{
Places the value @var{o} into the management of the custodian
@var{m}. If @var{m} is @cpp{NULL}, the current custodian is used.
The @var{f} function is called by the custodian if it is ever asked to
``shutdown'' its values; @var{o} and @var{data} are passed on to
@var{f}, which has the type
@verbatim[#<<EOS
typedef void (*Scheme_Close_Custodian_Client)(Scheme_Object *o,
void *data);
EOS
]
If @var{strong} is non-zero, then the newly managed value will
be remembered until either the custodian shuts it down or
@cpp{scheme_remove_managed} is called. If @var{strong} is
zero, the value is allowed to be garbaged collected (and automatically
removed from the custodian).
The return value from @cpp{scheme_add_managed} can be used to refer
to the value's custodian later in a call to
@cpp{scheme_remove_managed}. A value can be registered with at
most one custodian.
If @var{m} (or the current custodian if @var{m} is @cpp{NULL})is shut
down, then @var{f} is called immediately, and the result is
@cpp{NULL}.}
@function[(void scheme_custodian_check_available
[Scheme_Custodian* m]
[const-char* name]
[const-char* resname]
[Scheme_Custodian_Reference* mref]
[Scheme_Object* o])]{
Removes @var{o} from the management of its custodian. The @var{mref}
argument must be a value returned by @cpp{scheme_add_managed} or
@cpp{NULL}.}
@function[(void scheme_close_managed
[Scheme_Custodian* m])]{
Instructs the custodian @var{m} to shutdown all of its managed values.}
@function[(void scheme_add_atexit_closer
[Scheme_Exit_Closer_Func f])]{
Installs a function to be called on each custodian-registered item and
its closer when MzScheme is about to exit. The registered function
has the type
@verbatim[#<<EOS
typedef
void (*Scheme_Exit_Closer_Func)(Scheme_Object *o,
Scheme_Close_Custodian_Client *f,
void *d);
EOS
]
where @var{d} is the second argument for @var{f}.}

View File

@ -0,0 +1,288 @@
#lang scribble/doc
@(require "utils.ss")
@title{Evaluation}
A Scheme S-expression is evaluated by calling @cppi{scheme_eval}.
This function takes an S-expression (as a @cpp{Scheme_Object*}) and a
namespace and returns the value of the expression in that namespace.
The function @cppi{scheme_apply} takes a @cpp{Scheme_Object*} that is
a procedure, the number of arguments to pass to the procedure, and an
array of @cpp{Scheme_Object *} arguments. The return value is the
result of the application. There is also a function
@cppi{scheme_apply_to_list}, which takes a procedure and a list
(constructed with @cppi{scheme_make_pair}) and performs the Scheme
@scheme[apply] operation.
The @cppi{scheme_eval} function actually calls @cppi{scheme_compile}
followed by @cppi{scheme_eval_compiled}.
@; ----------------------------------------------------------------------
@section[#:tag "topleveleval"]{Top-level Evaluation Functions}
The functions @cpp{scheme_eval}, @cpp{scheme_apply}, etc., are
@defterm{top-level evaluation functions}. Continuation invocations are
confined to jumps within a top-level evaluation.
The functions @cppi{_scheme_eval_compiled}, @cppi{_scheme_apply},
etc. (with a leading underscore) provide the same functionality
without starting a new top-level evaluation; these functions should
only be used within new primitive procedures. Since these functions
allow full continuation hops, calls to non-top-level evaluation
functions can return zero or multiple times.
Currently, escape continuations and primitive error escapes can jump
out of all evaluation and application functions. For more information,
see @secref["exceptions"].
@; ----------------------------------------------------------------------
@section{Tail Evaluation}
@section-index{tail recursion}
All of Scheme's built-in functions and syntax support proper
tail-recursion. When a new primitive procedure or syntax is added to
Scheme, special care must be taken to ensure that tail recursion is
handled properly. Specifically, when the final return value of a
function is the result of an application, then
@cppi{scheme_tail_apply} should be used instead of
@cppi{scheme_apply}. When @cppi{scheme_tail_apply} is called, it
postpones the procedure application until control returns to the
Scheme evaluation loop.
For example, consider the following implementation of a
@scheme[thunk-or] primitive, which takes any number of thunks and
performs @scheme[or] on the results of the thunks, evaluating only as
many thunks as necessary.
@verbatim[#<<EOS
static Scheme_Object *
thunk_or (int argc, Scheme_Object **argv)
{
int i;
Scheme_Object *v;
if (!argc)
return scheme_false;
for (i = 0; i < argc - 1; i++)
if (SCHEME_FALSEP((v = _scheme_apply(argv[i], 0, NULL))))
return v;
return scheme_tail_apply(argv[argc - 1], 0, NULL);
}
EOS
]
This @scheme[thunk-or] properly implements tail-recursion: if the
final thunk is applied, then the result of @scheme[thunk-or] is the
result of that application, so @cppi{scheme_tail_apply} is used for
the final application.
@; ----------------------------------------------------------------------
@section[#:tag "multiple"]{Multiple Values}
A primitive procedure can return multiple values by returning the
result of calling @cppi{scheme_values}. The functions
@cppi{scheme_eval_compiled_multi}, @cppi{scheme_apply_multi},
@cppi{_scheme_eval_compiled_multi}, and @cppi{_scheme_apply_multi}
potentially return multiple values; all other evaluation and
applications procedures return a single value or raise an exception.
Multiple return values are represented by the
@cppi{scheme_multiple_values} ``value''. This quasi-value has the type
@cpp{Scheme_Object *}, but it is not a pointer or a fixnum. When the
result of an evaluation or application is
@cppi{scheme_multiple_values}, the number of actual values can be
obtained as @cppi{scheme_multiple_count} and the array of
@cpp{Scheme_Object*} values as @cppi{scheme_multiple_array}. If any
application or evaluation procedure is called, the
@cpp{scheme_multiple_count} and @cpp{scheme_multiple_array} variables
may be modified, but the array previously referenced by
@cpp{scheme_multiple_array} is never re-used and should never be
modified.
The @cpp{scheme_multiple_count} and @cpp{scheme_multiple_array}
variables only contain meaningful values when
@cpp{scheme_multiple_values} is returned.
@; ----------------------------------------------------------------------
@section{Evaluation Functions}
@function[(Scheme_Object* scheme_eval
[Scheme_Object* expr]
[Scheme_Env* env])]{
Evaluates the (uncompiled) S-expression @var{expr} in the namespace
@var{env}.}
@function[(Scheme_Object* scheme_eval_compiled
[Scheme_Object* obj]
[Scheme_Env* env])]{
Evaluates the compiled expression @var{obj}, which was previously
returned from @cpp{scheme_compile}, first linking to the namespace @var{env}.}
@function[(Scheme_Object* scheme_eval_compiled_multi
[Scheme_Object* obj]
[Scheme_Env* env])]{
Evaluates the compiled expression @var{obj}, possibly
returning multiple values (see @secref["multiple"]).}
@function[(Scheme_Object* _scheme_eval_compiled
[Scheme_Object* obj]
[Scheme_Env* env])]{
Non-top-level version of @cpp{scheme_eval_compiled}. (See @secref["topleveleval"].)}
@function[(Scheme_Object* _scheme_eval_compiled_multi
[Scheme_Object* obj]
[Scheme_Env* env])]{
Non-top-level version of @cpp{scheme_eval_compiled_multi}. (See @secref["topleveleval"].)}
@function[(Scheme_Env* scheme_basic_env)]{
Creates the main namespace for an embedded PLT Scheme. This procedure
must be called before other Scheme library function (except
@cpp{scheme_make_param}). Extensions to Scheme cannot call this
function.
If it is called more than once, this function resets all threads
(replacing the main thread), parameters, ports, namespaces, and
finalizations.}
@function[(Scheme_Object* scheme_make_namespace
[int argc]
[Scheme_Object** argv])]{
Creates and returns a new namespace. This values can be cast to
@scheme[Scheme\_Env *]. It can also be installed in
a parameterization using @cppi{scheme_set_param} with
@cppi{MZCONFIG_ENV}.
When PLT Scheme is embedded in an application, create the initial
namespace with @cppi{scheme_basic_env} before calling this procedure
to create new namespaces.}
@function[(Scheme_Object* scheme_apply
[Scheme_Object* f]
[int c]
[Scheme_Object** args])]{
Applies the procedure @var{f} to the given arguments.}
@function[(Scheme_Object* scheme_apply_multi
[Scheme_Object* f]
[int c]
[Scheme_Object** args])]{
Applies the procedure @var{f} to the given arguments, possibly
returning multiple values (see @secref["multiple"]).}
@function[(Scheme_Object* _scheme_apply
[Scheme_Object* f]
[int c]
[Scheme_Object** args])]{
Non-top-level version of @cpp{scheme_apply}. (See @secref["topleveleval"].)}
@function[(Scheme_Object* _scheme_apply_multi
[Scheme_Object* f]
[int c]
[Scheme_Object** args])]{
Non-top-level version of @cpp{scheme_apply_multi}. (See @secref["topleveleval"].)}
@function[(Scheme_Object* scheme_apply_to_list
[Scheme_Object* f]
[Scheme_Object* args])]{
Applies the procedure @var{f} to the list of arguments in @var{args}.}
@function[(Scheme_Object* scheme_eval_string
[char* str]
[Scheme_Env* env])]{
Reads a single S-expression from @var{str} and evaluates it in the given
namespace; the expression must return a single value, otherwise an
exception is raised. The @var{str} argument is parsed as a
UTF-8-encoded string of Unicode characters (so plain ASCII is fine).}
@function[(Scheme_Object* scheme_eval_string_multi
[char* str]
[Scheme_Env* env])]{
Like @cpp{scheme_eval_string}, but returns
@cpp{scheme_multiple_values} when the expression returns multiple
values.}
@function[(Scheme_Object* scheme_eval_string_all
[char* str]
[Scheme_Env* env]
[int all])]{
Like @cpp{scheme_eval_string}, but if @var{all} is not @cpp{0}, then
expressions are read and evaluated from @var{str} until the end of
the string is reached.}
@function[(Scheme_Object* scheme_tail_apply
[Scheme_Object* f]
[int n]
[Scheme_Object** args])]{
Applies the procedure as a tail-call. Actually, this function just
registers the given application to be invoked when control returns to
the evaluation loop. (Hence, this function is only useful within a
primitive procedure that is returning to its caller.)}
@function[(Scheme_Object* scheme_tail_apply_no_copy
[Scheme_Object* f]
[int n]
[Scheme_Object** args])]{
Like @cpp{scheme_tail_apply}, but the array @var{args} is not
copied. Use this only when @var{args} has infinite extent and will not
be used again, or when @var{args} will certainly not be used again
until the called procedure has returned.}
@function[(Scheme_Object* scheme_tail_apply_to_list
[Scheme_Object* f]
[Scheme_Object* l])]{
Applies the procedure as a tail-call.}
@function[(Scheme_Object* scheme_compile
[Scheme_Object* form]
[Scheme_Env* env]
[int writable])]{
Compiles the S-expression @var{form} in the given namespace. The
returned value can be used with @cpp{scheme_eval_compiled} et al.
Provide a non-zero value fo @var{writable} if the resulting compiled
object will be marshalled via @scheme[write] instead of evaluated.}
@function[(Scheme_Object* scheme_expand
[Scheme_Object* form]
[Scheme_Env* env])]{
Expands all macros in the S-expression @var{form} using the given
namespace.}
@function[(Scheme_Object* scheme_values
[int n]
[Scheme_Object** args])]{
Returns the given values together as multiple return values. Unless
@var{n} is @cpp{1}, the result will always be
@cpp{scheme_multiple_values}.}

View File

@ -0,0 +1,467 @@
#lang scribble/doc
@(require "utils.ss")
@title[#:tag "exceptions"]{Exceptions and Escape Continuations}
When Scheme encounters an error, it raises an exception. The default
exception handler invokes the error display handler and then the error
escape handler. The default error escape handler escapes via a
@defterm{primitive error escape}, which is implemented by calling
@cpp{scheme_longjmp(*scheme_current_thread->error_buf)}.
An embedding program should install a fresh buffer into
@cpp{scheme_current_thread->error_buf} and call
@cpp{scheme_setjmp(*scheme_current_thread->error_buf)} before any
top-level entry into Scheme evaluation to catch primitive error
escapes. When the new buffer goes out of scope, restore the original
in @cpp{scheme_current_thread->error_buf}. The macro
@cppi{scheme_error_buf} is a shorthand for
@cpp{*scheme_current_thread->error_buf}.
@verbatim[#<<EOS
mz_jmp_buf * volatile save, fresh;
...
save = scheme_current_thread->error_buf;
scheme_current_thread->error_buf = &fresh;
if (scheme_setjmp(scheme_error_buf)) {
/* There was an error */
...
} else {
v = scheme_eval_string(s, env);
}
scheme_current_thread->error_buf = save;
...
EOS
]
3m: when @cpp{scheme_setjmp} is used, the enclosing context must
provide a local-variable registration record via @cpp{MZ_GC_DECL_REG}.
Use @cpp{MZ_GC_DECL_REG(0)} if the context has no local variables to
register. Unfortunately, when using @DFlag{xform} with @|mzc| instead
of @cpp{MZ_GC_DECL_REG}, etc., you may need to declare a dummy pointer
and use it after @cpp{scheme_setjmp} to ensure that a local-variable
registration is generated.
New primitive procedures can raise a generic exception by calling
@cppi{scheme_signal_error}. The arguments for
@cpp{scheme_signal_error} are roughly the same as for the standard C
function @cpp{printf}. A specific primitive exception can be raised by
calling @cppi{scheme_raise_exn}.
Full @as-index{continuations} are implemented in Scheme by copying
the C stack and using @cppi{scheme_setjmp} and @cppi{scheme_longjmp}.
As long a C/C++ application invokes Scheme evaluation through the
top-level evaluation functions (@cpp{scheme_eval}, @cpp{scheme_apply},
etc., as opposed to @cpp{_scheme_apply}, @cpp{_scheme_eval_compiled},
etc.), the code is protected against any unusual behavior from Scheme
evaluations (such as returning twice from a function) because
continuation invocations are confined to jumps within a single
top-level evaluation. However, escape continuation jumps are still
allowed; as explained in the following sub-section, special care must
be taken in extension that is sensitive to escapes.
@; ----------------------------------------------------------------------
@section[#:tag "imz:tempcatch"]{Temporarily Catching Error Escapes}
When implementing new primitive procedure, it is sometimes useful to
catch and handle errors that occur in evaluating subexpressions. One
way to do this is the following: save
@cppi{scheme_current_thread->error_buf} to a temporary variable, set
@cppi{scheme_current_thread->error_buf} to the address of a
stack-allocated @cpp{mz_jmp_buf}, invoke
@cpp{scheme_setjmp(scheme_error_buf)}, perform the function's work,
and then restore @cpp{scheme_current_thread->error_buf} before
returning a value. (3m: A stack-allocated @cpp{mz_jmp_buf} instance
need not be registered with the garbage collector, and a
heap-allocated @cpp{mz_jmp_buf} should be alloctaed as atomic.)
However, beware that a prompt abort or the invocation of an escaping
continuation looks like a primitive error escape. In that case, the
special indicator flag @cppi{scheme_jumping_to_continuation} is
non-zero (instead of its normal zero value); this situation is only
visible when implementing a new primitive procedure. When
@cppi{scheme_jumping_to_continuation} is non-zero, honor the escape
request by chaining to the previously saved error buffer; otherwise,
call @cppi{scheme_clear_escape}.
@verbatim[#<<EOS
mz_jmp_buf * volatile save, fresh;
save = scheme_current_thread->error_buf;
scheme_current_thread->error_buf = &fresh;
if (scheme_setjmp(scheme_error_buf)) {
/* There was an error or continuation invocation */
if (scheme_jumping_to_continuation) {
/* It was a continuation jump */
scheme_longjmp(*save, 1);
/* To block the jump, instead: scheme_clear_escape(); */
} else {
/* It was a primitive error escape */
}
} else {
scheme_eval_string("x", scheme_env);
}
scheme_current_thread->error_buf = save;
EOS
]
This solution works fine as long as the procedure implementation only
calls top-level evaluation functions (@cpp{scheme_eval},
@cpp{scheme_apply}, etc., as opposed to @cpp{_scheme_apply},
@cpp{_scheme_eval_compiled}, etc.). Otherwise, use
@cppi{scheme_dynamic_wind} to protect your code against full
continuation jumps in the same way that @scheme[dynamic-wind] is used
in Scheme.
The above solution simply traps the escape; it doesn't report the
reason that the escape occurred. To catch exceptions and obtain
information about the exception, the simplest route is to mix Scheme
code with C-implemented thunks. The code below can be used to catch
exceptions in a variety of situations. It implements the function
@cpp{_apply_catch_exceptions}, which catches exceptions during the
application of a thunk. (This code is in
@filepath{collects/mzscheme/examples/catch.c} in the distribution.)
@verbatim[#<<EOS
static Scheme_Object *exn_catching_apply, *exn_p, *exn_message;
static void init_exn_catching_apply()
{
if (!exn_catching_apply) {
char *e =
"(lambda (thunk) "
"(with-handlers ([void (lambda (exn) (cons #f exn))]) "
"(cons #t (thunk))))";
/* make sure we have a namespace with the standard bindings: */
Scheme_Env *env = (Scheme_Env *)scheme_make_namespace(0, NULL);
scheme_register_extension_global(&exn_catching_apply,
sizeof(Scheme_Object *));
scheme_register_extension_global(&exn_p,
sizeof(Scheme_Object *));
scheme_register_extension_global(&exn_message,
sizeof(Scheme_Object *));
exn_catching_apply = scheme_eval_string(e, env);
exn_p = scheme_lookup_global(scheme_intern_symbol("exn?"), env);
exn_message
= scheme_lookup_global(scheme_intern_symbol("exn-message"),
env);
}
}
/* This function applies a thunk, returning the Scheme value if
there's no exception, otherwise returning NULL and setting *exn
to the raised value (usually an exn structure). */
Scheme_Object *_apply_thunk_catch_exceptions(Scheme_Object *f,
Scheme_Object **exn)
{
Scheme_Object *v;
init_exn_catching_apply();
v = _scheme_apply(exn_catching_apply, 1, &f);
/* v is a pair: (cons #t value) or (cons #f exn) */
if (SCHEME_TRUEP(SCHEME_CAR(v)))
return SCHEME_CDR(v);
else {
*exn = SCHEME_CDR(v);
return NULL;
}
}
Scheme_Object *extract_exn_message(Scheme_Object *v)
{
init_exn_catching_apply();
if (SCHEME_TRUEP(_scheme_apply(exn_p, 1, &v)))
return _scheme_apply(exn_message, 1, &v);
else
return NULL; /* Not an exn structure */
}
EOS
]
In the following example, the above code is used to catch exceptions
that occur during while evaluating source code from a string.
@verbatim[#<<EOS
static Scheme_Object *do_eval(void *s, int noargc, Scheme_Object **noargv)
{
return scheme_eval_string((char *)s, scheme_get_env(scheme_config));
}
static Scheme_Object *eval_string_or_get_exn_message(char *s)
{
Scheme_Object *v, *exn;
v = scheme_make_closed_prim(do_eval, s);
v = _apply_thunk_catch_exceptions(v, &exn);
/* Got a value? */
if (v)
return v;
v = extract_exn_message(exn);
/* Got an exn? */
if (v)
return v;
/* `raise' was called on some arbitrary value */
return exn;
}
EOS
]
@; ----------------------------------------------------------------------
@section{Enabling and Disabling Breaks}
When embedding PLT Scheme, asynchronous break exceptions are disabled by
default. Call @cpp{scheme_set_can_break} (which is the same as calling
the Scheme funciton @scheme[break-enabled]) to enable or disable
breaks. To enable or disable breaks during the dynamic extent of
another evaluation (where you would use
@scheme[with-break-parameterization] in Scheme), use
@cppi{scheme_push_break_enable} before and
@cppi{scheme_pop_break_enable} after, instead.
@section{Exception Functions}
@function[(void scheme_signal_error
[char* msg]
[... ...])]{
Raises a generic primitive exception. The parameters are roughly as
for @cpp{printf}, but with the following format directives:
@itemize{
@item{@FormatD{c} : a Unicode character (of type @cpp{mzchar})}
@item{@FormatD{d} : an integer}
@item{@FormatD{ld} : a @cpp{long} integer}
@item{@FormatD{f} : a floating-point @cpp{double}}
@item{@FormatD{s} : a nul-terminated @cpp{char} string}
@item{@FormatD{5} : a nul-terminated @cpp{mzchar} string}
@item{@FormatD{S} : a Scheme symbol (a @cpp{Scheme_Object*})}
@item{@FormatD{t} : a @cpp{char} string with a @cpp{long} size (two
arguments), possibly containing a non-terminating nul byte, and
possibly without a nul-terminator}
@item{@FormatD{u} : a @cpp{mzchar} string with a @cpp{long} size (two
arguments), possibly containing a non-terminating nul character, and
possibly without a nul-terminator}
@item{@FormatD{T} : a Scheme string (a @cpp{Scheme_Object*})}
@item{@FormatD{q} : a string, truncated to 253 characters, with ellipses
printed if the string is truncated}
@item{@FormatD{Q} : a Scheme string (a @cpp{Scheme_Object*}),
truncated to 253 characters, with ellipses printed if the string is
truncated}
@item{@FormatD{V} : a Scheme value (a @cpp{Scheme_Object*}),
truncated according to the current error print width.}
@item{@FormatD{e} : an @cpp{errno} value, to be printed as a text
message.}
@item{@FormatD{E} : a platform-specific error value, to be printed as a
text message.}
@item{@FormatD{Z} : a potential platform-specific error value and a
@cpp{char} string; if the string is non-@cpp{NULL}, then the error
value is ignored, otherwise the error value is used as for \Format{E}.}
@item{@FormatD{%} : a percent sign}
}
The arguments following the format string must include no more than 25
strings and Scheme values, 25 integers, and 25 floating-point
numbers. (This restriction simplifies the implementation with precise
garbage collection.)}
@function[(void scheme_raise_exn
[int exnid]
[... ...])]{
Raises a specific primitive exception. The @var{exnid} argument
specifies the exception to be raised. If an instance of that exception
has @math{n} fields, then the next @math{n-2} arguments are values for
those fields (skipping the @scheme[message] and @scheme[debug-info]
fields). The remaining arguments start with an error string and
proceed roughly as for @cpp{printf}; see @cpp{scheme_signal_error}
above for more details.
Exception ids are @cpp{#define}d using the same names as in Scheme,
but prefixed with ``MZ'', all letters are capitalized, and all ``:'s',
``-''s, and ``/''s are replaced with underscores. For example,
@cpp{MZEXN_FAIL_FILESYSTEM} is the exception id for a filesystem
exception.}
@function[(void scheme_warning
[char* msg]
[... ...])]{
Signals a warning. The parameters are roughly as for @cpp{printf}; see
@cpp{scheme_signal_error} above for more details.}
@function[(void scheme_wrong_count
[char* name]
[int minc]
[int maxc]
[int argc]
[Scheme_Object** argv])]{
This function is automatically invoked when the wrong number of
arguments are given to a primitive procedure. It signals that the
wrong number of parameters was received and escapes (like
@cpp{scheme_signal_error}). The @var{name} argument is the name of
the procedure that was given the wrong number of arguments; @var{minc}
is the minimum number of expected arguments; @var{maxc} is the maximum
number of expected arguments, or -1 if there is no maximum; @var{argc}
and @var{argv} contain all of the received arguments.}
@function[(void scheme_wrong_type
[char* name]
[char* expected]
[int which]
[int argc]
[Scheme_Object** argv])]{
Signals that an argument of the wrong type was received, and escapes
(like @cpp{scheme_signal_error}). The @var{name} argument is the name
of the procedure that was given the wrong type of argument;
@var{expected} is the name of the expected type; @var{which} is the
offending argument in the @var{argv} array; @var{argc} and @var{argv}
contain all of the received arguments. If the original @var{argc} and
@var{argv} are not available, provide -1 for @var{which} and a pointer
to the bad value in @var{argv}; @var{argc} is ignored in this case.}
@function[(void scheme_wrong_return_arity
[char* name]
[int expected]
[int got]
[Scheme_Object** argv]
[const-char* detail])]{
Signals that the wrong number of values were returned to a
multiple-values context. The @var{expected} argument indicates how
many values were expected, @var{got} indicates the number received,
and @var{argv} are the received values. The @var{detail} string can be
@cpp{NULL} or it can contain a @cpp{printf}-style string (with
additional arguments) to describe the context of the error; see
@cpp{scheme_signal_error} above for more details about the
@cpp{printf}-style string.}
@function[(void scheme_unbound_global
[char* name])]{
Signals an unbound-variable error, where @var{name} is the name of the
variable.}
@function[(char* scheme_make_provided_string
[Scheme_Object* o]
[int count]
[int* len])]{
Converts a Scheme value into a string for the purposes of reporting an
error message. The @var{count} argument specifies how many Scheme
values total will appear in the error message (so the string for this
value can be scaled appropriately). If @var{len} is not @cpp{NULL}, it
is filled with the length of the returned string.}
@function[(char* scheme_make_args_string
[char* s]
[int which]
[int argc]
[Scheme_Object** argv]
[long* len])]{
Converts an array of Scheme values into a byte string, skipping the
array element indicated by @var{which}. This function is used to
specify the ``other'' arguments to a function when one argument is bad
(thus giving the user more information about the state of the program
when the error occurred). If @var{len} is not @cpp{NULL}, it is
filled with the length of the returned string.}
@function[(void scheme_check_proc_arity
[char* where]
[int a]
[int which]
[int argc]
[Scheme_Object** argv])]{
Checks the @var{which}th argument in @var{argv} to make sure it is a
procedure that can take @var{a} arguments. If there is an error, the
@var{where}, @var{which}, @var{argc}, and @var{argv} arguments are
passed on to @cpp{scheme_wrong_type}. As in @cpp{scheme_wrong_type},
@var{which} can be -1, in which case @cpp{*}@var{argv} is checked.}
@function[(Scheme_Object* scheme_dynamic_wind
[void* data])]{
Evaluates calls the function @var{action} to get a value for the
@cpp{scheme_dynamic_wind} call. The functions @var{pre} and
@var{post} are invoked when jumping into and out of @var{action},
respectively.
The function @var{jmp_handler} is called when an error is signaled (or
an escaping continuation is invoked) during the call to @var{action};
if @var{jmp_handler} returns @cpp{NULL}, then the error is passed on
to the next error handler, otherwise the return value is used as the
return value for the @cpp{scheme_dynamic_wind} call.
The pointer @var{data} can be anything; it is passed along in calls to
@var{action}, @var{pre}, @var{post}, and @var{jmp_handler}.}
@function[(void scheme_clear_escape)]{
Clears the ``jumping to escape continuation'' flag associated with a
thread. Call this function when blocking escape continuation hops (see
the first example in @secref["imz:tempcatch"]).}
@function[(void scheme_set_can_break
[int on])]{
Enables or disables breaks in the same way as
calling @scheme[break-enabled].}
@function[(void scheme_push_break_enable
[Scheme_Cont_Frame_Data* cframe]
[int on]
[int pre_check])]{
Use this function with @cpp{scheme_pop_break_enable} to enable or
disable breaks in the same way as
@scheme[with-break-parameterization]; this function writes to
@var{cframe} to initialize it, and @cpp{scheme_pop_break_enable} reads
from @var{cframe}. If @var{pre_check} is non-zero and breaks are
currently enabled, any pending break exception is raised.}
@function[(void scheme_pop_break_enable
[Scheme_Cont_Frame_Data* cframe]
[int post_check])]{
Use this function with @cpp{scheme_push_break_enable}. If
@var{post_check} is non-zero and breaks are enabled after restoring
the previous state, then any pending break exception is raised.}
@function[(Scheme_Object* scheme_current_continuation_marks
[Scheme_Object* prompt_tag])]{
Like @scheme[current-continuation-marks]. Passing @cpp{NULL} as
@var{prompt_tag} is the same as providing the default continuation
prompt tag.}

View File

@ -0,0 +1,51 @@
#lang scribble/doc
@(require "utils.ss")
@title{Flags and Hooks}
The following flags and hooks are available when PLT Scheme is
embedded:
@itemize{
@item{@cppdef{scheme_exit} --- This pointer can be set to a function
that takes an integer argument and returns @cpp{void}; the function
will be used as the default exit handler. The default is @cpp{NULL}.}
@item{@cppdef{scheme_make_stdin}, @cppdef{scheme_make_stdout},
@cppdef{scheme_make_stderr}, --- These pointers can be set to a
function that takes no arguments and returns a Scheme port
@cpp{Scheme_Object *} to be used as the starting standard input,
output, and/or error port. The defaults are @cpp{NULL}. Setting the
initial error port is particularly important for seeing unexpected
error messages if @cpp{stderr} output goes nowhere.}
@item{@cppdef{scheme_console_output} --- This pointer can be set to a
function that takes a string and a @cpp{long} string length; the
function will be called to display internal MzScheme warnings and
messages that possibly contain non-terminating nuls. The default is
@var{NULL}.}
@item{@cppdef{scheme_check_for_break} --- \index{user breaks} This
points to a function of no arguments that returns an integer. It is
used as the default user-break polling procedure in the main
thread. A non-zero return value indicates a user break, and each time
the function returns a non-zero value, it counts as a new break
signal (though the break signal may be ignored if a previous signal
is still pending). The default is @cpp{NULL}.}
@item{@cppdef{scheme_case_sensitive} --- If this flag is set to a
non-zero value before @cppi{scheme_basic_env} is called, then
MzScheme will not ignore capitalization for symbols and global
variable names. The value of this flag should not change once it is
set. The default is zero.}
@item{@cppdef{scheme_allow_set_undefined} --- This flag determines
the initial value of \scmi{compile-allow-set!-undefined}. The default
is zero.}
@item{@cppdef{scheme_console_printf} --- This function pointer was
left for backward compatibility. The default builds a string and
calls @cppi{scheme_console_output}.}
}

View File

@ -0,0 +1,3 @@
(module info setup/infotab
(define name "Scribblings: Inside PLT Scheme")
(define scribblings '(("inside.scrbl" (multi-page main-doc)))))

View File

@ -0,0 +1,41 @@
#lang scribble/doc
@(require "utils.ss")
@title[#:tag-prefix '(lib "scribblings/inside/inside.scrbl")
#:tag "top"]{Inside PLT Scheme}
This manual describes PLT Scheme's C interface, which allows the
interpreter to be extended by a dynamically-loaded library, or
embedded within an arbitrary C/C++ program. The manual assumes
familiarity with PLT Scheme as described in @|MzScheme|.
For an alternative way of dealing with foreign code, see ..., which
describes the @schememodname[scheme/foreign] module for manipulating
low-level libraries and structures purely through Scheme code.
@table-of-contents[]
@; ------------------------------------------------------------------------
@include-section["overview.scrbl"]
@include-section["values.scrbl"]
@include-section["memory.scrbl"]
@include-section["namespaces.scrbl"]
@include-section["procedures.scrbl"]
@include-section["eval.scrbl"]
@include-section["exns.scrbl"]
@include-section["threads.scrbl"]
@include-section["params.scrbl"]
@include-section["contmarks.scrbl"]
@include-section["strings.scrbl"]
@include-section["numbers.scrbl"]
@include-section["ports.scrbl"]
@include-section["structures.scrbl"]
@include-section["security.scrbl"]
@include-section["custodians.scrbl"]
@include-section["misc.scrbl"]
@include-section["hooks.scrbl"]
@; ------------------------------------------------------------------------
@index-section[]

View File

@ -0,0 +1,923 @@
#lang scribble/doc
@(require "utils.ss")
@title[#:tag "im:memoryalloc"]{Memory Allocation}
@section-index{memory}
@section-index{garbage collection}
PLT Scheme uses both @cppi{malloc} and allocation functions provided
by a garbage collector. Embedding/extension C/C++ code may use either
allocation method, keeping in mind that pointers to
garbage-collectable blocks in @cpp{malloc}ed memory are invisible
(i.e., such pointers will not prevent the block from being
garbage-collected).
PLT Scheme CGC uses a conservative garbage collector. This garbage
collector normally only recognizes pointers to the beginning of
allocated objects. Thus, a pointer into the middle of a GC-allocated
string will normally not keep the string from being collected. The
exception to this rule is that pointers saved on the stack or in
registers may point to the middle of a collectable object. Thus, it
is safe to loop over an array by incrementing a local pointer
variable.
PLT Scheme 3m uses a precise garbage collector that moves objects
during collection, in which case the C code must be instrumented to
expose local pointer bindings to the collector, and to provide tracing
procedures for (tagged) records containing pointers. This
instrumentation is described further in @secref["im:3m"].
The basic collector allocation functions are:
@itemize{
@item{@cppi{scheme_malloc} --- Allocates collectable memory that may
contain pointers to collectable objects; for 3m, the memory must be
an array of pointers (though not necessarily to collectable
objects). The newly allocated memory is initially zeroed.}
@item{@cppi{scheme_malloc_atomic} --- Allocates collectable memory
that does not contain pointers to collectable objects. If the memory
does contain pointers, they are invisible to the collector and will
not prevent an object from being collected. Newly allocated atomic
memory is not necessary zeroed.
Atomic memory is used for strings or other blocks of memory which do
not contain pointers. Atomic memory can also be used to store
intentionally-hidden pointers.}
@item{@cppi{scheme_malloc_tagged} --- Allocates collectable memory
that contains a mixture of pointers and atomic data. With the
conservative collector, this function is the same
as @cppi{scheme_malloc}, but under 3m, the type tag stored at the
start of the block is used to determine the size and shape of the
object for future garbage collection (as described
in @secref["im:3m"]).}
@item{@cppi{scheme_malloc_allow_interior} --- Allocates a large
array of pointers such that references are allowed into the middle of
the block under 3m, and such pointers prevent the block from being
collected. This procedure is the same as @cppi{scheme_malloc} with
the conservative collector, but in the that case, having @italic{only}
a pointer into the interior will not prevent the array from being
collected.}
@item{@cppi{scheme_malloc_atomic_allow_interior} --- Like
@cpp{scheme_malloc_allow_interior} for memory that does not
contain pointers.}
@item{@cppi{scheme_malloc_uncollectable} --- Allocates
uncollectable memory that may contain pointers to collectable
objects. There is no way to free the memory. The newly allocated
memory is initially zeroed. This function is not available in 3m.}
}
@index['("globals" "in extension code")]{If} a PLT Scheme extension
stores Scheme pointers in a global or static variable, then that
variable must be registered with
@cppi{scheme_register_extension_global}; this makes the pointer
visible to the garbage collector. Registered variables need not
contain a collectable pointer at all times (even with 3m, but the
variable must contain some pointer, possibly uncollectable, at all
times).
With conservative collection, no registration is needed for the global
or static variables of an embedding program, unless it calls
@cppi{scheme_set_stack_base} with a non-zero second argument. (Under
Mac OS X or with 3m, @cpp{scheme_set_stack_base} must be called
always.) In that case, global and static variables containing
collectable pointers must be registered with
@cppi{scheme_register_static}. The @cppi{MZ_REGISTER_STATIC} macro
takes any variable name and registers it with
@cppi{scheme_register_static}. The @cppi{scheme_register_static}
function can be safely called even when it's not needed, but it must
not be called multiple times for a single memory address.
Collectable memory can be temporarily locked from collection by using
the reference-counting function @cppi{scheme_dont_gc_ptr}. Under 3m,
such locking does not prevent the object from being moved.
Garbage collection can occur during any call into Scheme or its
allocator, on anytime that Scheme has control, except during functions
that are documented otherwise. The predicate and accessor macros
listed in @secref["im:stdtypes"] never trigger a collection.
@; ----------------------------------------------------------------------
@section[#:tag "im:3m"]{Cooperating with 3m}
To allow 3m's precise collector to detect and update pointers during
garbage collection, all pointer values must be registered with the
collector, at least during the times that a collection may occur. The
content of a word registered as a pointer must contain either
@cpp{NULL}, a pointer to the start of a collectable object, a pointer
into an object allocated by @cpp{scheme_malloc_allow_interior}, a
pointer to an object currently allocated by another memory manager
(and therefore not into a block that is currently managed by the
collector), or a pointer to an odd-numbered address (e.g., a Scheme
fixnum).
Pointers are registered in three different ways:
@itemize{
@item{Pointers in static variables should be registered with
@cppi{scheme_register_static} or @cpp{MZ_REGISTER_STATIC}.}
@item{Pointers in allocated memory are registered automatically when
they are in an array allocated with @cpp{scheme_malloc}, etc. When a
pointer resides in an object allocated with
@cpp{scheme_malloc_tagged}, etc.~the tag at the start of the object
identifiers the object's size and shape. Handling of tags is
described in @secref["im:3m:tagged"].}
@item{Local pointers (i.e., pointers on the stack or in registers)
must be registered through the @cpp{MZ_GC_DECL_REG}, @|etc| macros
that are described in @secref["im:3m:stack"].}
}
A pointer must never refer to the interior of an allocated object
(when a garbage collection is possible), unless the object was
allocated with {@cppi{scheme_malloc_allow_interior}}. For this reason,
pointer arithmetic must usually be avoided, unless the variable
holding the generated pointer is @cpp{NULL}ed before a collection.
@bold{IMPORTANT:} The @cppi{SCHEME_SYM_VAL},
@cppi{SCHEME_KEYWORD_VAL}, @cppi{SCHEME_VEC_ELS}, and
@cppi{SCHEME_PRIM_CLOSURE_ELS} macros produce pointers into the middle
of their respective objects, so the results of these macros must not
be held during the time that a collection can occur. Incorrectly
retaining such a pointer can lead to a crash.
@; - - - - - - - - - - - - - - - - - - - - - - - -
@subsection[#:tag "im:3m:tagged"]{Tagged Objects}
As explained in @secref["im:values+types"], the @cpp{scheme_make_type}
function can be used to obtain a new tag for a new type of object.
These new types are in relatively short supply for 3m; the maximum tag
is 255, and Scheme itself uses nearly 200.
After allocating a new tag in 3m (and before creating instances of the
tag), a @defterm{size procedure}, a @defterm{mark procedure}, and a
@defterm{fixup procedure} must be installed for the tag using
@cppi{GC_register_traversers}.
A size procedure simply takes a pointer to an object with the tag and
returns its size in words (not bytes). The @cppi{gcBYTES_TO_WORDS}
macro converts a byte count to a word count.
A mark procedure is used to trace references among objects without
moving any objects. The procedure takes a pointer to an object, and it
should apply the @cppi{gcMARK} macro to every pointer within the
object. The mark procedure should return the same result as the size
procedure.
A fixup procedure is used to update references to objects after or
while they are moved. The procedure takes a pointer to an object, and
it should apply the @cppi{gcFIXUP} macro to every pointer within the
object; the expansion of this macro takes the address of its
argument. The fixup procedure should return the same result as the
size procedure.
Depending on the collector's implementation, the mark or fixup
procedure might not be used. For example, the collector may only use
the mark procedure and not actually move the object. Or it may use the
fixup procedure to mark and move objects at the same time. To
dereference an object pointer during a fixup procedure, use
@cppi{GC_fixup_self} to convert the address passed to the procedure to
refer to the potentially moved object, and use @cppi{GC_resolve} to
convert an address that is not yet fixed up to determine the object's
current location.
When allocating a tagged object in 3m, the tag must be installed
immediately after the object is allocated---or, at least, before the
next possible collection.
@; - - - - - - - - - - - - - - - - - - - - - - - -
@subsection[#:tag "im:3m:stack"]{Local Pointers}
The 3m collector needs to know the address of every local or temporary
pointer within a function call at any point when a collection can be
triggered. Beware that nested function calls can hide temporary
pointers; for example, in
@verbatim[#<<EOS
scheme_make_pair(scheme_make_pair(scheme_true, scheme_false),
scheme_make_pair(scheme_false, scheme_true))
EOS
]
the result from one @cpp{scheme_make_pair} call is on the stack or in
a register during the other call to @cpp{scheme_make_pair}; this
pointer must be exposed to the garbage collection and made subject to
update. Simply changing the code to
@verbatim[#<<EOS
tmp = scheme_make_pair(scheme_true, scheme_false);
scheme_make_pair(tmp,
scheme_make_pair(scheme_false, scheme_true))
EOS
]
does not expose all pointers, since @cpp{tmp} must be evaluated before
the second call to @cpp{scheme_make_pair}. In general, the above code
must be converted to the form
@verbatim[#<<EOS
tmp1 = scheme_make_pair(scheme_true, scheme_false);
tmp2 = scheme_make_pair(scheme_true, scheme_false);
scheme_make_pair(tmp1, tmp2);
EOS
]
and this is converted form must be instrumented to register @cpp{tmp1}
and @cpp{tmp2}. The final result might be
@verbatim[#<<EOS
{
Scheme_Object *tmp1 = NULL, *tmp2 = NULL, *result;
MZ_GC_DECL_REG(2);
MZ_GC_VAR_IN_REG(0, tmp1);
MZ_GC_VAR_IN_REG(1, tmp2);
MZ_GC_REG();
tmp1 = scheme_make_pair(scheme_true, scheme_false);
tmp2 = scheme_make_pair(scheme_true, scheme_false);
result = scheme_make_pair(tmp1, tmp2);
MZ_GC_UNREG();
return result;
}
EOS
]
Notice that @cpp{result} is not registered above. The
@cpp{MZ_GC_UNREG} macro cannot trigger a garbage collection, so the
@cpp{result} variable is never live during a potential
collection. Note also that @cpp{tmp1} and @cpp{tmp2} are initialized
with @cpp{NULL}, so that they always contain a pointer whenever a
collection is possible.
The @cppi{MZ_GC_DECL_REG} macro expands to a local-variable
declaration to hold information for the garbage collector. The
argument is the number of slots to provide for
registration. Registering a simple pointer requires a single slot,
whereas registering an array of pointers requires three slots. For
example, to register a pointer @cpp{tmp} and an array of 10
@cpp{char*}s:
@verbatim[#<<EOS
{
Scheme_Object *tmp1 = NULL;
char *a[10];
int i;
MZ_GC_DECL_REG(4);
MZ_GC_ARRAY_VAR_IN_REG(0, a, 10);
MZ_GC_VAR_IN_REG(3, tmp1);
/* Clear a before a potential GC: */
for (i = 0; i < 10; i++) a[i] = NULL;
...
f(a);
...
}
EOS
]
The @cppi{MZ_GC_ARRAY_VAR_IN_REG} macro registers a local array given
a starting slot, the array variable, and an array size. The
@cppi{MZ_GC_VAR_IN_REG} takes a slot and simple pointer variable. A
local variable or array must not be registered multiple times.
In the above example, the first argument to @cppi{MZ_GC_VAR_IN_REG} is
@cpp{3} because the information for @cpp{a} uses the first three
slots. Even if @cpp{a} is not used after the call to @cpp{f}, @cpp{a}
must be registered with the collector during the entire call to
@cpp{f}, because @cpp{f} presumably uses @cpp{a} until it returns.
The name used for a variable need not be immediate. Structure members
can be supplied as well:
@verbatim[#<<EOS
{
struct { void *s; int v; void *t; } x = {NULL, 0, NULL};
MZ_GC_DECL_REG(2);
MZ_GC_VAR_IN_REG(0, x.s);
MZ_GC_VAR_IN_REG(0, x.t);
...
}
EOS
]
In general, the only constraint on the second argument to
@cppi{MZ_GC_VAR_IN_REG} or @cppi{MZ_GC_ARRAY_VAR_IN_REG} is that
@cpp{&} must produce the relevant address.
Pointer information is not actually registered with the collector
until the @cppi{MZ_GC_REG} macro is used. The @cppi{MZ_GC_UNREG} macro
de-registers the information. Each call to @cpp{MZ_GC_REG} must be
balanced by one call to @cpp{MZ_GC_UNREG}.
Pointer information need not be initialized with
@cppi{MZ_GC_VAR_IN_REG} and @cppi{MZ_GC_ARRAY_VAR_IN_REG} before
calling @cpp{MZ_GC_REG}, and the set of registered pointers can change
at any time---as long as all relevent pointers are registered when a
collection might occur. The following example recycles slots and
completely de-registers information when no pointers are relevant. The
example also illustrates how @cpp{MZ_GC_UNREG} is not needed when
control escapes from the function, such as when
@cpp{scheme_signal_error} escapes.
@verbatim[#<<EOS
{
Scheme_Object *tmp1 = NULL, *tmp2 = NULL;
mzchar *a, *b;
MZ_GC_DECL_REG(2);
MZ_GC_VAR_IN_REG(0, tmp1);
MZ_GC_VAR_IN_REG(1, tmp2);
tmp1 = scheme_make_utf8_string("foo");
MZ_GC_REG();
tmp2 = scheme_make_utf8_string("bar");
tmp1 = scheme_append_char_string(tmp1, tmp2);
if (SCHEME_FALSEP(tmp1))
scheme_signal_error("shouldn't happen!");
a = SCHEME_CHAR_VAL(tmp1);
MZ_GC_VAR_IN_REG(0, a);
tmp2 = scheme_make_pair(scheme_read_bignum(a, 0, 10), tmp2);
MZ_GC_UNREG();
if (SCHEME_INTP(tmp2)) {
return 0;
}
MZ_GC_REG();
tmp1 = scheme_make_pair(scheme_read_bignum(a, 0, 8), tmp2);
MZ_GC_UNREG();
return tmp1;
}
EOS
]
A @cpp{MZ_GC_DECL_REG} can be used in a nested block to hold
declarations for the block's variables. In that case, the nested
@cpp{MZ_GC_DECL_REG} must have its own @cpp{MZ_GC_REG} and
@cpp{MZ_GC_UNREG} calls.
@verbatim[#<<EOS
{
Scheme_Object *accum = NULL;
MZ_GC_DECL_REG(1);
MZ_GC_VAR_IN_REG(0, accum);
MZ_GC_REG();
accum = scheme_make_pair(scheme_true, scheme_null);
{
Scheme_Object *tmp = NULL;
MZ_GC_DECL_REG(1);
MZ_GC_VAR_IN_REG(0, tmp);
MZ_GC_REG();
tmp = scheme_make_pair(scheme_true, scheme_false);
accum = scheme_make_pair(tmp, accum);
MZ_GC_UNREG();
}
accum = scheme_make_pair(scheme_true, accum);
MZ_GC_UNREG();
return accum;
}
EOS
]
Variables declared in a local block can also be registered together
with variables from an enclosing block, but the local-block variable
must be unregistered before it goes out of scope. The
@cppi{MZ_GC_NO_VAR_IN_REG} macro can be used to unregister a variable
or to initialize a slot as having no variable.
@verbatim[#<<EOS
{
Scheme_Object *accum = NULL;
MZ_GC_DECL_REG(2);
MZ_GC_VAR_IN_REG(0, accum);
MZ_GC_NO_VAR_IN_REG(1);
MZ_GC_REG();
accum = scheme_make_pair(scheme_true, scheme_null);
{
Scheme_Object *tmp = NULL;
MZ_GC_VAR_IN_REG(1, tmp);
tmp = scheme_make_pair(scheme_true, scheme_false);
accum = scheme_make_pair(tmp, accum);
MZ_GC_NO_VAR_IN_REG(1);
}
accum = scheme_make_pair(scheme_true, accum);
MZ_GC_UNREG();
return accum;
}
EOS
]
The @cpp{MZ_GC_} macros all expand to nothing when @cpp{MZ_PRECISE_GC}
is not defined, so the macros can be placed into code to be compiled
for both conservative and precise collection.
The @cpp{MZ_GC_REG} and @cpp{MZ_GC_UNREG} macros must never be
used in an OS thread other than Scheme's thread.
@; - - - - - - - - - - - - - - - - - - - - - - - -
@subsection[#:tag "im:3m:mzc"]{Local Pointers and @|mzc| @DFlag{xform}}
When @|mzc| is run with the @DFlag{xform} flag and a source C program,
it produces a C program that is instrumented in the way described in
the previous section (but with a slightly different set of macros).
For each input file @filepath{@italic{name}.c}, the transformed output
is @filepath{@italic{name}.3m.c}.
The @DFlag{xform} mode for @|mzc| does not change allocation calls,
nor does it generate size, mark, or fixup predocures. It merely
converts the code to register local pointers.
Furthermore, the @DFlag{xform} mode for @|mzc| does not handle all of
C. It's ability to rearrange compound expressions is particularly
limited, because @DFlag{xform} merely converts expression text
heuristically instead of parsing C. A future version of the tool will
correct such problems. For now, @|mzc| in @DFlag{xform} mode attempts
to provide reasonable error messages when it is unable to convert a
program, but beware that it can miss cases. To an even more limited
degree, @DFlag{xform} can work on C++ code. Inspect the output of
@DFlag{xform} mode to ensure that your code is correctly instrumented.
Some specific limitations:
@itemize{
@item{The body of a @cpp{for}, @cpp{while}, or @cpp{do} loop must be
surrounded with curly braces. (A conversion error is normally
reported, otherwise.)}
@item{Function calls may not appear on the right-hand side of an
assignment within a declaration block. (A conversion error is
normally reported if such an assignment is discovered.)}
@item{Multiple function calls in @cpp{... ? ... : ...} cannot be
lifted. (A conversion error is normally reported, otherwise.)}
@item{In an assignment, the left-hand side must be a local or static
variable, not a field selection, pointer dereference, etc. (A
conversion error is normally reported, otherwise.)}
@item{The conversion assumes that all function calls use an immediate
name for a function, as opposed to a compound expression as
in @cpp{s->f()}. The function name need not be a top-level
function name, but it must be bound either as an argument or
local variable with the form @cpp{@var{type} @var{id}}; the
syntax @cpp{@var{ret_type} (*@var{id})(...)} is not
recgoinzed, so bind the function type to a simple name
with @cpp{typedef}, first: @cpp{typedef @var{ret_type}
(*@var{type})(...); .... @var{type} @var{id}}.}
@item{Arrays and structs must be passed by address, only.}
@item{GC-triggering code must not appear in system headers.}
@item{Pointer-comparison expressions are not handled correctly when
either of the compared expressions includes a function call.
For example, @cpp{a() == b()} is not converted correctly when
@cpp{a} and @cpp{b} produce pointer values.}
@item{Passing the address of a local pointer to a function works only
when the pointer variable remains live after the function call.}
@item{A @cpp{return;} form can get converted to @cpp["{ " @var{stmt}
"; return; };"], which can break an @cpp{if (...) return; else
...} pattern.}
@item{Local instances of union types are generally not supported.}
@item{Pointer arithmetic cannot be converted away, and is instead
reported as an error.}
}
@; - - - - - - - - - - - - - - - - - - - - - - - -
@subsection[#:tag "im:3m:macros"]{Guiding @|mzc| @DFlag{xform}}
The following macros can be used (with care!) to navigate
@DFlag{xform} around code that it cannot handle:
@itemize{
@item{@cppi{XFORM_START_SKIP} and @cppi{XFORM_END_SKIP}: code
between these two statements is ignored by the transform tool,
except to tokenize it.
Example:
@verbatim[#<<EOS
int foo(int c, ...) {
int r = 0;
XFORM_START_SKIP;
{
/* va plays strange tricks that confuse xform */
va_list args;
va_start(args, c);
while (c--) {
r += va_arg(args, int);
}
}
XFORM_END_SKIP;
return r;
}
EOS
]
These macros can also be used at the top level, outside of any
function. Since they have to be terminated by a semi-colon, however,
top-level uses usually must be wrapped with @cpp{#ifdef
MZ_PRECISE_GC} and @cpp{#endif}; a semi-colon by itself at the
top level is not legal in C.}
@item{@cppi{XFORM_HIDE_EXPR}: a macro that takes wraps an expression to
disable processing of the expression.
Example:
@verbatim[#<<EOS
int foo(int c, ...) {
int r = 0;
{
/* va plays strange tricks that confuse xform */
XFORM_CAN_IGNORE va_list args; /* See below */
XFORM_HIDE_EXPR(va_start(args, c));
while (c--) {
r += XFORM_HIDE_EXPR(va_arg(args, int));
}
}
return r;
}
EOS
]}
@item{@cppi{XFORM_CAN_IGNORE}: a macro that acts like a type
modifier (must appear first) to indicate that a declared variable
can be treated as atomic. See above for an example.}
@item{@cppi{XFORM_START_SUSPEND} and @cppi{XFORM_END_SUSPEND}: for
use at the top level (outside of any function definition), and
similar to @cpp{XFORM_START_SKIP} and @cpp{XFORM_END_SKIP} in
that function and class bodies are not transformed. Type and
prototype information is still collected for use by later
transformations, however. These forms must be terminated by a
semi-colon.}
@item{@cppi{XFORM_START_TRUST_ARITH} and
@cppi{XFORM_END_TRUST_ARITH}: for use at the top level (outside
of any function definition) to disable warnings about pointer
arithmetic. Use only when you're absolutely certain that the garbage
collector cannot be pointers offset into the middle of a collectable
object. These forms must be terminated by a semi-colon.}
@item{@cppi{XFORM_TRUST_PLUS}: a replacement for @cpp{+} that does
not trigger pointer-arithmetic warnings. Use with care.}
@item{@cppi{XFORM_TRUST_MINUS}: a replacement for @cpp{-} that does
not trigger pointer-arithmetic warnings. Use with care.}
}
@section{Memory Functions}
@function[(void* scheme_malloc
[size_t n])]{
Allocates @var{n} bytes of collectable memory, initially filled with
zeros. In 3m, the allocated object is treated as an array of
pointers.}
@function[(void* scheme_malloc_atomic
[size_t n])]{
Allocates @var{n} bytes of collectable memory containing no pointers
visible to the garbage collector. The object is @italic{not}
initialized to zeros.}
@function[(void* scheme_malloc_uncollectable
[size_t n])]{
Non-3m, only. Allocates @var{n} bytes of uncollectable memory.}
@function[(void* scheme_malloc_eternal
[size_t n])]{
Allocates uncollectable atomic memory. This function is equivalent to
@cpp{malloc}, except that the memory cannot be freed.}
@function[(void* scheme_calloc
[size_t num]
[size_t size])]{
Allocates @var{num} * @var{size} bytes of memory using @cpp{scheme_malloc}.}
@function[(void* scheme_malloc_tagged
[size_t n])]{
Like @cpp{scheme_malloc}, but in 3m, the type tag determines how the
garbage collector traverses the object; see @secref["im:memoryalloc"].}
@function[(void* scheme_malloc_allow_interior
[size_t n])]{
Like @cpp{scheme_malloc}, but in 3m, pointers are allowed to
reference the middle of the object; see @secref["im:memoryalloc"].}
@function[(char* scheme_strdup
[char* str])]{
Copies the null-terminated string @var{str}; the copy is collectable.}
@function[(char* scheme_strdup_eternal
[char* str])]{
Copies the null-terminated string @var{str}; the copy will never be freed.}
@function[(void* scheme_malloc_fail_ok
[size_t size]
[size_t size])]{
Attempts to allocate @var{size} bytes using @var{mallocf}. If the
allocation fails, the @scheme[exn:misc:out-of-memory] exception is
raised.}
@function[(void** scheme_malloc_immobile_box
[void* p])]{
Allocates memory that is not garbage-collected and that does not move
(even with 3m), but whose first word contains a pointer to a
collectable object. The box is initialized with @var{p}, but the value
can be changed at any time. An immobile box must be explicitly freed
using @cpp{scheme_free_immobile_box}.}
@function[(void scheme_free_immobile_box
[void** b])]{
Frees an immobile box allocated with @cpp{scheme_malloc_immobile_box}.}
@function[(void scheme_register_extension_global
[void* ptr]
[long size])]{
Registers an extension's global variable that can contain Scheme
pointers. The address of the global is given in @var{ptr}, and its
size in bytes in @var{size}.In addition to global variables, this
function can be used to register any permanent memory that the
collector would otherwise treat as atomic. A garbage collection can
occur during the registration.}
@function[(void scheme_set_stack_base
[void* stack_addr]
[int no_auto_statics])]{
Overrides the GC's auto-determined stack base, and/or disables the
GC's automatic traversal of global and static variables. If
@var{stack_addr} is @cpp{NULL}, the stack base determined by the GC is
used. Otherwise, it should be the ``deepest'' memory address on the
stack where a collectable pointer might be stored. This function
should be called only once, and before any other @cpp{scheme_}
function is called. It never triggers a garbage collection.
The following example shows a typical use for setting the stack base:
@verbatim[#<<EOS
int main(int argc, char **argv) {
int dummy;
scheme_set_stack_base(&dummy, 0);
real_main(argc, argv); /* calls scheme_basic_env(), etc. */
}
EOS
]}
@function[(void scheme_set_stack_bounds
[void* stack_addr]
[void* stack_end]
[int no_auto_statics])]{
Like @cpp{scheme_set_stack_base}, except for the extra
@var{stack_end} argument. If @var{stack_end} is non-@cpp{NULL}, then
it corresponds to a point of C-stack growth after which Scheme
should attempt to handle stack overflow. The @var{stack_end} argument
should not correspond to the actual stack end, since detecting stack
overflow may take a few frames, and since handling stack overflow
requires a few frames.
If @var{stack_end} is @cpp{NULL}, then the stack end is computed
automatically: the stack size assumed to be the limit reported by
@cpp{getrlimit} under Unix and Mac OS X, or it is assumed to be 1 MB
under Windows; if this size is greater than 8 MB, then 8 MB is
assumed, instead; the size is decremented by 50000 bytes to cover a
large margin of error; finally, the size is subtracted from (for
stacks that grow down) or added to (for stacks that grow up) the stack
base in @var{stack_addr} or the auotmatically computed stack
base. Note that the 50000-byte margin of error is assumed to cover the
difference between the actual stack start and the reported stack base,
in addition to the margin needed for detecting and handling stack
overflow.}
@function[(void scheme_register_static
[void* ptr]
[long size])]{
Like @cpp{scheme_register_extension_global}, for use in embedding
applications in situations where the collector does not automatically
find static variables (i.e., when @cpp{scheme_set_stack_base} has
been called with a non-zero second argument).
The macro @cppi{MZ_REGISTER_STATIC} can be used directly on a static
variable. It expands to a comment if statics need not be registered,
and a call to @cpp{scheme_register_static} (with the address of the
static variable) otherwise.}
@function[(void scheme_weak_reference
[void** p])]{
Registers the pointer @var{*p} as a weak pointer; when no other
(non-weak) pointers reference the same memory as @var{*p} references,
then @var{*p} will be set to @cpp{NULL} by the garbage collector. The
value in @var{*p} may change, but the pointer remains weak with
respect to the value of @var{*p} at the time @var{p} was registered.}
@function[(void scheme_weak_reference_indirect
[void** p]
[void* v])]{
Like @cppi{scheme_weak_reference}, but @var{*p} is cleared
(regardless of its value) when there are no references to @var{v}.}
@function[(void scheme_register_finalizer
[void* p]
[fnl_proc f]
[void* data]
[fnl_proc* oldf]
[void** olddata])]{
Registers a callback function to be invoked when the memory @var{p}
would otherwise be garbage-collected, and when no ``will''-like
finalizers are registered for @var{p}.
The @cpp{fnl_proc} type is not actually defined, but it is equivalent
to
@verbatim[" typedef void (*fnl_proc)(void *p, void *data)"]
The @var{f} argument is the callback function; when it is called, it
will be passed the value @var{p} and the data pointer @var{data};
@var{data} can be anything --- it is only passed on to the callback
function. If @var{oldf} and @var{olddata} are not @cpp{NULL}, then
@var{*oldf} and @var{*olddata} are filled with the old callback
information (@var{f} and @var{data} will override this old callback).
To remove a registered finalizer, pass @cpp{NULL} for @var{f} and
@var{data}.
Note: registering a callback not only keeps @var{p} from collection
until the callback is invoked, but it also keeps @var{data} reachable
until the callback is invoked.}
@function[(void scheme_add_finalizer
[void* p]
[fnl_proc f]
[void* data])]{
Adds a finalizer to a chain of primitive finalizers. This chain is
separate from the single finalizer installed with
@cpp{scheme_register_finalizer}; all finalizers in the chain are
called immediately after a finalizer that is installed with
@cpp{scheme_register_finalizer}.
See @cpp{scheme_register_finalizer}, above, for information about
the arguments.
To remove an added finalizer, use @cpp{scheme_subtract_finalizer}.}
@function[(void scheme_add_scheme_finalizer
[void* p]
[fnl_proc f]
[void* data])]{
Installs a ``will''-like finalizer, similar to @scheme[will-register].
Scheme finalizers are called one at a time, requiring the collector
to prove that a value has become inaccessible again before calling
the next Scheme finalizer. Finalizers registered with
@cpp{scheme_register_finalizer} or @cpp{scheme_add_finalizer} are
not called until all Scheme finalizers have been exhausted.
See @cpp{scheme_register_finalizer}, above, for information about
the arguments.
There is currently no facility to remove a ``will''-like finalizer.}
@function[(void scheme_add_finalizer_once
[void* p]
[fnl_proc f]
[void* data])]{
Like @cpp{scheme_add_finalizer}, but if the combination @var{f} and
@var{data} is already registered as a (non-``will''-like) finalizer
for @var{p}, it is not added a second time.}
@function[(void scheme_add_scheme_finalizer_once
[void* p]
[fnl_proc f]
[void* data])]{
Like @cpp{scheme_add_scheme_finalizer}, but if the combination of
@var{f} and @var{data} is already registered as a ``will''-like
finalizer for @var{p}, it is not added a second time.}
@function[(void scheme_subtract_finalizer
[void* p]
[fnl_proc f]
[void* data])]{
Removes a finalizer that was installed with
@cpp{scheme_add_finalizer}.}
@function[(void scheme_remove_all_finalization
[void* p])]{
Removes all finalization (``will''-like or not) for @var{p}, including
wills added in Scheme with @scheme[will-register] and finalizers used
by custodians.}
@function[(void scheme_dont_gc_ptr
[void* p])]{
Keeps the collectable block @var{p} from garbage collection. Use this
procedure when a reference to @var{p} is be stored somewhere
inaccessible to the collector. Once the reference is no longer used
from the inaccessible region, de-register the lock with
@cpp{scheme_gc_ptr_ok}. A garbage collection can occur during the
registration.
This function keeps a reference count on the pointers it registers, so
two calls to @cppi{scheme_dont_gc_ptr} for the same @var{p} should
be balanced with two calls to @cpp{scheme_gc_ptr_ok}.}
@function[(void scheme_gc_ptr_ok
[void* p])]{
See @cpp{scheme_dont_gc_ptr}.}
@function[(void scheme_collect_garbage)]{
Forces an immediate garbage-collection.}
@function[(void GC_register_traversers
[short tag]
[Size_Proc s]
[Mark_Proc m]
[Fixup_Proc f]
[int is_const_size]
[int is_atomic])]{
3m only. Registers a size, mark, and fixup procedure for a given type
tag; see @secref["im:3m:tagged"] for more information.
Each of the three procedures takes a pointer and returns an integer:
@verbatim[#<<EOS
typedef int (*Size_Proc)(void *obj);
typedef int (*Mark_Proc)(void *obj);
typedef int (*Fixup_Proc)(void *obj);
EOS
]
If the result of the size procedure is a constant, then pass a
non-zero value for @var{is_const_size}. If the mark and fixup
procedures are no-ops, then pass a non-zero value
for @var{is_atomic}.
}

View File

@ -0,0 +1,293 @@
#lang scribble/doc
@(require "utils.ss")
@title{Miscellaneous Utilities}
The @cppi{MZSCHEME_VERSION} preprocessor macro is defined as a string
describing the version of Scheme. The @cppi{MZSCHEME_VERSION_MAJOR}
and @cppi{MZSCHEME_VERSION_MINOR} macros are defined as the major and
minor version numbers, respectively.
@function[(int scheme_eq
[Scheme_Object* obj1]
[Scheme_Object* obj2])]{
Returns 1 if the Scheme values are @scheme[eq?].}
@function[(int scheme_eqv
[Scheme_Object* obj1]
[Scheme_Object* obj2])]{
Returns 1 if the Scheme values are @scheme[eqv?].}
@function[(int scheme_equal
[Scheme_Object* obj1]
[Scheme_Object* obj2])]{
Returns 1 if the Scheme values are @scheme[equal?].}
@function[(long scheme_equal_hash_key
[Scheme_Object* obj]
[Scheme_Object* obj]
[int c]
[Scheme_Object** elems])]{
Creates and returns a list of length @var{c} with the elements
@var{elems}.}
@function[(int scheme_list_length
[Scheme_Object* list])]{
Returns the length of the list. If @var{list} is not a proper list,
then the last @scheme[cdr] counts as an item. If there is a cycle in
@var{list} (involving only @scheme[cdr]s), this procedure will not
terminate.}
@function[(int scheme_proper_list_length
[Scheme_Object* list])]{
Returns the length of the list, or -1 if it is not a proper list. If
there is a cycle in @var{list} (involving only @scheme[cdr]s), this
procedure returns -1.}
@function[(Scheme_Object* scheme_car
[Scheme_Object* pair])]{
Returns the @scheme[car] of the pair.}
@function[(Scheme_Object* scheme_cdr
[Scheme_Object* pair])]{
Returns the @scheme[cdr] of the pair.}
@function[(Scheme_Object* scheme_cadr
[Scheme_Object* pair])]{
Returns the @scheme[cadr] of the pair.}
@function[(Scheme_Object* scheme_caddr
[Scheme_Object* pair])]{
Returns the @scheme[caddr] of the pair.}
@function[(Scheme_Object* scheme_vector_to_list
[Scheme_Object* vec])]{
Creates a list with the same elements as the given vector.}
@function[(Scheme_Object* scheme_list_to_vector
[Scheme_Object* list])]{
Creates a vector with the same elements as the given list.}
@function[(Scheme_Object* scheme_append
[Scheme_Object* lstx]
[Scheme_Object* lsty])]{
Non-destructively appends the given lists.}
@function[(Scheme_Object* scheme_unbox
[Scheme_Object* obj])]{
Returns the contents of the given box.}
@function[(void scheme_set_box
[Scheme_Object* b]
[Scheme_Object* v])]{
Sets the contents of the given box.}
@function[(Scheme_Object* scheme_load
[char* file])]{
Loads the specified Scheme file, returning the value of the last
expression loaded, or @cpp{NULL} if the load fails.}
@function[(Scheme_Object* scheme_load_extension
[char* filename])]{
Loads the specified Scheme extension file, returning the value provided
by the extension's initialization function.}
@function[(Scheme_Hash_Table* scheme_make_hash_table
[int type])]{
Creates a hash table. The @var{type} argument must be either
@cppi{SCHEME_hash_ptr} or @cppi{SCHEME_hash_string}, which determines
how keys are compared (unless the hash and compare functions are
modified in the hash table record; see below). A @cpp{SCHEME_hash_ptr}
table hashes on a key's pointer address, while
@cpp{SCHEME_hash_string} uses a key as a @cpp{char*} and hashes on the
null-terminated string content. Since a hash table created with
@cpp{SCHEME_hash_string} (instead of @cpp{SCHEME_hash_ptr}) does not
use a key as a Scheme value, it cannot be used from Scheme code.
Although the hash table interface uses the type @cpp{Scheme_Object*}
for both keys and values, the table functions never inspect values,
and they inspect keys only for @cpp{SCHEME_hash_string} hashing. Thus,
the actual types of the values (and keys, for @cpp{SCHEME_hash_ptr}
tables) can be anything.
The public portion of the @cppi{Scheme_Hash_Table} type is defined
roughly as follows:
@verbatim[#<<EOS
typedef struct Scheme_Hash_Table {
Scheme_Object so; /* so.type == scheme_hash_table_type */
/* ... */
int size; /* size of keys and vals arrays */
int count; /* number of mapped keys */
Scheme_Object **keys;
Scheme_Object **vals;
void (*make_hash_indices)(void *v, long *h1, long *h2);
int (*compare)(void *v1, void *v2);
/* ... */
} Scheme_Hash_Table;
EOS
]
The @cpp{make_hash_indices} and @cpp{compare} function pointers can be
set to arbitrary hashing and comparison functions (before any mapping
is installed into the table). A hash function should fill @var{h1}
with a primary hash value and @var{h2} with a secondary hash value;
the values are for double-hashing, where the caller takes appropriate
modulos.
To traverse the hash table content, iterate over @var{keys} and
@var{vals} in parallel from @cpp{0} to @cpp{size-1}, and ignore
@var{keys} where the corresponding @var{vals} entry is @cpp{NULL}.
The @cpp{count} field indicates the number of non-@cpp{NULL} values
that will be encountered.}
@function[(Scheme_Hash_Table* scheme_make_hash_table_equal)]{
Like @cpp{scheme_make_hash_table}, except that keys are treated as
Scheme values and hashed based on @scheme[equal?]\ instead of
@scheme[eq?].}
@function[(void scheme_hash_set
[Scheme_Hash_Table* table]
[Scheme_Object* key]
[Scheme_Object* val])]{
Sets the current value for @var{key} in @var{table} to @var{val}. If
@var{val} is @cpp{NULL}, the @var{key} is unmapped in @var{table}.}
@function[(Scheme_Object* scheme_hash_get
[Scheme_Hash_Table* table]
[Scheme_Object* key])]{
Returns the current value for @var{key} in @var{table}, or @cpp{NULL}
if @var{key} has no value.}
@function[(Scheme_Bucket_Table* scheme_make_bucket_table
[int size_hint]
[int type])]{
Like @cpp{make_hash_table}, but bucket tables are somewhat more
flexible, in that hash buckets are accessible and weak keys are
supported. (They also consume more space than hash tables.)
The @var{type} argument must be either @cppi{SCHEME_hash_ptr},
@cppi{SCHEME_hash_string}, or @cppi{SCHEME_hash_weak_ptr}. The first
two are the same as for hash tables. The last is like
@cpp{SCHEME_hash_ptr}, but the keys are weakly held.
The public portion of the @cppi{Scheme_Bucket_Table} type is defined
roughly as follows:
@verbatim[#<<EOS
typedef struct Scheme_Bucket_Table {
Scheme_Object so; /* so.type == scheme_variable_type */
/* ... */
int size; /* size of buckets array */
int count; /* number of buckets, >= number of mapped keys */
Scheme_Bucket **buckets;
void (*make_hash_indices)(void *v, long *h1, long *h2);
int (*compare)(void *v1, void *v2);
/* ... */
} Scheme_Bucket_Table;
EOS
]
The @cpp{make_hash_indices} and @cpp{compare} functions are used as
for hash tables. Note that @cppi{SCHEME_hash_weak_ptr} supplied as the
initial type makes keys weak even if the hash and comparison functions
are changed.
See @cpp{scheme_bucket_from_table} for information on buckets.}
@function[(void scheme_add_to_table
[Scheme_Bucket_Table* table]
[const-char* key]
[void* val]
[int const])]{
Sets the current value for @var{key} in @var{table} to @var{val}. If
@var{const} is non-zero, the value for @var{key} must never be
changed.}
@function[(void scheme_change_in_table
[Scheme_Bucket_Table* table]
[const-char* key]
[void* val])]{
Sets the current value for @var{key} in @var{table} to @var{val}, but
only if @var{key} is already mapped in the table.}
@function[(void* scheme_lookup_in_table
[Scheme_Bucket_Table* table]
[const-char* key])]{
Returns the current value for @var{key} in @var{table}, or @cpp{NULL}
if @var{key} has no value.}
@function[(Scheme_Bucket* scheme_bucket_from_table
[Scheme_Bucket_Table* table]
[const-char* key])]{
Returns the bucket for @var{key} in @var{table}. The
@cppi{Scheme_Bucket} structure is defined as:
@verbatim[#<<EOS
typedef struct Scheme_Bucket {
Scheme_Object so; /* so.type == scheme_bucket_type */
/* ... */
void *key;
void *val;
} Scheme_Bucket;
EOS
]
Setting @var{val} to @cpp{NULL} unmaps the bucket's key, and @var{key}
can be @cpp{NULL} in that case as well. If the table holds keys
weakly, then @var{key} points to a (weak) pointer to the actual key,
and the weak pointer's value can be @cpp{NULL}.}
@function[(long scheme_double_to_int
[char* where]
[double d])]{
Returns a fixnum value for the given floating-point number @var{d}. If @var{d}
is not an integer or if it is too large, then an error message is
reported; @var{name} is used for error-reporting.}
@function[(long scheme_get_milliseconds)]{
Returns the current ``time'' in milliseconds, just like
@scheme[current-milliseconds].}
@function[(long scheme_get_process_milliseconds)]{
Returns the current process ``time'' in milliseconds, just like
@scheme[current-process-milliseconds].}
@function[(char* scheme_banner)]{
Returns the string that is used as the Scheme startup banner.}
@function[(char* scheme_version)]{
Returns a string for the executing version of Scheme.}

View File

@ -0,0 +1,145 @@
#lang scribble/doc
@(require "utils.ss")
@title[#:tag "im:env"]{Namespaces and Modules}
A Scheme namespace (a top-level environment) is represented by a value
of type @cppi{Scheme_Env*} --- which is also a Scheme value, castable
to @cpp{Scheme_Object*}. Calling @cppi{scheme_basic_env} returns a
namespace that includes all of Scheme's standard global procedures
and syntax.
The @cpp{scheme_basic_env} function must be called once by an
embedding program, before any other PLT Scheme function is called
(except @cpp{scheme_make_param}). The returned namespace is the
initial current namespace for the main Scheme thread. Scheme
extensions cannot call @cpp{scheme_basic_env}.
The current thread's current namespace is available from
@cppi{scheme_get_env}, given the current parameterization (see
@secref["config"]): @cpp{scheme_get_env(scheme_config)}.
New values can be added as @as-index{globals} in a namespace using
@cppi{scheme_add_global}. The @cppi{scheme_lookup_global} function
takes a Scheme symbol and returns the global value for that name, or
@cpp{NULL} if the symbol is undefined.
A @as-index{module}'s set of top-level bindings is implemented using
the same machinery as a namespace. Use @cppi{scheme_primitive_module}
to create a new @cpp{Scheme_Env*} that represents a primitive
module. The name provided to @cppi{scheme_primitive_module} is subject
to prefixing through the @scheme[current-module-name-prefix] parameter
(which is normally set by the module name resolver when auto-loading
module files). After installing variables into the module with
@cppi{scheme_add_global}, etc., call
@cppi{scheme_finish_primitive_module} on the @cpp{Scheme_Env*} value
to make the module declaration available. All defined variables are
exported from the primitive module.
The Scheme @indexed-scheme[#%variable-reference] form produces a value
that is opaque to Scheme code. Use @cpp{SCHEME_PTR_VAL} on the result
of @scheme[#%variable-reference] to obtain the same kind of value as
returned by @cpp{scheme_global_bucket} (i.e., a bucket containing the
variable's value, or @cpp{NULL} if the variable is not yet defined).
@; ----------------------------------------------------------------------
@function[(void scheme_add_global
[char* name]
[Scheme_Object* val]
[Scheme_Env* env])]{
Adds a value to the table of globals for the namespace @var{env},
where @var{name} is a null-terminated string. (The string's case will
be normalized in the same way as for interning a symbol.)}
@function[(void scheme_add_global_symbol
[Scheme_Object* name]
[Scheme_Object* val]
[Scheme_Env* env])]{
Adds a value to the table of globals by symbol name instead of string
name.}
@function[(Scheme_Object* scheme_lookup_global
[Scheme_Object* symbol]
[Scheme_Env* env])]{
Given a global variable name (as a symbol) in @var{sym}, returns the current
value.}
@function[(Scheme_Bucket* scheme_global_bucket
[Scheme_Object* symbol]
[Scheme_Env* env])]{
Given a global variable name (as a symbol) in @var{sym}, returns the bucket
where the value is stored. When the value in this bucket is @cpp{NULL}, then
the global variable is undefined.
The @cppi{Scheme_Bucket} structure is defined as:
@verbatim[#<<EOS
typedef struct Scheme_Bucket {
Scheme_Object so; /* so.type = scheme_variable_type */
void *key;
void *val;
} Scheme_Bucket;
EOS
]}
@function[(Scheme_Bucket* scheme_module_bucket
[Scheme_Object* mod]
[Scheme_Object* symbol]
[int pos]
[Scheme_Env* env])]{
Like @cpp{scheme_global_bucket}, but finds a variable in a
module. The @var{mod} and @var{symbol} arguments are as for
@scheme[dynamic-require] in Scheme. The @var{pos} argument should be
@cpp{-1} always. The @var{env} argument represents the namespace in
which the module is declared.}
@function[(void scheme_set_global_bucket
[char* procname]
[Scheme_Bucket* var]
[Scheme_Object* val]
[int set_undef])]{
Changes the value of a global variable. The @var{procname} argument is
used to report errors (in case the global variable is constant, not
yet bound, or bound as syntax). If @var{set_undef} is not 1, then the
global variable must already have a binding. (For example,
@scheme[set!] cannot set unbound variables, while @scheme[define]
can.)}
@function[(Scheme_Object* scheme_builtin_value
[const-char* name])]{
Gets the binding of a name as it would be defined in the initial
namespace.}
@function[(Scheme_Env* scheme_get_env
[Scheme_Config* config])]{
Returns the current namespace for the given parameterization (see
@secref["config"]). The current thread's current parameterization is
available as @cppi{scheme_config}.}
@function[(Scheme_Env* scheme_primitive_module
[Scheme_Object* name]
[Scheme_Env* for_env])]{
Prepares a new primitive module whose name is the symbol @var{name} (plus any
prefix that is active via @scheme[current-module-name-prefix]). The
module will be declared within the namespace @var{for_env}. The
result is a @cpp{Scheme_Env *} value that can be used with
@cpp{scheme_add_global}, etc., but it represents a module instead
of a namespace. The module is not fully declared until
@cpp{scheme_finish_primitive_module} is called, at which point all
variables defined in the module become exported.}
@function[(void scheme_finish_primitive_module
[Scheme_Env* env])]{
Finalizes a primitive module and makes it available for use within the
module's namespace.}

View File

@ -0,0 +1,165 @@
#lang scribble/doc
@(require "utils.ss")
@title{Bignums, Rationals, and Complex Numbers}
Scheme supports integers of an arbitrary magnitude; when an integer
cannot be represented as a fixnum (i.e., 30 or 62 bits plus a sign
bit), then it is represented by the Scheme type
@cppi{scheme_bignum_type}. There is no overlap in integer values
represented by fixnums and bignums.
Rationals are implemented by the type @cppi{scheme_rational_type},
composed of a numerator and a denominator.
The numerator and denominator fixnums or bignums (possibly mixed).
Complex numbers are implemented by the types
@cppi{scheme_complex_type} and @cppi{scheme_complex_izi_type},
composed of a real and imaginary part. The real and imaginary parts
will either be both flonums, both exact numbers (fixnums, bignums, and
rationals can be mixed in any way), or one part will be exact 0 and
the other part will be a flonum. If the inexact part is inexact 0, the
type is @cpp{scheme_complex_izi_type}, otherwise the type is
@cppi{scheme_complex_type}; this distinction make it easy to test
whether a complex number should be treated as a real number.
@function[(int scheme_is_exact
[Scheme_Object* n])]{
Returns @cpp{1} if @var{n} is an exact number, @scheme[0] otherwise
(@var{n} need not be a number).}
@function[(int scheme_is_inexact
[Scheme_Object* n])]{
Returns @cpp{1} if @var{n} is an inexact number, @scheme[0] otherwise
(@var{n} need not be a number).}
@function[(Scheme_Object* scheme_make_bignum
[long v])]{
Creates a bignum representing the integer @var{v}. This can create a
bignum that otherwise fits into a fixnum. This must only be used to
create temporary values for use with the @cpp{bignum} functions. Final
results can be normalized with @cpp{scheme_bignum_normalize}. Only
normalized numbers can be used with procedures that are not specific
to bignums.}
@function[(Scheme_Object* scheme_make_bignum_from_unsigned
[unsigned-long v])]{
Like @cpp{scheme_make_bignum}, but works on unsigned integers.}
@function[(double scheme_bignum_to_double
[Scheme_Object* n])]{
Converts a bignum to a floating-point number, with reasonable but
unspecified accuracy.}
@function[(float scheme_bignum_to_float
[Scheme_Object* n])]{
If PLT Scheme is not compiled with single-precision floats, this procedure
is actually a macro alias for @cpp{scheme_bignum_to_double}.}
@function[(Scheme_Object* scheme_bignum_from_double
[double d])]{
Creates a bignum that is close in magnitude to the floating-point
number @var{d}. The conversion accuracy is reasonable but unspecified.}
@function[(Scheme_Object* scheme_bignum_from_float
[float f])]{
If PLT Scheme is not compiled with single-precision floats, this procedure
is actually a macro alias for @cpp{scheme_bignum_from_double}.}
@function[(char* scheme_bignum_to_string
[Scheme_Object* n]
[int radix])]{
Writes a bignum into a newly allocated byte string.}
@function[(Scheme_Object* scheme_read_bignum
[mzchar* str]
[int offset]
[int radix])]{
Reads a bignum from a @cpp{mzchar} string, starting from position
@var{offset} in @var{str}. If the string does not represent an
integer, then @cpp{NULL} will be returned. If the string represents a
number that fits in 31 bits, then a @cpp{scheme_integer_type}
object will be returned.}
@function[(Scheme_Object* scheme_read_bignum_bytes
[char* str]
[int offset]
[int radix])]{
Like @cpp{scheme_read_bignum}, but from a UTF-8-encoding byte string.}
@function[(Scheme_Object* scheme_bignum_normalize
[Scheme_Object* n])]{
If @var{n} fits in 31 bits, then a @cpp{scheme_integer_type} object
will be returned. Otherwise, @var{n} is returned.}
@function[(Scheme_Object* scheme_make_rational
[Scheme_Object* n]
[Scheme_Object* d])]{
Creates a rational from a numerator and denominator. The @var{n} and
@var{d} parameters must be fixnums or bignums (possibly mixed). The
resulting will be normalized (thus, a bignum or fixnum might be returned).}
@function[(double scheme_rational_to_double
[Scheme_Object* n])]{
Converts the rational @var{n} to a @cpp{double}.}
@function[(float scheme_rational_to_float
[Scheme_Object* n])]{
If PLT Scheme is not compiled with single-precision floats, this procedure
is actually a macro alias for @cpp{scheme_rational_to_double}.}
@function[(Scheme_Object* scheme_rational_numerator
[Scheme_Object* n])]{
Returns the numerator of the rational @var{n}.}
@function[(Scheme_Object* scheme_rational_denominator
[Scheme_Object* n])]{
Returns the denominator of the rational @var{n}.}
@function[(Scheme_Object* scheme_rational_from_double
[double d])]{
Converts the given @cpp{double} into a maximally-precise rational.}
@function[(Scheme_Object* scheme_rational_from_float
[float d])]{
If PLT Scheme is not compiled with single-precision floats, this procedure
is actually a macro alias for @cpp{scheme_rational_from_double}.}
@function[(Scheme_Object* scheme_make_complex
[Scheme_Object* r]
[Scheme_Object* i])]{
Creates a complex number from real and imaginary parts. The @var{r}
and @var{i} arguments must be fixnums, bignums, flonums, or rationals
(possibly mixed). The resulting number will be normalized (thus, a real
number might be returned).}
@function[(Scheme_Object* scheme_complex_real_part
[Scheme_Object* n])]{
Returns the real part of the complex number @var{n}.}
@function[(Scheme_Object* scheme_complex_imaginary_part
[Scheme_Object* n])]{
Returns the imaginary part of the complex number @var{n}.}

View File

@ -0,0 +1,556 @@
#lang scribble/doc
@(require "utils.ss")
@title{Overview}
@section{CGC versus 3m}
Before mixing any C code with MzScheme, first decide whether to use
the @bold{3m} variant of PLT Scheme, the @bold{CGC} variant of PLT
Scheme, or both:
@itemize{
@item{@bold{@as-index{3m}} : the main variant of PLT Scheme, which
uses @defterm{precise} garbage collection instead of conservative
garbage collection, and it may move objects in memory during a
collection.}
@item{@bold{@as-index{CGC}} : the original variant of PLT Scheme,
where memory management depends on a @defterm{conservative} garbage
collector. The conservative garbage collector can automatically find
references to managed values from C local variables and (on some
platforms) static variables.}
}
At the C level, working with CGC can be much easier than working with
3m, but overall system performance is typically better with 3m.
@; ----------------------------------------------------------------------
@section{Writing MzScheme Extensions}
@section-index["extending MzScheme"]
The process of creating an extension for 3m or CGC is essentially the
same, but the process for 3m is most easily understood as a variant of
the process for CGC.
@subsection{CGC Extensions}
To write a C/C++-based extension for PLT Scheme CGC, follow these
steps:
@itemize{
@item{@index['("header files")]{For} each C/C++ file that uses PLT
Scheme library functions, @cpp{#include} the file
@as-index{@filepath{escheme.h}}.
This file is distributed with the PLT software in an
@filepath{include} directory, but if @|mzc| is used to compile, this
path is found automatically.}
@item{Define the C function @cppi{scheme_initialize}, which takes a
@cpp{Scheme_Env*} namespace (see @secref["im:env"]) and returns a
@cpp{Scheme_Object*} Scheme value.
This initialization function can install new global primitive
procedures or other values into the namespace, or it can simply
return a Scheme value. The initialization function is called when the
extension is loaded with @scheme[load-extension] (the first time);
the return value from @cpp{scheme_initialize} is used as the return
value for @scheme[load-extension]. The namespace provided to
@cpp{scheme_initialize} is the current namespace when
@scheme[load-extension] is called.}
@item{Define the C function @cppi{scheme_reload}, which has the same
arguments and return type as @cpp{scheme_initialize}.
This function is called if @scheme[load-extension] is called a second
time (or more times) for an extension. Like @cpp{scheme_initialize},
the return value from this function is the return value for
@scheme[load-extension].}
@item{Define the C function @cppi{scheme_module_name}, which takes
no arguments and returns a @cpp{Scheme_Object*} value, either a
symbol or @cpp{scheme_false}.
The function should return a symbol when the effect of calling
@cpp{scheme_initialize} and @cpp{scheme_reload} is only to declare
a module with the returned name. This function is called when the
extension is loaded to satisfy a @scheme[require] declaration.
The @cpp{scheme_module_name} function may be called before
@cpp{scheme_initialize} and @cpp{scheme_reload}, after those
functions, or both before and after, depending on how the extension
is loaded and re-loaded.}
@item{Compile the extension C/C++ files to create platform-specific
object files.
The @as-index{@|mzc|} compiler, which is distributed with PLT Scheme,
compiles plain C files when the @as-index{@DFlag{cc}} flag is
specified. More precisely, @|mzc| does not compile the files itself,
but it locates a C compiler on the system and launches it with the
appropriate compilation flags. If the platform is a relatively
standard Unix system, a Windows system with either Microsoft's C
compiler or @exec{gcc} in the path, or a Mac OS X system with Apple's
developer tools installed, then using @|mzc| is typically easier than
working with the C compiler directly. Use the @as-index{@DFlag{cgc}}
flag to indicate that the build is for use with PLT Scheme CGC.}
@item{Link the extension C/C++ files with
@as-index{@filepath{mzdyn.o}} (Unix, Mac OS X) or
@as-index{@filepath{mzdyn.obj}} (Windows) to create a shared object. The
resulting shared object should use the extension @filepath{.so} (Unix),
@filepath{.dll} (Windows), or @filepath{.dylib} (Mac OS X).
The @filepath{mzdyn} object file is distributed in the installation's
@filepath{lib} directory. For Windows, the object file is in a
compiler-specific sub-directory of @filepath{plt\lib}.
The @|mzc| compiler links object files into an extension when the
@as-index{@DFlag{ld}} flag is specified, automatically locating
@filepath{mzdyn}. Again, use the @DFlag{cgc} flag with @|mzc|.}
@item{Load the shared object within Scheme using
@scheme[(load-extension _path)], where @scheme[_path] is the name of
the extension file generated in the previous step.
Alternately, if the extension defines a module (i.e.,
@cpp{scheme_module_name} returns a symbol), then place the shared
object in a special directory so that it is detected by the module
loader when @scheme[require] is used. The special directory is a
platform-specific path that can be obtained by evaluating
@scheme[(build-path "compiled" "native" (system-library-subpath))];
see @scheme[load/use-compiled] for more information. For example, if
the shared object's name is @filepath{example.dll}, then
@scheme[(require "example.ss")] will be redirected to
@filepath{example.dll} if the latter is placed in the sub-directory
@scheme[(build-path "compiled" "native" (system-library-subpath))]
and if @filepath{example.ss} does not exist or has an earlier
timestamp.
Note that @scheme[(load-extension _path)] within a @scheme[module]
does @italic{not} introduce the extension's definitions into the
module, because @scheme[load-extension] is a run-time operation. To
introduce an extension's bindings into a module, make sure that the
extension defines a module, put the extension in the
platform-specific location as described above, and use
@scheme[require].}
}
@index['("allocation")]{@bold{IMPORTANT:}} With PLT Scheme CGC, Scheme
values are garbage collected using a conservative garbage collector,
so pointers to Scheme objects can be kept in registers, stack
variables, or structures allocated with @cppi{scheme_malloc}. However,
static variables that contain pointers to collectable memory must be
registered using @cppi{scheme_register_extension_global} (see
@secref["im:memoryalloc"]).
As an example, the following C code defines an extension that returns
@scheme["hello world"] when it is loaded:
@verbatim[#<<EOS
#include "escheme.h"
Scheme_Object *scheme_initialize(Scheme_Env *env) {
return scheme_make_utf8_string("hello world");
}
Scheme_Object *scheme_reload(Scheme_Env *env) {
return scheme_initialize(env); /* Nothing special for reload */
}
Scheme_Object *scheme_module_name() {
return scheme_false;
}
EOS
]
Assuming that this code is in the file @filepath{hw.c}, the extension
is compiled under Unix with the following two commands:
@commandline{mzc --cgc --cc hw.c}
@commandline{mzc --cgc --ld hw.so hw.o}
(Note that the @DFlag{cgc}, @DFlag{cc}, and @DFlag{ld} flags are each
prefixed by two dashes, not one.)
The @filepath{collects/mzscheme/examples} directory in the PLT
distribution contains additional examples.
@subsection{3m Extensions}
To build an extension to work with PLT Scheme 3m, the CGC instructions
must be extended as follows:
@itemize{
@item{Adjust code to cooperate with the garbage collector as
described in @secref["im:3m"]. Using @|mzc| with the
@as-index{@DFlag{xform}} might convert your code to implement part of
the conversion, as described in @secref["im:3m:mzc"].}
@item{In either your source in the in compiler command line,
@cpp{#define} @cpp{MZ_PRECISE_GC} before including
@filepath{escheme.h}. When using @|mzc| with the @DFlag{cc} and
@as-index{@DFlag{3m}} flags, @cpp{MZ_PRECISE_GC} is automatically
defined.}
@item{Link with @as-index{@filepath{mzdyn3m.o}} (Unix, Mac OS X) or
@as-index{@filepath{mzdyn3m.obj}} (Windows) to create a shared
object. When using @|mzc|, use the @DFlag{ld} and @DFlag{3m} flags
to link to these libraries.}
}
For a relatively simple extension @filepath{hw.c}, the extension is
compiled under Unix for 3m with the following three commands:
@commandline{mzc --xform --cc hw.c}
@commandline{mzc --3m --cc hw.3m.c}
@commandline{mzc --3m --ld hw.so hw.o}
Some examples in @filepath{collects/mzscheme/examples} work with
MzScheme3m in this way. A few examples are manually instrumented, in
which case the @DFlag{xform} step should be skipped.
@; ----------------------------------------------------------------------
@section{Embedding MzScheme into a Program}
@section-index["embedding MzScheme"]
Like creating extensions, the embedding process for PLT Scheme CGC or
PLT Scheme 3m is essentially the same, but the process for PLT Scheme
3m is most easily understood as a variant of the process for
PLT Scheme CGC.
@subsection{CGC Embedding}
To embed PLT Scheme CGC in a program, follow these steps:
@itemize{
@item{Locate or build the PLT Scheme CGC libraries. Since the
standard distribution provides 3m libraries, only, you will most
likely have to build from source.
Under Unix, the libraries are @as-index{@filepath{libmzscheme.a}}
and @as-index{@filepath{libmzgc.a}} (or
@as-index{@filepath{libmzscheme.so}} and
@as-index{@filepath{libmzgc.so}} for a dynamic-library build, with
@as-index{@filepath{libmzscheme.la}} and
@as-index{@filepath{libmzgc.la}} files for use with
@exec{libtool}). Building from source and installing places the
libraries into the installation's @filepath{lib} directory. Be sure
to build the CGC variant, since the default is 3m.
Under Windows, stub libraries for use with Microsoft tools are
@filepath{libmzsch@italic{x}.lib} and
@filepath{libmzgc@italic{x}.lib} (where @italic{x} represents the
version number) are in a compiler-specific directory in
@filepath{plt\lib}. These libraries identify the bindings that are
provided by @filepath{libmzsch@italic{x}.dll} and
@filepath{libmzgc@italic{x}.dll} --- which are typically installed
in @filepath{plt\lib}. When linking with Cygwin, link to
@filepath{libmzsch@italic{x}.dll} and
@filepath{libmzgc@italic{x}.dll} directly. At run time, either
@filepath{libmzsch@italic{x}.dll} and
@filepath{libmzgc@italic{x}.dll} must be moved to a location in the
standard DLL search path, or your embedding application must
``delayload'' link the DLLs and explicitly load them before
use. (@filepath{MzScheme.exe} and @filepath{MrEd.exe} use the latter
strategy.)
Under Mac OS X, dynamic libraries are provided by the
@filepath{PLT_MzScheme} framework, which is typically installed in
@filepath{lib} sub-directory of the installation. Supply
@exec{-framework PLT_MzScheme} to @exec{gcc} when linking, along
with @exec{-F} and a path to the @filepath{lib} directory. Beware
that CGC and 3m libraries are installed as different versions within
a single framework, and installation marks one version or the other
as the default (by setting symbolic links); install only CGC to
simplify accessing the CGC version within the framework. At run
time, either @filepath{PLT_MzScheme.framework} must be moved to a
location in the standard framework search path, or your embedding
executable must provide a specific path to the framework (possibly
an executable-relative path using the Mach-O @tt["@executable_path"]
prefix).}
@item{For each C/C++ file that uses MzScheme library functions,
@cpp{#include} the file @as-index{@filepath{scheme.h}}.
The C preprocessor symbol @cppi{SCHEME_DIRECT_EMBEDDED} is defined
as @cpp{1} when @filepath{scheme.h} is @cpp{#include}d, or as
@cpp{0} when @filepath{escheme.h} is @cpp{#include}d.
The @filepath{scheme.h} file is distributed with the PLT software in
the installation's @filepath{include} directory. Building and
installing from source also places this file in the installation's
@filepath{include} directory.}
@item{In your main program, obtain a global MzScheme environment
@cpp{Scheme_Env*} by calling @cppi{scheme_basic_env}. This function
must be called before any other function in the MzScheme library
(except @cpp{scheme_make_param}).}
@item{Access MzScheme through @cppi{scheme_load},
@cppi{scheme_eval}, and/or other top-level MzScheme functions
described in this manual.}
@item{Compile the program and link it with the MzScheme libraries.}
}
@index['("allocation")]{With} PLT Scheme CGC, Scheme values are
garbage collected using a conservative garbage collector, so pointers
to Scheme objects can be kept in registers, stack variables, or
structures allocated with @cppi{scheme_malloc}. In an embedding
application on some platforms, static variables are also automatically
registered as roots for garbage collection (but see notes below
specific to Mac OS X and Windows).
For example, the following is a simple embedding program which
evaluates all expressions provided on the command line and displays
the results, then runs a @scheme[read]-@scheme[eval]-@scheme[print]
loop:
@verbatim[#<<EOS
#include "scheme.h"
int main(int argc, char *argv[])
{
Scheme_Env *e;
Scheme_Object *curout;
int i;
mz_jmp_buf * volatile save, fresh;
scheme_set_stack_base(NULL, 1); /* required for OS X, only */
e = scheme_basic_env();
curout = scheme_get_param(scheme_current_config(),
MZCONFIG_OUTPUT_PORT);
for (i = 1; i < argc; i++) {
save = scheme_current_thread->error_buf;
scheme_current_thread->error_buf = &fresh;
if (scheme_setjmp(scheme_error_buf)) {
scheme_current_thread->error_buf = save;
return -1; /* There was an error */
} else {
Scheme_Object *v = scheme_eval_string(argv[i], e);
scheme_display(v, curout);
scheme_display(scheme_make_character('\n'), curout);
/* read-eval-print loop, uses initial Scheme_Env: */
scheme_apply(scheme_builtin_value("read-eval-print-loop"),
0, NULL);
scheme_current_thread->error_buf = save;
}
}
return 0;
}
EOS
]
Under Mac OS X, or under Windows when MzScheme is compiled to a DLL
using Cygwin, the garbage collector cannot find static variables
automatically. In that case, @cppi{scheme_set_stack_base} must be
called with a non-zero second argument before calling any
@cpp{scheme_} function.
Under Windows (for any other build mode), the garbage collector finds
static variables in an embedding program by examining all memory
pages. This strategy fails if a program contains multiple Windows
threads; a page may get unmapped by a thread while the collector is
examining the page, causing the collector to crash. To avoid this
problem, call @cpp{scheme_set_stack_base} with a non-zero second
argument before calling any @cpp{scheme_} function.
When an embedding application calls @cpp{scheme_set_stack_base} with a
non-zero second argument, it must register each of its static
variables with @cppi{MZ_REGISTER_STATIC} if the variable can contain a
GCable pointer. For example, if @cpp{e} above is made @cpp{static},
then @cpp{MZ_REGISTER_STATIC(e)} should be inserted before the call to
@cpp{scheme_basic_env}.
When building an embedded MzSchemeCGC to use SenoraGC (SGC) instead of
the default collector, @cpp{scheme_set_stack_base} must be called both
with a non-zero second argument and with a stack-base pointer in the
first argument. See @secref["im:memoryalloc"] for more information.
@subsection{3m Embedding}
MzScheme3m can be embedded mostly the same as MzScheme, as long as the
embedding program cooperates with the precise garbage collector as
described in @secref["im:3m"].
In either your source in the in compiler command line, @cpp{#define}
@cpp{MZ_PRECISE_GC} before including @filepath{scheme.h}. When using
@|mzc| with the @DFlag{cc} and @DFlag{3m} flags, @cpp{MZ_PRECISE_GC}
is automatically defined.
In addition, some library details are different:
@itemize{
@item{Under Unix, the library is just
@as-index{@filepath{libmzscheme3m.a}} (or
@as-index{@filepath{libmzscheme3m.so}} for a dynamic-library build,
with @as-index{@filepath{libmzscheme3m.la}} for use with
@exec{libtool}). There is no separate library for 3m analogous to
CGC's @filepath{libmzgc.a}.}
@item{Under Windows, the stub library for use with Microsoft tools is
@filepath{libmzsch3m@italic{x}.lib} (where @italic{x} represents the
version number). This library identifies the bindings that are
provided by @filepath{libmzsch3m@italic{x}.dll}. There is no
separate library for 3m analogous to CGC's
@filepath{libmzgc@italic{x}.lib}.}
@item{Under Mac OS X, 3m dynamic libraries are provided by the
@filepath{PLT_MzScheme} framework, just as for CGC, but as a version
suffixed with @filepath{_3m}.}
}
For MzScheme3m, an embedding application must call
@cpp{scheme_set_stack_base} with non-zero arguments. Furthermore, the
first argument must be @cpp{&__gc_var_stack__}, where
@cpp{__gc_var_stack__} is bound by a @cpp{MZ_GC_DECL_REG}.
The simple embedding program from the previous section can be
extended to work with either CGC or 3m, dependong on whether
@cpp{MZ_PRECISE_GC} is specified on the compiler's command line:
@verbatim[#<<EOS
#include "scheme.h"
int main(int argc, char *argv[])
{
Scheme_Env *e = NULL;
Scheme_Object *curout = NULL, *v = NULL;
Scheme_Config *config = NULL;
int i;
mz_jmp_buf * volatile save = NULL, fresh;
MZ_GC_DECL_REG(5);
MZ_GC_VAR_IN_REG(0, e);
MZ_GC_VAR_IN_REG(1, curout);
MZ_GC_VAR_IN_REG(2, save);
MZ_GC_VAR_IN_REG(3, config);
MZ_GC_VAR_IN_REG(4, v);
# ifdef MZ_PRECISE_GC
# define STACK_BASE &__gc_var_stack__
# else
# define STACK_BASE NULL
# endif
scheme_set_stack_base(STACK_BASE, 1);
MZ_GC_REG();
e = scheme_basic_env();
config = scheme_current_config();
curout = scheme_get_param(config, MZCONFIG_OUTPUT_PORT);
for (i = 1; i < argc; i++) {
save = scheme_current_thread->error_buf;
scheme_current_thread->error_buf = &fresh;
if (scheme_setjmp(scheme_error_buf)) {
scheme_current_thread->error_buf = save;
return -1; /* There was an error */
} else {
v = scheme_eval_string(argv[i], e);
scheme_display(v, curout);
v = scheme_make_character('\n');
scheme_display(v, curout);
/* read-eval-print loop, uses initial Scheme_Env: */
v = scheme_builtin_value("read-eval-print-loop");
scheme_apply(v, 0, NULL);
scheme_current_thread->error_buf = save;
}
}
MZ_GC_UNREG();
return 0;
}
EOS
]
Strictly speaking, the @cpp{config} and @cpp{v} variables above need not be
registered with the garbage collector, since their values are not needed
across function calls that allocate. That is, the original example could have
been left alone starting with the @cpp{scheme_base_env} call, except for the
addition of @cpp{MZ_GC_UNREG}. The code is much easier to maintain, however,
when all local variables are regsistered and when all temporary values are
put into variables.
@; ----------------------------------------------------------------------
@section{MzScheme and Threads}
MzScheme implements threads for Scheme programs without aid from the
operating system, so that MzScheme threads are cooperative from the
perspective of C code. Under Unix, stand-alone MzScheme uses a single
OS-implemented thread. Under Windows and Mac OS X, stand-alone
MzScheme uses a few private OS-implemented threads for background
tasks, but these OS-implemented threads are never exposed by the
MzScheme API.
In an embedding application, MzScheme can co-exist with additional
OS-implemented threads, but the additional OS threads must not call
any @cpp{scheme_} function. Only the OS thread that originally calls
@cpp{scheme_basic_env} can call @cpp{scheme_} functions. (This
restriction is stronger than saying all calls must be serialized
across threads. MzScheme relies on properties of specific threads to
avoid stack overflow and garbage collection.) When
@cpp{scheme_basic_env} is called a second time to reset the
interpreter, it can be called in an OS thread that is different from
the original call to @cpp{scheme_basic_env}. Thereafter, all calls to
@cpp{scheme_} functions must originate from the new thread.
See @secref["threads"] for more information about threads, including
the possible effects of MzScheme's thread implementation on extension
and embedding C code.
@; ----------------------------------------------------------------------
@section[#:tag "im:unicode"]{MzScheme, Unicode, Characters, and Strings}
A character in MzScheme is a Unicode code point. In C, a character
value has type @cppi{mzchar}, which is an alias for @cpp{unsigned} ---
which is, in turn, 4 bytes for a properly compiled MzScheme. Thus, a
@cpp{mzchar*} string is effectively a UCS-4 string.
Only a few MzScheme functions use @cpp{mzchar*}. Instead, most
functions accept @cpp{char*} strings. When such byte strings are to be
used as a character strings, they are interpreted as UTF-8
encodings. A plain ASCII string is always acceptable in such cases,
since the UTF-8 encoding of an ASCII string is itself.
See also @secref["im:strings"] and @secref["im:encodings"].
@; ----------------------------------------------------------------------
@section[#:tag "im:intsize"]{Integers}
MzScheme expects to be compiled in a mode where @cppi{short} is a
16-bit integer, @cppi{int} is a 32-bit integer, and @cppi{long} has
the same number of bits as @cpp{void*}. The @cppi{mzlonglong} type has
64 bits for compilers that support a 64-bit integer type, otherwise it
is the same as @cpp{long}; thus, @cpp{mzlonglong} tends to match
@cpp{long long}. The @cppi{umzlonglong} type is the unsigned version
of @cpp{mzlonglong}.

View File

@ -0,0 +1,209 @@
#lang scribble/doc
@(require "utils.ss")
@title[#:tag "config"]{Parameterizations}
A @defterm{parameterization} is a set of parameter values. Each thread
has its own initial parameterization, which is extended functionally
and superseded by parameterizations that are attached to a particular
continuation mark.
Parameterization information is stored in a @cppi{Scheme_Config}
record. For the currently executing thread,
@cppi{scheme_current_config} returns the current parameterization.
To obtain parameter values, a @cpp{Scheme_Config} is combined with the
current threads @cpp{Scheme_Thread_Cell_Table}, as stored in the
thread record's @cpp{cell_values} field.
Parameter values for built-in parameters are obtained and modified
(for the current thread) using @cppi{scheme_get_param} and
@cppi{scheme_set_param}. Each parameter is stored as a
@cpp{Scheme_Object *} value, and the built-in parameters are accessed
through the following indices:
@itemize{
@item{@cppi{MZCONFIG_ENV} --- @scheme[current-namespace] (use @cppi{scheme_get_env})}
@item{@cppi{MZCONFIG_INPUT_PORT} --- @scheme[current-input-port]}
@item{@cppi{MZCONFIG_OUTPUT_PORT} --- @scheme[current-output-port]}
@item{@cppi{MZCONFIG_ERROR_PORT} --- @scheme[current-error-port]}
@item{@cppi{MZCONFIG_ERROR_DISPLAY_HANDLER} --- @scheme[error-display-handler]}
@item{@cppi{MZCONFIG_ERROR_PRINT_VALUE_HANDLER} --- @scheme[error-value->string-handler]}
@item{@cppi{MZCONFIG_EXIT_HANDLER} --- @scheme[exit-handler]}
@item{@cppi{MZCONFIG_INIT_EXN_HANDLER} --- @scheme[uncaught-exception-handler]}
@item{@cppi{MZCONFIG_EVAL_HANDLER} --- @scheme[current-eval]}
@item{@cppi{MZCONFIG_LOAD_HANDLER} --- @scheme[current-load]}
@item{@cppi{MZCONFIG_PRINT_HANDLER} --- @scheme[current-print]}
@item{@cppi{MZCONFIG_PROMPT_READ_HANDLER} --- @scheme[current-prompt-read]}
@item{@cppi{MZCONFIG_CAN_READ_GRAPH} --- @scheme[read-accept-graph]}
@item{@cppi{MZCONFIG_CAN_READ_COMPILED} --- @scheme[read-accept-compiled]}
@item{@cppi{MZCONFIG_CAN_READ_BOX} --- @scheme[read-accept-box]}
@item{@cppi{MZCONFIG_CAN_READ_PIPE_QUOTE} --- @scheme[read-accept-bar-quote]}
@item{@cppi{MZCONFIG_PRINT_GRAPH} --- @scheme[print-graph]}
@item{@cppi{MZCONFIG_PRINT_STRUCT} --- @scheme[print-struct]}
@item{@cppi{MZCONFIG_PRINT_BOX} --- @scheme[print-box]}
@item{@cppi{MZCONFIG_CASE_SENS} --- @scheme[read-case-sensitive]}
@item{@cppi{MZCONFIG_SQUARE_BRACKETS_ARE_PARENS} --- @scheme[read-square-brackets-as-parens]}
@item{@cppi{MZCONFIG_CURLY_BRACES_ARE_PARENS} --- @scheme[read-curly-braces-as-parens]}
@item{@cppi{MZCONFIG_ERROR_PRINT_WIDTH} --- @scheme[error-print-width]}
@item{@cppi{MZCONFIG_ALLOW_SET_UNDEFINED} --- @scheme[allow-compile-set!-undefined]}
@item{@cppi{MZCONFIG_CUSTODIAN} --- @scheme[current-custodian]}
@item{@cppi{MZCONFIG_USE_COMPILED_KIND} --- @scheme[use-compiled-file-paths]}
@item{@cppi{MZCONFIG_LOAD_DIRECTORY} --- @scheme[current-load-relative-directory]}
@item{@cppi{MZCONFIG_COLLECTION_PATHS} --- @scheme[current-library-collection-paths]}
@item{@cppi{MZCONFIG_PORT_PRINT_HANDLER} --- @scheme[global-port-print-handler]}
@item{@cppi{MZCONFIG_LOAD_EXTENSION_HANDLER} --- @scheme[current-load-extension]}
}
To get or set a parameter value for a thread other than the current
one, use @cppi{scheme_get_thread_param} and
@cppi{scheme_set_thread_param}, each of which takes a
@cpp{Scheme_Thread_Cell_Table} to use in resolving or setting a
parameter value.
When installing a new parameter with @cpp{scheme_set_param}, no check
is performed on the supplied value to ensure that it is a legal value
for the parameter; this is the responsibility of the caller of
@cpp{scheme_set_param}. Note that Boolean parameters should only be
set to the values @scheme[#t] and @scheme[#f].
New primitive parameter indices are created with
@cppi{scheme_new_param} and implemented with
@cppi{scheme_make_parameter} and @cppi{scheme_param_config}.
@; ----------------------------------------------------------------------
@function[(Scheme_Object* scheme_get_param
[Scheme_Config* config]
[int param_id])]{
Gets the current value (for the current thread) of the parameter
specified by @var{param_id}.}
@function[(Scheme_Object* scheme_set_param
[Scheme_Config* config]
[int param_id]
[Scheme_Object* v])]{
Sets the current value (for the current thread) of the parameter
specified by @var{param_id}.}
@function[(Scheme_Object* scheme_get_thread_param
[Scheme_Config* config]
[Scheme_Thread_Cell_Table* cells]
[int param_id])]{
Like @cpp{scheme_get_param}, but using an arbitrary thread's
cell-value table.}
@function[(Scheme_Object* scheme_set_thread_param
[Scheme_Config* config]
[Scheme_Thread_Cell_Table* cells]
[int param_id]
[Scheme_Object* v])]{
Like @cpp{scheme_set_param}, but using an arbitrary thread's
cell-value table.}
@function[(Scheme_Object* scheme_extend_config
[Scheme_Config* base]
[int param_id]
[Scheme_Object* v])]{
Creates and returns a parameterization that extends @var{base} with a
new value @var{v} (in all threads) for the parameter
@var{param_id}. Use @cpp{scheme_install_config} to make this
configuration active in the current thread.}
@function[(void scheme_install_config
[Scheme_Config* config])]{
Adjusts the current thread's continuation marks to make @var{config}
the current parameterization. Typically, this function is called
after @cpp{scheme_push_continuation_frame} to establish a new
continuation frame, and then @cpp{scheme_pop_continuation_frame}
is called later to remove the frame (and thus the parameterization).}
@function[(Scheme_Thread_Cell_Table* scheme_inherit_cells
[Scheme_Thread_Cell_Table* cells])]{
Creates a new thread-cell-value table, copying values for preserved
thread cells from @var{cells}.}
@function[(int scheme_new_param)]{
Allocates a new primitive parameter index. This function must be
called @italic{before} @cppi{scheme_basic_env}, so it is only
available to embedding applications (i.e., not extensions).}
@function[(Scheme_Object* scheme_register_parameter
[Scheme_Prim* function]
[char* name]
[int exnid])]{
Use this function instead of the other primitive-constructing
functions, like @cpp{scheme_make_prim}, to create a primitive
parameter procedure. See also @cpp{scheme_param_config}, below.
This function is only available to embedding applications (i.e., not
extensions).}
@function[(Scheme_Object* scheme_param_config
[char* name]
[Scheme_Object* param]
[int argc]
[Scheme_Object** argv]
[int arity]
[Scheme_Prim* check]
[char* expected]
[int isbool])]{
Call this procedure in a primitive parameter procedure to implement
the work of getting or setting the parameter. The @var{name} argument
should be the parameter procedure name; it is used to report
errors. The @var{param} argument is a fixnum corresponding to the
primitive parameter index returned by @cpp{scheme_new_param}. The
@var{argc} and @var{argv} arguments should be the un-touched and
un-tested arguments that were passed to the primitive parameter.
Argument-checking is performed within @cpp{scheme_param_config}
using @var{arity}, @var{check}, @var{expected}, and @var{isbool}:
@itemize{
@item{If @var{arity} is non-negative, potential parameter values must
be able to accept the specified number of arguments. The @var{check}
and @var{expected} arguments should be @cpp{NULL}.}
@item{If @var{check} is not @cpp{NULL}, it is called to check a
potential parameter value. The arguments passed to @var{check} are
always @cpp{1} and an array that contains the potential parameter
value. If @var{isbool} is @cpp{0} and @var{check} returns
@cpp{scheme_false}, then a type error is reported using @var{name}
and @var{expected}. If @var{isbool} is @cpp{1}, then a type error is
reported only when @var{check} returns @cpp{NULL} and any
non-@cpp{NULL} return value is used as the actual value to be stored
for the parameter.}
@item{Otherwise, @var{isbool} should be 1. A potential procedure
argument is then treated as a Boolean value.}
}
This function is only available to embedding applications (i.e., not
extensions).}

View File

@ -0,0 +1,918 @@
#lang scribble/doc
@(require "utils.ss")
@title{Ports and the Filesystem}
Ports are represented as Scheme values with the types
@cppi{scheme_input_port_type} and @cppi{scheme_output_port_type}. The
function @cppi{scheme_read} takes an input port value and returns the
next S-expression from the port. The function @cppi{scheme_write}
takes an output port and a value and writes the value to the
port. Other standard low-level port functions are also provided, such
as @cppi{scheme_getc}.
File ports are created with @cppi{scheme_make_file_input_port} and
@cppi{scheme_make_file_output_port}; these functions take a @cpp{FILE
*} file pointer and return a Scheme port. Strings are read or written
with @cppi{scheme_make_byte_string_input_port}, which takes a
nul-terminated byte string, and
@cppi{scheme_make_byte_string_output_port}, which takes no arguments.
The contents of a string output port are obtained with
@cppi{scheme_get_byte_string_output}.
Custom ports, with arbitrary read/write handlers, are created with
@cppi{scheme_make_input_port} and @cppi{scheme_make_output_port}.
When opening a file for any reason using a name provided from Scheme,
use @cppi{scheme_expand_filename} to normalize the filename and
resolve relative paths.
@function[(Scheme_Object* scheme_read
[Scheme_Object* port])]{
@scheme[read]s the next S-expression from the given input port.}
@function[(void scheme_write
[Scheme_Object* obj]
[Scheme_Object* port])]{
@scheme[write]s the Scheme value @var{obj} to the given output port.}
@function[(void scheme_write_w_max
[Scheme_Object* obj]
[Scheme_Object* port]
[int n])]{
Like @cpp{scheme_write}, but the printing is truncated to @var{n} bytes.
(If printing is truncated, the last bytes are printed as ``.''.)}
@function[(void scheme_display
[Scheme_Object* obj]
[Scheme_Object* port])]{
@scheme[display]s the Scheme value @var{obj} to the given output
port.}
@function[(void scheme_display_w_max
[Scheme_Object* obj]
[Scheme_Object* port]
[int n])]{
Like @cpp{scheme_display}, but the printing is truncated to @var{n} bytes.
(If printing is truncated, the last three bytes are printed as ``.''.)}
@function[(void scheme_write_byte_string
[char* str]
[long len]
[Scheme_Object* port])]{
Writes @var{len} bytes of @var{str} to the given output port.}
@function[(void scheme_write_char_string
[mzchar* str]
[long len]
[Scheme_Object* port])]{
Writes @var{len} characters of @var{str} to the given output port.}
@function[(long scheme_put_byte_string
[const-char* who]
[Scheme_Object* port]
[char* str]
[long d]
[long len]
[int rarely_block])]{
Writes @var{len} bytes of @var{str}, starting with the @var{d}th
character. Bytes are written to the given output port, and errors are
reported as from @var{who}.
If @var{rarely_block} is @cpp{0}, the write blocks until all @var{len}
bytes are written, possibly to an internal buffer. If
@var{rarely_block} is @cpp{2}, the write never blocks, and written
bytes are not buffered. If @var{rarely_block} is @cpp{1}, the write
blocks only until at least one byte is written (without buffering) or
until part of an internal buffer is flushed.
Supplying @cpp{0} for @var{len} corresponds to a buffer-flush
request. If @var{rarely_block} is @cpp{2}, the flush request is
non-blocking, and if @var{rarely_block} is @cpp{0}, it is blocking.
(A @var{rarely_block} of @cpp{1} is the same as @cpp{0} in this case.)
The result is @cpp{-1} if no bytes are written from @var{str} and
unflushed bytes remain in the internal buffer. Otherwise, the return
value is the number of written characters.}
@function[(long scheme_put_char_string
[const-char* who]
[Scheme_Object* port]
[char* str]
[long d]
[long len])]{
Like @cpp{scheme_put_byte_string}, but for a @cpp{mzchar} string, and
without the non-blocking option.}
@function[(char* scheme_write_to_string
[Scheme_Object* obj]
[long* len])]{
Prints the Scheme value @var{obj} using @scheme[write] to a newly
allocated string. If @var{len} is not @cpp{NULL}, @cpp{*@var{len}} is
set to the length of the bytes string.}
@function[(void scheme_write_to_string_w_max
[Scheme_Object* obj]
[long* len]
[int n])]{
Like @cpp{scheme_write_to_string}, but the string is truncated to
@var{n} bytes. (If the string is truncated, the last three bytes are
``.''.)}
@function[(char* scheme_display_to_string
[Scheme_Object* obj]
[long* len])]{
Prints the Scheme value @var{obj} using @scheme[display] to a newly
allocated string. If @var{len} is not @cpp{NULL}, @cpp{*@var{len}} is
set to the length of the string.}
@function[(void scheme_display_to_string_w_max
[Scheme_Object* obj]
[long* len]
[int n])]{
Like @cpp{scheme_display_to_string}, but the string is truncated to
@var{n} bytes. (If the string is truncated, the last three bytes are
``.''.)}
@function[(void scheme_debug_print
[Scheme_Object* obj])]{
Prints the Scheme value @var{obj} using @scheme[write] to the main
thread's output port.}
@function[(void scheme_flush_output
[Scheme_Object* port])]{
If @var{port} is a file port, a buffered data is written to the file.
Otherwise, there is no effect. @var{port} must be an output port.}
@function[(int scheme_get_byte
[Scheme_Object* port])]{
Get the next byte from the given input port. The result can be @cpp{EOF}.}
@function[(int scheme_getc
[Scheme_Object* port])]{
Get the next character from the given input port (by decoding bytes as UTF-8).
The result can be @cpp{EOF}.}
@function[(int scheme_peek_byte
[Scheme_Object* port])]{
Peeks the next byte from the given input port. The result can be @cpp{EOF}.}
@function[(int scheme_peekc
[Scheme_Object* port])]{
Peeks the next character from the given input port (by decoding bytes as UTF-8).
The result can be @cpp{EOF}.}
@function[(int scheme_peek_byte_skip
[Scheme_Object* port]
[Scheme_Object* skip])]{
Like @cpp{scheme_peek_byte}, but with a skip count. The result can be @cpp{EOF}.}
@function[(int scheme_peekc_skip
[Scheme_Object* port]
[Scheme_Object* skip])]{
Like @cpp{scheme_peekc}, but with a skip count. The result can be @cpp{EOF}.}
@function[(long scheme_get_byte_string
[const-char* who]
[Scheme_Object* port]
[char* buffer]
[int offset]
[long size]
[int only_avail]
[int peek]
[Scheme_Object* peek_skip])]{
Gets multiple bytes at once from a port, reporting errors with the
name @var{who}. The @var{size} argument indicates the number of
requested bytes, to be put into the @var{buffer} array starting at
@var{offset}. The return value is the number of bytes actually read,
or @cpp{EOF} if an end-of-file is encountered without reading any
bytes.
If @var{only_avail} is @cpp{0}, then the function blocks until
@var{size} bytes are read or an end-of-file is reached. If
@var{only_avail} is @cpp{1}, the function blocks only until at least
one byte is read. If @var{only_avail} is @cpp{2}, the function never
blocks. If @var{only_avail} is @cpp{-1}, the function blocks only
until at least one byte is read but also allows breaks (with the
guarantee that bytes are read or a break is raised, but not both).
If @var{peek} is non-zero, then the port is peeked instead of
read. The @var{peek_skip} argument indicates a portion of the input
stream to skip as a non-negative, exact integer (fixnum or bignum). In
this case, an @var{only_avail} value of @cpp{1} means to continue the
skip until at least one byte can be returned, even if it means
multiple blocking reads to skip bytes.
If @var{peek} is zero, then @var{peek_skip} should be either
@cpp{NULL} (which means zero) or the fixnum zero.}
@function[(long scheme_get_char_string
[const-char* who]
[Scheme_Object* port]
[char* buffer]
[int offset]
[long size]
[int peek]
[Scheme_Object* peek_skip])]{
Like @cpp{scheme_get_byte_string}, but for characters (by decoding
bytes as UTF-8), and without the non-blocking option.}
@function[(long scheme_get_bytes
[Scheme_Object* port]
[long size]
[char* buffer]
[int offset])]{
For backward compatibility: calls @cpp{scheme_get_byte_string} in
essentially the obvious way with @var{only_avail} as @cpp{0}; if
@var{size} is negative, then it reads @var{-size} bytes with
@var{only_avail} as @cpp{1}.}
@function[(void scheme_ungetc
[int ch]
[Scheme_Object* port])]{
Puts the byte @var{ch} back as the next character to be read from the
given input port. The character need not have been read from
@var{port}, and @cpp{scheme_ungetc} can be called to insert up to five
characters at the start of @var{port}.
Use @cpp{scheme_get_byte} followed by @cpp{scheme_ungetc} only when
your program will certainly call @cpp{scheme_get_byte} again to
consume the byte. Otherwise, use @cpp{scheme_peek_byte}, because some
a port may implement peeking and getting differently.}
@function[(int scheme_byte_ready
[Scheme_Object* port])]{
Returns 1 if a call to @cpp{scheme_get_byte} is guaranteed not to
block for the given input port.}
@function[(int scheme_char_ready
[Scheme_Object* port])]{
Returns 1 if a call to @cpp{scheme_getc} is guaranteed not to block
for the given input port.}
@function[(void scheme_need_wakeup
[Scheme_Object* port]
[void* fds])]{
Requests that appropriate bits are set in @var{fds} to specify which
file descriptors(s) the given input port reads from. (@var{fds} is
sortof a pointer to an @cppi{fd_set} struct; see
@secref["blockednonmainel"].)}
@function[(long scheme_tell
[Scheme_Object* port])]{
Returns the current read position of the given input port, or the
current file position of the given output port.}
@function[(long scheme_tell_line
[Scheme_Object* port])]{
Returns the current read line of the given input port. If lines are
not counted, -1 is returned.}
@function[(void scheme_count_lines
[Scheme_Object* port])]{
Turns on line-counting for the given input port. To get accurate line
counts, call this function immediately after creating a port.}
@function[(long scheme_set_file_position
[Scheme_Object* port]
[long pos])]{
Sets the file position of the given input or output port (from the
start of the file). If the port does not support position setting, an
exception is raised.}
@function[(void scheme_close_input_port
[Scheme_Object* port])]{
Closes the given input port.}
@function[(void scheme_close_output_port
[Scheme_Object* port])]{
Closes the given output port.}
@function[(int scheme_get_port_file_descriptor
[Scheme_Object* port]
[long* fd])]{
Fills @cpp{*@var{fd}} with a file-descriptor value for @var{port} if
one is available (i.e., the port is a file-stream port and it is not
closed). The result is non-zero if the file-descriptor value is
available, zero otherwise. Under Windows, a ``file dscriptor'' is a
file @cpp{HANDLE}.}
@function[(long scheme_get_port_fd
[Scheme_Object* port]
[Scheme_Object* port]
[long* s])]{
Fills @cpp{*@var{s}} with a socket value for @var{port} if one is
available (i.e., the port is a TCP port and it is not closed). The
result is non-zero if the socket value is available, zero
otherwise. Under Windows, a socket value has type @cpp{SOCKET}.}
@function[(Scheme_Object* scheme_make_port_type
[char* name])]{
Creates a new port subtype.}
@function[(Scheme_Input_Port* scheme_make_input_port
[Scheme_Object* subtype]
[void* data]
[Scheme_Object* name]
[Scheme_Get_String_Fun get_bytes_fun]
[Scheme_Peek_String_Fun peek_bytes_fun]
[Scheme_Progress_Evt_Fun progress_evt_fun]
[Scheme_Peeked_Read_Fun peeked_read_fun]
[Scheme_In_Ready_Fun char_ready_fun]
[Scheme_Close_Input_Fun close_fun]
[Scheme_Need_Wakeup_Input_Fun need_wakeup_fun]
[int must_close])]{
Creates a new input port with arbitrary control functions. The
@var{subtype} is an arbitrary value to distinguish the port's class.
The pointer @var{data} will be installed as the port's user data,
which can be extracted/set with the @cppi{SCHEME_INPORT_VAL} macro.
The @var{name} object is used as the port's name (for
@scheme[object-name] and as the default source name for
@scheme[read-syntax]).
If @var{must_close} is non-zero, the new port will be registered with
the current custodian, and @var{close_fun} is guaranteed to be called
before the port is garbage-collected.
Although the return type of @cpp{scheme_make_input_port} is
@cppi{Scheme_Input_Port*}, it can be cast into a @cpp{Scheme_Object*}.
The functions are as follows.
@subfunction[(long get_bytes_fun
[Scheme_Input_Port* port]
[char* buffer]
[long offset]
[long size]
[int nonblock]
[Scheme_Object* unless])]{
Reads bytes into @var{buffer}, starting from @var{offset}, up to
@var{size} bytes (i.e., @var{buffer} is at least
@var{offset} plus @var{size} long). If @var{nonblock} is @cpp{0},
then the function can block indefinitely, but it should return
when at least one byte of data is available. If @var{nonblock} is
@cpp{1}, the function should never block. If @var{nonblock} is
@cpp{2}, a port in unbuffered mode should return only bytes
previously forced to be buffered; other ports should treat a
@var{nonblock} of @cpp{2} like @cpp{1}. If @var{nonblock} is
@cpp{-1}, the function can block, but should enable breaks while
blocking. The function should return @cpp{0} if no bytes are ready
in non-blocking mode. It should return @cpp{EOF} if an end-of-file
is reached (and no bytes were read into @var{buffer}). Otherwise,
the function should return the number of read bytes. The function
can raise an exception to report an error.
The @var{unless} argument will be non-@cpp{NULL} only when
@var{nonblocking} is non-zero (except as noted below), and only if
the port supports progress events. If @var{unless} is
non-@cpp{NULL} and @cpp{SCHEME_CDR(@var{unless})} is
non-@cpp{NULL}, the latter is a progress event specific to the
port. The @var{get_bytes_fun} function should return
@cppi{SCHEME_UNLESS_READY} instead of reading bytes if the event
in @var{unless} becomes ready before bytes can be read. In
particular, @var{get_bytes_fun} should check the event in
@var{unless} before taking any action, and it should check the
event in @var{unless} after any operation that may allow Scheme
thread swaps. If the read must block, then it should unblock if
the event in @var{unless} becomes ready.
If @cpp{scheme_progress_evt_via_get} is used for
@var{progress_evt_fun}, then @var{unless} can be non-@cpp{NULL}
even when @var{nonblocking} is @cpp{0}. In all modes,
@var{get_bytes_fun} must call @cpp{scheme_unless_ready} to check
@var{unless_evt}. Furthermore, after any potentially
thread-swapping operation, @var{get_bytes_fun} must call
@cpp{scheme_wait_input_allowed}, because another thread may be
attempting to commit, and @var{unless_evt} must be checked after
@cpp{scheme_wait_input_allowed} returns. To block, the port should
use @cpp{scheme_block_until_unless} instead of
@cpp{scheme_block_until}. Finally, in blocking mode,
@var{get_bytes_fun} must return after immediately reading data,
without allowing a Scheme thread swap.}
@subfunction[(long peek_bytes_fun
[Scheme_Input_Port* port]
[char* buffer]
[long offset]
[long size]
[Scheme_Object* skip]
[int nonblock]
[Scheme_Object* unless_evt])]{
Can be @cpp{NULL} to use a default implementation of peeking that
uses @var{get_bytes_fun}. Otherwise, the protocol is the same as
for @var{get_bytes_fun}, except that an extra @var{skip} argument
indicates the number of input elements to skip (but @var{skip}
does not apply to @var{buffer}). The @var{skip} value will be a
non-negative exact integer, either a fixnum or a bignum.}
@subfunction[(Scheme_Object* progress_evt_fun
[Scheme_Input_Port* port])]{
Called to obtain a progress event for the port, such as for
@scheme[port-progress-evt]. This function can be @cpp{NULL} if the
port does not support progress events. Use
@cpp{progress_evt_via_get} to obtain a default implementation, in
which case @var{peeked_read_fun} should be
@cpp{peeked_read_via_get}, and @var{get_bytes_fun} and
@var{peek_bytes_fun} should handle @var{unless} as described
above.}
@subfunction[(int peeked_read_fun
[Scheme_Input_Port* port]
[long amount]
[Scheme_Object* unless_evt]
[Scheme_Object* target_ch])]{
Called to commit previously peeked bytes, just like the sixth
argument to @scheme[make-input-port]. Use
@cpp{peeked_read_via_get} for the default implementation of
commits when @var{progress_evt_fun} is
@cpp{progress_evt_via_get}.}
@subfunction[(int char_ready_fun
[Scheme_Input_Port* port])]{
Returns @cpp{1} when a non-blocking @var{get_bytes_fun} will
return bytes or an @cpp{EOF}.}
@subfunction[(void close_fun
[Scheme_Input_Port* port])]{
Called to close the port. The port is not considered closed until
the function returns.}
@subfunction[(void need_wakeup_fun
[Scheme_Input_Port* port]
[void* fds])]{
Called when the port is blocked on a read; @var{need_wakeup_fun}
should set appropriate bits in @var{fds} to specify which file
descriptor(s) it is blocked on. The @var{fds} argument is
conceptually an array of three @cppi{fd_set} structs (one for
read, one for write, one for exceptions), but manipulate this
array using @cppi{scheme_get_fdset} to get a particular element of
the array, and use @cppi{MZ_FD_XXX} instead of @cpp{FD_XXX} to
manipulate a single ``@cpp{fd_set}''. Under Windows, the first
``@cpp{fd_set}'' can also contain OS-level semaphores or other
handles via @cpp{scheme_add_fd_handle}.}
}
@function[(Scheme_Output_Port* scheme_make_output_port
[Scheme_Object* subtype]
[void* data]
[Scheme_Object* name]
[Scheme_Write_String_Evt_Fun write_bytes_evt_fun]
[Scheme_Write_String_Fun write_bytes_fun]
[Scheme_Out_Ready_Fun char_ready_fun]
[Scheme_Close_Output_Fun close_fun]
[Scheme_Need_Wakeup_Output_Fun need_wakeup_fun]
[Scheme_Write_Special_Fun write_special_fun]
[Scheme_Write_Special_Evt_Fun write_special_evt_fun]
[Scheme_Write_Special_Fun write_special_fun]
[int must_close])]{
Creates a new output port with arbitrary control functions. The
@var{subtype} is an arbitrary value to distinguish the port's class.
The pointer @var{data} will be installed as the port's user data,
which can be extracted/set with the @cppi{SCHEME_OUTPORT_VAL}
macro. The @var{name} object is used as the port's name.
If @var{must_close} is non-zero, the new port will be registered with
the current custodian, and @var{close_fun} is guaranteed to be called
before the port is garbage-collected.
Although the return type of @cpp{scheme_make_output_port} is
@cppi{Scheme_Output_Port*}, it can be cast into a
@cpp{Scheme_Object*}.
The functions are as follows.
@subfunction[(long write_bytes_evt_fun
[Scheme_Output_Port* port]
[const-char* buffer]
[long offset]
[long size])]{
Returns an event that writes up to @var{size} bytes atomically
when event is chosen in a synchronization. Supply @cpp{NULL} if
bytes cannot be written atomically, or supply
@cppi{scheme_write_evt_via_write} to use the default
implementation in terms of @cpp{write_bytes_fun} (with
@var{rarely_block} as @cpp{2}).}
@subfunction[(long write_bytes_fun
[Scheme_Output_Port* port]
[const-char* buffer]
[long offset]
[long size]
[int rarely_block]
[int enable_break])]{
Write bytes from @var{buffer}, starting from @var{offset}, up to
@var{size} bytes (i.e., @var{buffer} is at least
@var{offset} plus @var{size} long). If @var{rarely_block} is @cpp{0},
then the function can block indefinitely, and it can buffer
output. If @var{rarely_block} is @cpp{2}, the function should
never block, and it should not buffer output. If
@var{rarely_block} is @cpp{1}, the function should not buffer
data, and it should block only until writing at least one byte,
either from @var{buffer} or an internal buffer. The function
should return the number of bytes from @var{buffer} that were
written; when @var{rarely_block} is non-zero and bytes remain in
an internal buffer, it should return @cpp{-1}. The @var{size}
argument can be @cpp{0} when @var{rarely_block} is @cpp{0} for a
blocking flush, and it can be @cpp{0} if @var{rarely_block} is
@cpp{2} for a non-blocking flush. If @var{enable_break} is true,
then it should enable breaks while blocking. The function can
raise an exception to report an error.}
@subfunction[(int char_ready_fun
[Scheme_Output_Port* port])]{
Returns @cpp{1} when a non-blocking @var{write_bytes_fun} will
write at least one byte or flush at least one byte from
the port's internal buffer.}
@subfunction[(void close_fun
[Scheme_Output_Port* port])]{
Called to close the port. The port is not considered closed until
the function returns. This function is allowed to block (usually
to flush a buffer) unless
@cpp{scheme_close_should_force_port_closed} returns a non-zero
result, in which case the function must return without blocking.}
@subfunction[(void need_wakeup_fun
[Scheme_Output_Port* port]
[void* fds])]{
Called when the port is blocked on a write; @var{need_wakeup_fun}
should set appropriate bits in @var{fds} to specify which file
descriptor(s) it is blocked on. The @var{fds} argument is
conceptually an array of three @cppi{fd_set} structs (one for
read, one for write, one for exceptions), but manipulate this
array using @cppi{scheme_get_fdset} to get a particular element of
the array, and use @cppi{MZ_FD_XXX} instead of @cpp{FD_XXX} to
manipulate a single ``@cpp{fd_set}''. Under Windows, the first
``@cpp{fd_set}'' can also contain OS-level semaphores or other
handles via @cpp{scheme_add_fd_handle}.}
@subfunction[(int write_special_evt_fun
[Scheme_Output_Port* port]
[Scheme_Object* v])]{
Returns an event that writes @var{v} atomically when event is
chosen in a synchronization. Supply @cpp{NULL} if specials cannot
be written atomically (or at all), or supply
@cppi{scheme_write_special_evt_via_write_special} to use the
default implementation in terms of @cpp{write_special_fun} (with
@var{non_block} as @cpp{1}).}
@subfunction[(int write_special_fun
[Scheme_Output_Port* port]
[Scheme_Object* v]
[int non_block])]{
Called to write the special value @var{v} for
@scheme[write-special] (when @var{non_block} is @cpp{0}) or
@scheme[write-special-avail*] (when @var{non_block} is
@cpp{1}). If @cpp{NULL} is supplied instead of a function pointer,
then @scheme[write-special] and @scheme[write-special-avail*]
produce an error for this port.}
}
@function[(Scheme_Object* scheme_make_file_input_port
[FILE* fp])]{
Creates a Scheme input file port from an ANSI C file pointer. The file
must never block on reads.}
@function[(Scheme_Object* scheme_open_input_file
[const-char* filename]
[const-char* who])]{
Opens @var{filename} for reading. In an exception is raised, the
exception message uses @var{who} as the name of procedure that raised
the exception.}
@function[(Scheme_Object* scheme_make_named_file_input_port
[FILE* fp]
[Scheme_Object* name])]{
Creates a Scheme input file port from an ANSI C file pointer. The file
must never block on reads. The @var{name} argument is used as the
port's name.}
@function[(Scheme_Object* scheme_open_output_file
[const-char* filename]
[const-char* who])]{
Opens @var{filename} for writing in @scheme['truncate/replace] mode. If
an exception is raised, the exception message uses @var{who} as the
name of procedure that raised the exception.}
@function[(Scheme_Object* scheme_make_file_output_port
[FILE* fp])]{
Creates a Scheme output file port from an ANSI C file pointer. The
file must never block on writes.}
@function[(Scheme_Object* scheme_make_fd_input_port
[int fd]
[Scheme_Object* name]
[int regfile]
[int win_textmode]
[int fd]
[Scheme_Object* name]
[int regfile]
[int win_textmode]
[int read_too]
[long s]
[const-char* name]
[int close]
[Scheme_Object** inp]
[Scheme_Object** outp]
[char* str])]{
Creates a Scheme input port from a byte string; successive
@scheme[read-char]s on the port return successive bytes in the
string.}
@function[(Scheme_Object* scheme_make_byte_string_output_port)]{
Creates a Scheme output port; all writes to the port are kept in a byte string,
which can be obtained with @cpp{scheme_get_byte_string_output}.}
@function[(char* scheme_get_byte_string_output
[Scheme_Object* port])]{
Returns (in a newly allocated byte string) all data that has been
written to the given string output port so far. (The returned string
is nul-terminated.)}
@function[(char* scheme_get_sized_byte_string_output
[Scheme_Object* port]
[long* len])]{
Returns (in a newly allocated byte string) all data that has been
written to the given string output port so far and fills in
@cpp{*len} with the length of the string in bytes (not including the
nul terminator).}
@function[(void scheme_pipe
[Scheme_Object** read]
[Scheme_Object** write])]{
Creates a pair of ports, setting @cpp{*@var{read}} and
@cpp{*@var{write}}; data written to @cpp{*@var{write}} can be read
back out of @cpp{*@var{read}}. The pipe can store arbitrarily many
unread characters,}
@function[(void scheme_pipe_with_limit
[Scheme_Object** read]
[Scheme_Object** write]
[int limit])]{
Like @cpp{scheme_pipe} is @var{limit} is @cpp{0}. If @var{limit} is
positive, creates a pipe that stores at most @var{limit} unread
characters, blocking writes when the pipe is full.}
@function[(Scheme_Input_Port* scheme_input_port_record
[Scheme_Object* port])]{
Returns the input-port record for @var{port}, which may be either a
raw-port object with type @cpp{scheme_input_port_type} or a structure
with the @scheme[prop:input-port] property.}
@function[(Scheme_Output_Port* scheme_output_port_record
[Scheme_Object* port])]{
Returns the output-port record for @var{port}, which may be either a
raw-port object with type @cpp{scheme_output_port_type} or a structure
with the @scheme[prop:output-port] property.}
@function[(int scheme_file_exists
[char* name])]{
Returns 1 if a file by the given name exists, 0 otherwise. If
@var{name} specifies a directory, FALSE is returned.
The @var{name} should be already expanded.}
@function[(int scheme_directory_exists
[char* name])]{
Returns 1 if a directory by the given name exists, 0 otherwise. The
@var{name} should be already expanded.}
@function[(char* scheme_expand_filename
[const-char* name]
[int len]
[const-char* where]
[int* expanded]
[int checks])]{
Cleanses the pathname @var{name} (see @scheme[cleanse-path]) and
resolves relative paths with respect to the current directory
parameter. The @var{len} argument is the length of the input string;
if it is -1, the string is assumed to be null-terminated. The
@var{where} argument is used to raise an exception if there is an
error in the filename; if this is @cpp{NULL}, an error is not reported
and @cpp{NULL} is returned instead. If @var{expanded} is not
@cpp{NULL}, *@var{expanded} is set to 1 if some expansion takes place,
or 0 if the input name is simply returned.
If @var{guards} is not @cpp{0}, then @cpp{scheme_security_check_file}
(see @secref["security"]) is called with @var{name}, @var{where}, and
@var{checks} (which implies that @var{where} should never be
@cpp{NULL} unless @var{guards} is @cpp{0}). Normally, @var{guards}
should be @cpp{SCHEME_GUARD_FILE_EXISTS} at a minimum. Note that a
failed access check will result in an exception.}
@function[(char* scheme_expand_string_filename
[Scheme_Object* name]
[const-char* where]
[int* expanded]
[int checks])]{
Like @cpp{scheme_expand_string}, but given a @var{name} that can be a
character string or a path value.}
@function[(Scheme_Object* scheme_char_string_to_path
[Scheme_Object* s])]{
Converts a Scheme character string into a Scheme path value.}
@function[(Scheme_Object* scheme_path_to_char_string
[Scheme_Object* s])]{
Converts a Scheme path value into a Scheme character string.}
@function[(Scheme_Object* scheme_make_path
[char* bytes])]{
Makes a path value given a byte string. The @var{bytes} string is copied.}
@function[(Scheme_Object* scheme_make_path_without_copying
[char* bytes])]{
Like @cpp{scheme_make_path}, but the string is not copied.}
@function[(Scheme_Object* scheme_make_sized_path
[char* bytes]
[long len]
[int copy])]{
Makes a path whose byte form has size @var{len}. A copy of @var{bytes}
is made if @var{copy} is not 0. The string @var{bytes} should contain
@var{len} bytes, and if @var{copy} is zero, @var{bytes} must have a
nul terminator in addition. If @var{len} is negative, then the
nul-terminated length of @var{bytes} is used for the length.}
@function[(Scheme_Object* scheme_make_sized_path
[char* bytes]
[long d]
[long len]
[int copy])]{
Like @cpp{scheme_make_sized_path}, except the @var{len} bytes start
from position @var{d} in @var{bytes}. If @var{d} is non-zero, then
@var{copy} must be non-zero.}
@function[(char* scheme_build_mac_filename
[FSSpec* spec]
[int isdir])]{
Mac OS X only: Converts an @cppi{FSSpec} record (defined by Mac OS X)
into a pathname string. If @var{spec} contains only directory
information (via the @cpp{vRefNum} and @cpp{parID} fields),
@var{isdir} should be @cpp{1}, otherwise it should be @cpp{0}.}
@function[(int scheme_mac_path_to_spec
[const-char* filename]
[FSSpec* spec]
[long* type])]{
Mac OS X only: Converts a pathname into an @cppi{FSSpec} record
(defined by Mac OS X), returning @cpp{1} if successful and @cpp{0}
otherwise. If @var{type} is not @cpp{NULL} and @var{filename} is a
file that exists, @var{type} is filled with the file's four-character
Mac OS X type. If @var{type} is not @cpp{NULL} and @var{filename} is
not a file that exists, @var{type} is filled with @cpp{0}.}
@function[(char* scheme_os_getcwd
[char* buf]
[int buflen]
[int* actlen]
[int noexn])]{
Gets the @as-index{current working directory} according to the
operating system. This is separate from MzScheme's current directory
parameter.
The directory path is written into @var{buf}, of length @var{buflen},
if it fits. Otherwise, a new (collectable) string is allocated for the
directory path. If @var{actlen} is not @cpp{NULL}, *@var{actlen} is
set to the length of the current directory path. If @var{noexn} is
no 0, then an exception is raised if the operation fails.}
@function[(int scheme_os_setcwd
[char* buf]
[int noexn])]{
Sets the current working directory according to the operating system. This
is separate from MzScheme's current directory parameter.
If @var{noexn} is not 0, then an exception is raised if the operation
fails.}
@function[(char* scheme_format
[mzchar* format]
[int flen]
[int argc]
[Scheme_Object** argv]
[long* rlen])]{
Creates a string like MzScheme's @scheme[format] procedure, using the
format string @var{format} (of length @var{flen}) and the extra
arguments specified in @var{argc} and @var{argv}. If @var{rlen} is not
@cpp{NULL}, @cpp{*@var{rlen}} is filled with the length of the
resulting string.}
@function[(void scheme_printf
[char* format]
[int flen]
[int argc]
[Scheme_Object** argv])]{
Writes to the current output port like MzScheme's @scheme[printf]
procedure, using the format string @var{format} (of length @var{flen})
and the extra arguments specified in @var{argc} and @var{argv}.}
@function[(char* scheme_format_utf8
[char* format]
[int flen]
[int argc]
[Scheme_Object** argv]
[long* rlen])]{
Like @cpp{scheme_format}, but takes a UTF-8-encoding byte string.}
@function[(void scheme_printf_utf8
[char* format]
[int flen]
[int argc]
[Scheme_Object** argv])]{
Like @cpp{scheme_printf}, but takes a UTF-8-encoding byte string.}
@function[(int scheme_close_should_force_port_closed)]{
This function must be called by the close function for a port created
with @cpp{scheme_make_output_port}.}

View File

@ -0,0 +1,134 @@
#lang scribble/doc
@(require "utils.ss")
@title{Procedures}
A @defterm{primitive procedure} is a Scheme-callable procedure that is
implemented in C. Primitive procedures are created in Scheme with
the function @cppi{scheme_make_prim_w_arity}, which takes a C function
pointer, the name of the primitive, and information about the number
of Scheme arguments that it takes; it returns a Scheme procedure
value.
The C function implementing the procedure must take two arguments: an
integer that specifies the number of arguments passed to the
procedure, and an array of @cpp{Scheme_Object*} arguments. The number
of arguments passed to the function will be checked using the arity
information. (The arity information provided to
@cpp{scheme_make_prim_w_arity} is also used for the Scheme
@scheme[arity] procedure.) The procedure implementation is not allowed
to mutate the input array of arguments, although it may mutate the
arguments themselves when appropriate (e.g., a fill in a vector
argument).
The function @cppi{scheme_make_prim_closure_w_arity} is similar to
@cpp{scheme_make_prim_w_arity}, but it takes an additional count and
@cpp{Scheme_Object*} array that is copied into the created procedure;
the procedure is passed back to the C function when the closure is
invoked. In this way, closure-like data from the C world can be
associated with the primitive procedure.
The function @cppi{scheme_make_closed_prim_w_arity} is similar to
@cpp{scheme_make_prim_closure_w_arity}, but it uses an older calling
convention for passing closure data.
To work well with Scheme threads, a C function that performs
substantial or unbounded work should occasionally call
@cpp{SCHEME_USE_FUEL}; see @secref["usefuel"] for details.
@; ----------------------------------------------------------------------
@function[(Scheme_Object* scheme_make_prim_w_arity
[Scheme_Prim* prim]
[char* name]
[int mina]
[int maxa])]{
Creates a primitive procedure value, given the C function pointer
@var{prim}. The form of @var{prim} is defined by:
@verbatim[#<<EOS
typedef Scheme_Object *(Scheme_Prim)(int argc,
Scheme_Object **argv);
EOS
]
The value @var{mina} should be the minimum number of arguments that
must be supplied to the procedure. The value @var{maxa} should be the
maximum number of arguments that can be supplied to the procedure, or
-1 if the procedure can take arbitrarily many arguments. The
@var{mina} and @var{maxa} values are used for automatically checking
the argument count before the primitive is invoked, and also for the
Scheme @indexed-scheme[arity] procedure. The @var{name} argument is
used to report application arity errors at run-time.}
@function[(Scheme_Object* scheme_make_folding_prim
[Scheme_Prim* prim]
[char* name]
[int mina]
[int maxa]
[short folding])]{
Like @cpp{scheme_make_prim_w_arity}, but if @var{folding} is non-zero,
the compiler assumes that an application of the procedure to constant
values can be folded to a constant. For example, @scheme[+],
@scheme[zero?], and @scheme[string-length] are folding primitives, but
@scheme[display] and @scheme[cons] are not.}
@function[(Scheme_Object* scheme_make_prim
[Scheme_Prim* prim])]{
Same as @cppi{scheme_make_prim_w_arity}, but the arity (0, -1) and the
name ``UNKNOWN'' is assumed. This function is provided for backward
compatibility only.}
@function[(Scheme_Object* scheme_make_prim_closure_w_arity
[Scheme_Prim_Closure_Proc* prim]
[int c]
[Scheme_Object* vals]
[char* name]
[int mina]
[int maxa])]{
Creates a primitive procedure value that includes the @var{c} values
in @var{vals}; when the C function @var{prim} is invoked, the
generated primitive is passed as the last parameter. The form of
@var{prim} is defined by:
@verbatim[#<<EOS
typedef
Scheme_Object *(Scheme_Prim_Closure_Proc)(int argc,
Scheme_Object **argv,
Scheme_Object *prim);
EOS
]
The macro @cppi{SCHEME_PRIM_CLOSURE_ELS} takes a primitive-closure
object and returns an array with the same length and content as
@var{vals}. (3m: see @secref["im:3m"] for a caution about
@cppi{SCHEME_PRIM_CLOSURE_ELS}.)}
@function[(Scheme_Object* scheme_make_closed_prim_w_arity
[Scheme_Closed_Prim* prim]
[void* data]
[char* name]
[int mina]
[int maxa])]{
Creates an old-style primitive procedure value; when the C function
@var{prim} is invoked, @var{data} is passed as the first parameter.
The form of @var{prim} is defined by:
@verbatim[#<<EOS
typedef
Scheme_Object *(Scheme_Closed_Prim)(void *data, int argc,
Scheme_Object **argv);
EOS
]}
@function[(Scheme_Object* scheme_make_closed_prim
[Scheme_Closed_Prim* prim]
[void* data])]{
Creates a closed primitive procedure value without arity information.
This function is provided for backward compatibility only.}

View File

@ -0,0 +1,60 @@
#lang scribble/doc
@(require "utils.ss")
@title[#:tag "security"]{Security Guards}
Before a primitive procedure accesses the filesystem or creates a
network connection, it should first consult the current security guard
to determine whether such access is allowed for the current thread.
File access is normally preceded by a call to
@cppi{scheme_expand_filename}, which accepts flags to indicate the
kind of filesystem access needed, so that the security guard is
consulted automatically.
An explicit filesystem-access check can be made by calling
@cpp{scheme_security_check_file}. Similarly, an explicit
network-access check is performed by calling
@cpp{scheme_security_check_network}.
@; ----------------------------------------------------------------------
@function[(void scheme_security_check_file
[const-char* who]
[char* filename]
[int guards])]{
Consults the current security manager to determine whether access is
allowed to @var{filename}. The @var{guards} argument should be a
bitwise combination of the following:
@itemize{
@item{@cppi{SCHEME_GUARD_FILE_READ}}
@item{@cppi{SCHEME_GUARD_FILE_WRITE}}
@item{@cppi{SCHEME_GUARD_FILE_EXECUTE}}
@item{@cppi{SCHEME_GUARD_FILE_DELETE}}
@item{@cppi{SCHEME_GUARD_FILE_EXISTS} (do not combine with other values)}
}
The @var{filename} argument can be @cpp{NULL} (in which case
@scheme[#f] is sent to the security manager's procedure), and
@var{guards} should be @cppi{SCHEME_GUARD_FILE_EXISTS} in that case.
If access is denied, an exception is raised.}
@function[(void scheme_security_check_network
[const-char* who]
[char* host]
[int portno])]{
Consults the current security manager to determine whether access is
allowed for creating a client connection to @var{host} on port number
@var{portno}. If @var{host} is @cpp{NULL}, the security manager is
consulted for creating a server at port number @var{portno}.
If access is denied, an exception is raised.}

View File

@ -0,0 +1,256 @@
#lang scribble/doc
@(require "utils.ss")
@title[#:tag "im:encodings"]{String Encodings}
The @cpp{scheme_utf8_decode} function decodes a @cpp{char} array as
UTF-8 into either a UCS-4 @cpp{mzchar} array or a UTF-16 @cpp{short}
array. The @cpp{scheme_utf8_encode} function encodes either a UCS-4
@cpp{mzchar} array or a UTF-16 @cpp{short} array into a UTF-8
@cpp{char} array.
These functions can be used to check or measure an encoding or
decoding without actually producing the result decoding or encoding,
and variations of the function provide control over the handling of
decoding errors.
@function[(int scheme_utf8_decode
[const-unsigned-char* s]
[int start]
[int end]
[mzchar* us]
[int dstart]
[int dend]
[long* ipos]
[char utf16]
[int permissive])]{
Decodes a byte array as UTF-8 to produce either Unicode code points
into @var{us} (when @var{utf16} is zero) or UTF-16 code units into
@var{us} cast to @cpp{short*} (when @var{utf16} is non-zero). No nul
terminator is added to @var{us}.
The result is non-negative when all of the given bytes are decoded,
and the result is the length of the decoding (in @cpp{mzchar}s or
@cpp{short}s). A @cpp{-2} result indicates an invalid encoding
sequence in the given bytes (possibly because the range to decode
ended mid-encoding), and a @cpp{-3} result indicates that decoding
stopped because not enough room was available in the result string.
The @var{start} and @var{end} arguments specify a range of @var{s} to
be decoded. If @var{end} is negative, @cpp{strlen(@var{s})} is used
as the end.
If @var{us} is @cpp{NULL}, then decoded bytes are not produced, but
the result is valid as if decoded bytes were written. The
@var{dstart} and @var{dend} arguments specify a target range in
@var{us} (in @cpp{mzchar} or @cpp{short} units) for the decoding; a
negative value for @var{dend} indicates that any number of bytes can
be written to @var{us}, which is normally sensible only when @var{us}
is @cpp{NULL} for measuring the length of the decoding.
If @var{ipos} is non-@cpp{NULL}, it is filled with the first undecoded
index within @var{s}. If the function result is non-negative, then
@cpp{*@var{ipos}} is set to the ending index (with is @var{end} if
non-negative, @cpp{strlen(@var{s})} otherwise). If the result is
@cpp{-1} or @cpp{-2}, then @cpp{*@var{ipos}} effectively indicates
how many bytes were decoded before decoding stopped.
If @var{permissive} is non-zero, it is used as the decoding of bytes
that are not part of a valid UTF-8 encoding. Thus, the function
result can be @cpp{-2} only if @var{permissive} is @cpp{0}.
This function does not allocate or trigger garbage collection.}
@function[(int scheme_utf8_decode_as_prefix
[const-unsigned-char* s]
[int start]
[int end]
[mzchar* us]
[int dstart]
[int dend]
[long* ipos]
[char utf16]
[int permissive])]{
Like @cpp{scheme_utf8_decode}, but the result is always the number
of the decoded @cpp{mzchar}s or @cpp{short}s. If a decoding error is
encountered, the result is still the size of the decoding up until
the error.}
@function[(int scheme_utf8_decode_all
[const-unsigned-char* s]
[int len]
[mzchar* us]
[int permissive])]{
Like @cpp{scheme_utf8_decode}, but with fewer arguments. The
decoding produces UCS-4 @cpp{mzchar}s. If the buffer @var{us} is
non-@cpp{NULL}, it is assumed to be long enough to hold the decoding
(which cannot be longer than the length of the input, though it may
be shorter). If @var{len} is negative, @cpp{strlen(@var{s})} is used
as the input length.}
@function[(int scheme_utf8_decode_prefix
[const-unsigned-char* s]
[int len]
[mzchar* us]
[int permissive])]{
Like @cpp{scheme_utf8_decode}, but with fewer arguments. The
decoding produces UCS-4 @cpp{mzchar}s. If the buffer @var{us}
@bold{must} be non-@cpp{NULL}, and it is assumed to be long enough to hold the
decoding (which cannot be longer than the length of the input, though
it may be shorter). If @var{len} is negative, @cpp{strlen(@var{s})}
is used as the input length.
In addition to the result of @cpp{scheme_utf8_decode}, the result
can be @cpp{-1} to indicate that the input ended with a partial
(valid) encoding. A @cpp{-1} result is possible even when
@var{permissive} is non-zero.}
@function[(mzchar* scheme_utf8_decode_to_buffer
[const-unsigned-char* s]
[int len]
[mzchar* buf]
[int blen])]{
Like @cpp{scheme_utf8_decode_all} with @var{permissive} as @cpp{0},
but if @var{buf} is not large enough (as indicated by @var{blen}) to
hold the result, a new buffer is allocated. Unlike other functions,
this one adds a nul terminator to the decoding result. The function
result is either @var{buf} (if it was big enough) or a buffer
allocated with @cpp{scheme_malloc_atomic}.}
@function[(mzchar* scheme_utf8_decode_to_buffer_len
[const-unsigned-char* s]
[int len]
[mzchar* buf]
[int blen]
[long* ulen])]{
Like @cpp{scheme_utf8_decode_to_buffer}, but the length of the
result (not including the terminator) is placed into @var{ulen} if
@var{ulen} is non-@cpp{NULL}.}
@function[(int scheme_utf8_decode_count
[const-unsigned-char* s]
[int start]
[int end]
[int* state]
[int might_continue]
[int permissive])]{
Like @cpp{scheme_utf8_decode}, but without producing the decoded
@cpp{mzchar}s, and always returning the number of decoded
@cpp{mzchar}s up until a decoding error (if any). If
@var{might_continue} is non-zero, the a partial valid encoding at
the end of the input is not decoded when @var{permissive} is also
non-zero.
If @var{state} is non-@cpp{NULL}, it holds information about partial
encodings; it should be set to zero for an initial call, and then
passed back to @cpp{scheme_utf8_decode} along with bytes that
extend the given input (i.e., without any unused partial
encodings). Typically, this mode makes sense only when
@var{might_continue} and @var{permissive} are non-zero.}
@function[(int scheme_utf8_encode
[const-mzchar* us]
[int start]
[int end]
[unsigned-char* s]
[int dstart]
[char utf16])]{
Encodes the given UCS-4 array of @cpp{mzchar}s (if @var{utf16} is
zero) or UTF-16 array of @cpp{short}s (if @var{utf16} is non-zero)
into @var{s}. The @var{end} argument must be no less than
@var{start}.
The array @var{s} is assumed to be long enough to contain the
encoding, but no encoding is written if @var{s} is @cpp{NULL}. The
@var{dstart} argument indicates a starting place in @var{s} to hold
the encoding. No nul terminator is added to @var{s}.
The result is the number of bytes produced for the encoding (or that
would be produced if @var{s} was non-@cpp{NULL}). Encoding never
fails.
This function does not allocate or trigger garbage collection.}
@function[(int scheme_utf8_encode_all
[const-mzchar* us]
[int len]
[unsigned-char* s])]{
Like @cpp{scheme_utf8_encode} with @cpp{0} for @var{start},
@var{len} for @var{end}, @cpp{0} for @var{dstart} and @cpp{0} for
@var{utf16}.}
@function[(char* scheme_utf8_encode_to_buffer
[const-mzchar* s]
[int len]
[char* buf]
[int blen])]{
Like @cpp{scheme_utf8_encode_all}, but the length of @var{buf} is
given, and if it is not long enough to hold the encoding, a buffer is
allocated. A nul terminator is added to the encoded array. The result
is either @var{buf} or an array allocated with
@cpp{scheme_malloc_atomic}.}
@function[(char* scheme_utf8_encode_to_buffer_len
[const-mzchar* s]
[int len]
[char* buf]
[int blen]
[long* rlen])]{
Like @cpp{scheme_utf8_encode_to_buffer}, but the length of the
resulting encoding (not including a nul terminator) is reported in
@var{rlen} if it is non-@cpp{NULL}.}
@function[(unsigned-short* scheme_ucs4_to_utf16
[const-mzchar* text]
[int start]
[int end]
[unsigned-short* buf]
[int bufsize]
[long* ulen]
[int term_size])]{
Converts a UCS-4 encoding (the indicated range of @var{text}) to a
UTF-16 encoding. The @var{end} argument must be no less than
@var{start}.
A result buffer is allocated if @var{buf} is not long enough (as
indicated by @var{bufsize}). If @var{ulen} is non-@cpp{NULL}, it is
filled with the length of the UTF-16 encoding. The @var{term_size}
argument indicates a number of @cpp{short}s to reserve at the end of
the result buffer for a terminator (but no terminator is actually
written).}
@function[(mzchar* scheme_utf16_to_ucs4
[const-unsigned-short* text]
[int start]
[int end]
[mzchar* buf]
[int bufsize]
[long* ulen]
[int term_size])]{
Converts a UTF-16 encoding (the indicated range of @var{text}) to a
UCS-4 encoding. The @var{end} argument must be no less than
@var{start}.
A result buffer is allocated if @var{buf} is not long enough (as
indicated by @var{bufsize}). If @var{ulen} is non-@cpp{NULL}, it is
filled with the length of the UCS-4 encoding. The @var{term_size}
argument indicates a number of @cpp{mzchar}s to reserve at the end of
the result buffer for a terminator (but no terminator is actually
written).}

View File

@ -0,0 +1,137 @@
#lang scribble/doc
@(require "utils.ss")
@title{Structures}
A new Scheme structure type is created with
@cppi{scheme_make_struct_type}. This creates the structure type, but
does not generate the constructor, etc. procedures. The
@cppi{scheme_make_struct_values} function takes a structure type and
creates these procedures. The @cppi{scheme_make_struct_names} function
generates the standard structure procedures names given the structure
type's name. Instances of a structure type are created with
@cppi{scheme_make_struct_instance} and the function
@cppi{scheme_is_struct_instance} tests a structure's type. The
@cppi{scheme_struct_ref} and @cppi{scheme_struct_set} functions access
or modify a field of a structure.
The the structure procedure values and names generated by
@cpp{scheme_make_struct_values} and @cpp{scheme_make_struct_names} can
be restricted by passing any combination of these flags:
@itemize{
@item{@cppi{SCHEME_STRUCT_NO_TYPE} --- the structure type
value/name is not returned.}
@item{@cppi{SCHEME_STRUCT_NO_CONSTR} --- the constructor procedure
value/name is not returned.}
@item{@cppi{SCHEME_STRUCT_NO_PRED}--- the predicate procedure
value/name is not returned.}
@item{@cppi{SCHEME_STRUCT_NO_GET} --- the selector procedure
values/names are not returned.}
@item{@cppi{SCHEME_STRUCT_NO_SET} --- the mutator procedure
values/names are not returned.}
@item{@cppi{SCHEME_STRUCT_GEN_GET} --- the field-independent
selector procedure value/name is returned.}
@item{@cppi{SCHEME_STRUCT_GEN_SET} --- the field-independent
mutator procedure value/name is returned.}
}
When all values or names are returned, they are returned as an array
with the following order: structure type, constructor, predicate,
first selector, first mutator, second selector, etc.,
field-independent select, field-independent mutator. When particular
values/names are omitted, the array is compressed accordingly.
@; ----------------------------------------------------------------------
@function[(Scheme_Object* scheme_make_struct_type
[Scheme_Object* base_name]
[Scheme_Object* super_type]
[Scheme_Object* inspector]
[int num_init_fields]
[int num_auto_fields]
[Scheme_Object* auto_val]
[Scheme_Object* properties]
[Scheme_Object* guard])]{
Creates and returns a new structure type. The @var{base_name}
argument is used as the name of the new structure type; it must be a
symbol. The @var{super_type} argument should be @cpp{NULL} or an
existing structure type to use as the super-type. The @var{inspector}
argument should be @cpp{NULL} or an inspector to manage the type.
The @var{num_init_fields} argument specifies the number of fields
for instances of this structure type that have corresponding
constructor arguments. (If a super-type is used, this is the number
of additional fields, rather than the total number.) The
@var{num_auto_fields} argument specifies the number of additional
fields that have no corresponding constructor arguments, and they are
initialized to @var{auto_val}. The @var{properties} argument is a
list of property-value pairs. The @var{guard} argument is either NULL
or a procedure to use as a constructor guard.}
@function[(Scheme_Object** scheme_make_struct_names
[Scheme_Object* base_name]
[Scheme_Object* field_names]
[int flags]
[int* count_out])]{
Creates and returns an array of standard structure value name
symbols. The @var{base_name} argument is used as the name of the
structure type; it should be the same symbol passed to the associated
call to @cpp{scheme_make_struct_type}. The @var{field_names} argument
is a (Scheme) list of field name symbols. The @var{flags} argument
specifies which names should be generated, and if @var{count_out} is
not @cpp{NULL}, @var{count_out} is filled with the number of names
returned in the array.}
@function[(Scheme_Object** scheme_make_struct_values
[Scheme_Object* struct_type]
[Scheme_Object** names]
[int count]
[int flags])]{
Creates and returns an array of the standard structure value and procedure values
for @var{struct_type}. The @var{struct_type} argument must be a structure type
value created by @cpp{scheme_make_struct_type}. The @var{names} procedure
must be an array of name symbols, generally the array returned by
@cpp{scheme_make_struct_names}. The @var{count} argument specifies the
length of the @var{names} array (and therefore the number of expected
return values) and the @var{flags} argument specifies which values
should be generated.}
@function[(Scheme_Object* scheme_make_struct_instance
[Scheme_Object* struct_type]
[int argc]
[Scheme_Object** argv])]{
Creates an instance of the structure type @var{struct_type}. The
@var{argc} and @var{argv} arguments provide the field values for the
new instance.}
@function[(int scheme_is_struct_instance
[Scheme_Object* struct_type]
[Scheme_Object* v])]{
Returns 1 if @var{v} is an instance of @var{struct_type} or 0 otherwise.}
@function[(Scheme_Object* scheme_struct_ref
[Scheme_Object* s]
[int n])]{
Returns the @var{n}th field (counting from 0) in the structure @var{s}.}
@function[(void scheme_struct_set
[Scheme_Object* s]
[int n]
[Scheme_Object* v])]{
Sets the @var{n}th field (counting from 0) in the structure @var{s} to @var{v}.}

View File

@ -0,0 +1,736 @@
#lang scribble/doc
@(require "utils.ss"
(for-label scheme/tcp))
@title[#:tag "threads"]{Threads}
The initializer function @cppi{scheme_basic_env} creates the main
Scheme thread; all other threads are created through calls to
@cppi{scheme_thread}.
Information about each internal Scheme thread is kept in a
@cppi{Scheme_Thread} structure. A pointer to the current thread's
structure is available as @cppi{scheme_current_thread}. A
@cpp{Scheme_Thread} structure includes the following fields:
@itemize{
@item{@cppi{error_buf} --- the @cppi{mz_jmp_buf} value used to escape
from errors. The @cpp{error_buf} value of the current thread is
available as @cppi{scheme_error_buf}.}
@item{@cppi{cjs.jumping_to_continuation} --- a flag that
distinguishes escaping-continuation invocations from error
escapes. The @cpp{cjs.jumping_to_continuation} value of the current
thread is available as @cppi{scheme_jumping_to_continuation}.}
@item{@cppi{init_config} ---
the thread's initial parameterization. See also @secref["config"].}
@item{@cppi{cell_values} --- The thread's values for thread cells
(see also @secref["config"]).}
@item{@cppi{next} --- The next thread in the linked list of threads;
this is @cpp{NULL} for the main thread.}
}
The list of all scheduled threads is kept in a linked list;
@cppi{scheme_first_thread} points to the first thread in the list.
The last thread in the list is always the main thread.
@; ----------------------------------------------------------------------
@section{Integration with Threads}
Scheme's threads can break external C code under two circumstances:
@itemize{
@item{@italic{Pointers to stack-based values can be communicated
between threads.} For example, if thread A stores a pointer to a
stack-based variable in a global variable, if thread B uses the
pointer in the global variable, it may point to data that is not
currently on the stack.}
@item{@italic{C functions that can invoke Scheme (and also be invoked
by Scheme) depend on strict function-call nesting.} For example,
suppose a function F uses an internal stack, pushing items on to the
stack on entry and popping the same items on exit. Suppose also that
F invokes Scheme to evaluate an expression. If the evaluation of
this expression invokes F again in a new thread, but then returns to
the first thread before completing the second F, then F's internal
stack will be corrupted.}
}
If either of these circumstances occurs, Scheme will probably crash.
@; ----------------------------------------------------------------------
@section[#:tag "usefuel"]{Allowing Thread Switches}
C code that performs substantial or unbounded work should occasionally
call @cppi{SCHEME_USE_FUEL}---actually a macro---which allows Scheme
to swap in another Scheme thread to run, and to check for breaks on
the current thread. In particular, if breaks are enabled, then
@cpp{SCHEME_USE_FUEL} may trigger an exception.
The macro consumes an integer argument. On most platforms, where
thread scheduling is based on timer interrupts, the argument is
ignored. On some platforms, however, the integer represents the amount
of ``fuel'' that has been consumed since the last call to
@cpp{SCHEME_USE_FUEL}. For example, the implementation of
@scheme[vector->list] consumes a unit of fuel for each created cons
cell:
@verbatim[#<<EOS
Scheme_Object *scheme_vector_to_list(Scheme_Object *vec)
{
int i;
Scheme_Object *pair = scheme_null;
i = SCHEME_VEC_SIZE(vec);
for (; i--; ) {
SCHEME_USE_FUEL(1);
pair = scheme_make_pair(SCHEME_VEC_ELS(vec)[i], pair);
}
return pair;
}
EOS
]
The @cpp{SCHEME_USE_FUEL} macro expands to a C block, not an
expression.
@; ----------------------------------------------------------------------
@section[#:tag "threadblock"]{Blocking the Current Thread}
Embedding or extension code sometimes needs to block, but blocking
should allow other Scheme threads to execute. To allow other threads
to run, block using @cppi{scheme_block_until}. This procedure takes
two functions: a polling function that tests whether the blocking
operation can be completed, and a prepare-to-sleep function that sets
bits in @cpp{fd_set}s when Scheme decides to sleep (because all Scheme
threads are blocked). Under Windows, an ``@cpp{fd_set}'' can also
accommodate OS-level semaphores or other handles via
@cpp{scheme_add_fd_handle}.
Since the functions passed to @cppi{scheme_block_until} are called by
the Scheme thread scheduler, they must never raise exceptions, call
@cpp{scheme_apply}, or trigger the evaluation of Scheme code in any
way. The @cpp{scheme_block_until} function itself may call the current
exception handler, however, in reaction to a break (if breaks are
enabled).
When a blocking operation is associated with an object, then the
object might make sense as an argument to @indexed-scheme[sync]. To
extend the set of objects accepted by @scheme[sync], either register
polling and sleeping functions with @cppi{scheme_add_evt}, or register
a semaphore accessor with @cppi{scheme_add_evt_through_sema}.
The @cppi{scheme_signal_received} function can be called to wake up
Scheme when it is sleeping. In particular, calling
@cppi{scheme_signal_received} ensures that Scheme will poll all
blocking synchronizations soon afterward. Furthermore,
@cpp{scheme_signal_received} can be called from any OS-level thread.
Thus, when no adequate prepare-to-sleep function can be implemented
for @cpp{scheme_block_until} in terms of file descriptors or Windows
handles, calling @cpp{scheme_signal_received} when the poll result
changes will ensure that a poll is issued.
@; ----------------------------------------------------------------------
@section[#:tag "threadtime"]{Threads in Embedded Scheme with Event Loops}
When Scheme is embedded in an application with an event-based model
(i.e., the execution of Scheme code in the main thread is repeatedly
triggered by external events until the application exits) special
hooks must be set to ensure that non-main threads execute
correctly. For example, during the execution in the main thread, a new
thread may be created; the new thread may still be running when the
main thread returns to the event loop, and it may be arbitrarily long
before the main thread continues from the event loop. Under such
circumstances, the embedding program must explicitly allow Scheme to
execute the non-main threads; this can be done by periodically calling
the function @cppi{scheme_check_threads}.
Thread-checking only needs to be performed when non-main threads exist
(or when there are active callback triggers). The embedding
application can set the global function pointer
@cppi{scheme_notify_multithread} to a function that takes an integer
parameter and returns @cpp{void}. This function is be called with 1
when thread-checking becomes necessary, and then with 0 when thread
checking is no longer necessary. An embedding program can use this
information to prevent unnecessary @cpp{scheme_check_threads} polling.
The below code illustrates how MrEd formerly set up
@cpp{scheme_check_threads} polling using the wxWindows @cpp{wxTimer}
class. (Any regular event-loop-based callback is appropriate.) The
@cpp{scheme_notify_multithread} pointer is set to
@cpp{MrEdInstallThreadTimer}. (MrEd no longer work this way, however.)
@verbatim[#<<EOS
class MrEdThreadTimer : public wxTimer
{
public:
void Notify(void); /* callback when timer expires */
};
static int threads_go;
static MrEdThreadTimer *theThreadTimer;
#define THREAD_WAIT_TIME 40
void MrEdThreadTimer::Notify()
{
if (threads_go)
Start(THREAD_WAIT_TIME, TRUE);
scheme_check_threads();
}
static void MrEdInstallThreadTimer(int on)
{
if (!theThreadTimer)
theThreadTimer = new MrEdThreadTimer;
if (on)
theThreadTimer->Start(THREAD_WAIT_TIME, TRUE);
else
theThreadTimer->Stop();
threads_go = on;
if (on)
do_this_time = 1;
}
EOS
]
An alternate architecture, which MrEd now uses, is to send the main
thread into a loop, which blocks until an event is ready to handle.
Scheme automatically takes care of running all threads, and it does so
efficiently because the main thread blocks on a file descriptor, as
explained in @secref["threadblock"].
@subsection[#:tag "blockednonmainel"]{Callbacks for Blocked Threads}
Scheme threads are sometimes blocked on file descriptors, such as an
input file or the X event socket. Blocked non-main threads do not
block the main thread, and therefore do not affect the event loop, so
@cppi{scheme_check_threads} is sufficient to implement this case
correctly. However, it is wasteful to poll these descriptors with
@cpp{scheme_check_threads} when nothing else is happening in the
application and when a lower-level poll on the file descriptors can be
installed. If the global function pointer
@cppi{scheme_wakeup_on_input} is set, then this case is handled more
efficiently by turning off thread checking and issuing a ``wakeup''
request on the blocking file descriptors through
@cpp{scheme_wakeup_on_input}.
A @cpp{scheme_wakeup_on_input} procedure takes a pointer to an array
of three @cpp{fd_set}s (sortof\footnote{To ensure maximum portability,
use @cpp{MZ_FD_XXX} instead of @cpp{FD_XXX}.}) and returns
@cpp{void}. The @cpp{scheme_wakeup_on_input} does not sleep; it just
sets up callbacks on the specified file descriptors. When input is
ready on any of those file descriptors, the callbacks are removed and
@cpp{scheme_wake_up} is called.
For example, the X Windows version of MrEd formerly set
@cpp{scheme_wakeup_on_input} to this @cpp{MrEdNeedWakeup}:
@verbatim[#<<EOS
static XtInputId *scheme_cb_ids = NULL;
static int num_cbs;
static void MrEdNeedWakeup(void *fds)
{
int limit, count, i, p;
fd_set *rd, *wr, *ex;
rd = (fd_set *)fds;
wr = ((fd_set *)fds) + 1;
ex = ((fd_set *)fds) + 2;
limit = getdtablesize();
/* See if we need to do any work, really: */
count = 0;
for (i = 0; i < limit; i++) {
if (MZ_FD_ISSET(i, rd))
count++;
if (MZ_FD_ISSET(i, wr))
count++;
if (MZ_FD_ISSET(i, ex))
count++;
}
if (!count)
return;
/* Remove old callbacks: */
if (scheme_cb_ids)
for (i = 0; i < num_cbs; i++)
notify_set_input_func((Notify_client)NULL, (Notify_func)NULL,
scheme_cb_ids[i]);
num_cbs = count;
scheme_cb_ids = new int[num_cbs];
/* Install callbacks */
p = 0;
for (i = 0; i < limit; i++) {
if (MZ_FD_ISSET(i, rd))
scheme_cb_ids[p++] = XtAppAddInput(wxAPP_CONTEXT, i,
(XtPointer *)XtInputReadMask,
(XtInputCallbackProc)MrEdWakeUp, NULL);
if (MZ_FD_ISSET(i, wr))
scheme_cb_ids[p++] = XtAppAddInput(wxAPP_CONTEXT, i,
(XtPointer *)XtInputWriteMask,
(XtInputCallbackProc)MrEdWakeUp, NULL);
if (MZ_FD_ISSET(i, ex))
scheme_cb_ids[p++] = XtAppAddInput(wxAPP_CONTEXT, i,
(XtPointer *)XtInputExceptMask,
(XtInputCallbackProc)MrEdWakeUp,
NULL);
}
}
/* callback function when input/exception is detected: */
Bool MrEdWakeUp(XtPointer, int *, XtInputId *)
{
int i;
if (scheme_cb_ids) {
/* Remove all callbacks: */
for (i = 0; i < num_cbs; i++)
XtRemoveInput(scheme_cb_ids[i]);
scheme_cb_ids = NULL;
/* ``wake up'' */
scheme_wake_up();
}
return FALSE;
}
EOS
]
@; ----------------------------------------------------------------------
@section[#:tag "sleeping"]{Sleeping by Embedded Scheme}
When all Scheme threads are blocked, Scheme must ``sleep'' for a
certain number of seconds or until external input appears on some file
descriptor. Generally, sleeping should block the main event loop of
the entire application. However, the way in which sleeping is
performed may depend on the embedding application. The global function
pointer @cppi{scheme_sleep} can be set by an embedding application to
implement a blocking sleep, although Scheme implements this function
for you.
A @cpp{scheme_sleep} function takes two arguments: a @cpp{float} and a
@cpp{void*}. The latter is really points to an array of three
``@cpp{fd_set}'' records (one for read, one for write, and one for
exceptions); these records are described further below. If the
@cpp{float} argument is non-zero, then the @cpp{scheme_sleep} function
blocks for the specified number of seconds, at most. The
@cpp{scheme_sleep} function should block until there is input one of
the file descriptors specified in the ``@cpp{fd_set},'' indefinitely
if the @cpp{float} argument is zero.
The second argument to @cpp{scheme_sleep} is conceptually an array of
three @cpp{fd_set} records, but always use @cpp{scheme_get_fdset} to
get anything other than the zeroth element of this array, and
manipulate each ``@cpp{fd_set}'' with @cpp{MZ_FD_XXX} instead of
@cpp{FD_XXX}.
The following function @cpp{mzsleep} is an appropriate
@cpp{scheme_sleep} function for most any Unix or Windows application.
(This is approximately the built-in sleep used by Scheme.)
@verbatim[#<<EOS
void mzsleep(float v, void *fds)
{
if (v) {
sleep(v);
} else {
int limit;
fd_set *rd, *wr, *ex;
# ifdef WIN32
limit = 0;
# else
limit = getdtablesize();
# endif
rd = (fd_set *)fds;
wr = (fd_set *)scheme_get_fdset(fds, 1);
ex = (fd_set *)scheme_get_fdset(fds, 2);
select(limit, rd, wr, ex, NULL);
}
}
EOS
]
@; ----------------------------------------------------------------------
@section{Thread Functions}
@function[(Scheme_Object* scheme_thread
[Scheme_Object* thunk])]{
Creates a new thread, just like @scheme[thread].}
@function[(Scheme_Object* scheme_thread_w_details
[Scheme_Object* thunk]
[Scheme_Config* config]
[Scheme_Thread_Cell_Table* cells]
[Scheme_Custodian* cust]
[int suspend_to_kill])]{
Like @cpp{scheme_thread}, except that the created thread belongs to
@var{cust} instead of the current custodian, it uses the given
@var{config} for its initial configuration, it uses @var{cells} for
its thread-cell table, and if @var{suspend_to_kill} is non-zero, then
the thread is merely suspended when it would otherwise be killed
(through either @scheme[kill-thread] or
@scheme[custodian-shutdown-all]).
The @var{config} argument is typically obtained through
@cpp{scheme_current_config} or @cpp{scheme_extend_config}. A
@var{config} is immutable, so different threads can safely use the
same value. The @var{cells} argument should be obtained from
@cpp{scheme_inherit_cells}; it is mutable, and a particular cell table
should be used by only one thread.}
@function[(Scheme_Object* scheme_make_sema
[long v])]{
Creates a new semaphore.}
@function[(void scheme_post_sema
[Scheme_Object* sema])]{
Posts to @var{sema}.}
@function[(int scheme_wait_sema
[Scheme_Object* sema]
[int try])]{
Waits on @var{sema}. If @var{try} is not 0, the wait can fail and 0 is
returned for failure, otherwise 1 is returned.}
@function[(void scheme_thread_block
[float sleep_time])]{
Allows the current thread to be swapped out in favor of other
threads. If @var{sleep_time} positive, then the current thread will
sleep for at least @var{sleep_time} seconds.
After calling this function, a program should almost always call
@cppi{scheme_making_progress} next. The exception is when
@cpp{scheme_thread_block} is called in a polling loop that performs no
work that affects the progress of other threads. In that case,
@cpp{scheme_making_progress} should be called immediately after
exiting the loop.
See also @cpp{scheme_block_until}, and see also the
@cpp{SCHEME_USE_FUEL} macro in @secref["usefuel"].}
@function[(void scheme_thread_block_enable_break
[float sleep_time]
[int break_on])]{
Like @cpp{scheme_thread_block}, but breaks are enabled while blocking if
@var{break_on} is true.}
@function[(void scheme_swap_thread
[Scheme_Thread* thread])]{
Swaps out the current thread in favor of @var{thread}.}
@function[(void scheme_break_thread
[Scheme_Thread* thread])]{
Sends a break signal to the given thread.}
@function[(int scheme_break_waiting
[Scheme_Thread* thread])]{
Returns @cpp{1} if a break from @scheme[break-thread] or @cpp{scheme_break_thread}
has occurred in the specified thread but has not yet been handled.}
@function[(int scheme_block_until
[Scheme_Ready_Fun f]
[Scheme_Needs_Wakeup_Fun fdf]
[Scheme_Object* data]
[float sleep])]{
The @cpp{Scheme_Ready_Fun} and @cpp{Scheme_Needs_Wakeup_Fun}
types are defined as follows:
@verbatim[#<<EOS
typedef int (*Scheme_Ready_Fun)(Scheme_Object *data);
typedef void (*Scheme_Needs_Wakeup_Fun)(Scheme_Object *data,
void *fds);
EOS
]
Blocks the current thread until @var{f} with @var{data} returns a true
value. The @var{f} function is called periodically---at least once
per potential swap-in of the blocked thread---and it may be called
multiple times even after it returns a true value. If @var{f}
with @var{data} ever returns a true value, it must continue to return
a true value until @cpp{scheme_block_until} returns. The argument
to @var{f} is the same @var{data} as provided
to @cpp{scheme_block_until}, and @var{data} is ignored
otherwise. (The @var{data} argument is not actually required to be
a @cpp{Scheme_Object*} value, because it is only used by @var{f}
and @var{fdf}.)
If Scheme decides to sleep, then the @var{fdf} function is called to
sets bits in @var{fds}, conceptually an array of three
@cpp{fd_set}s: one or reading, one for writing, and one for
exceptions. Use @cpp{scheme_get_fdset} to get elements of this
array, and manipulate an ``@cpp{fd_set}'' with @cpp{MZ_FD_XXX}
instead of @cpp{FD_XXX}. Under Windows, an ``@cpp{fd_set}'' can
also accommodate OS-level semaphores or other handles via
@cpp{scheme_add_fd_handle}.
The @var{fdf} argument can be @cpp{NULL}, which implies that the thread
becomes unblocked (i.e., @var{ready} changes its result to true) only
through Scheme actions, and never through external processes (e.g.,
through a socket or OS-level semaphore)---with the exception that
@cpp{scheme_signal_received} may be called to indicate an external
change.
If @var{sleep} is a positive number, then @cpp{scheme_block_until}
polls @var{f} at least every @var{sleep} seconds, but
@cpp{scheme_block_until} does not return until @var{f} returns a
true value. The call to @cpp{scheme_block_until} can return before
@var{sleep} seconds if @var{f} returns a true value.
The return value from @cpp{scheme_block_until} is the return value
of its most recent call to @var{f}, which enables @var{f} to return
some information to the @cpp{scheme_block_until} caller.
See @secref["threadblock"] for information about restrictions on the
@var{f} and @var{fdf} functions.}
@function[(int scheme_block_until_enable_break
[Scheme_Ready_Fun f]
[Scheme_Needs_Wakeup_Fun fdf]
[Scheme_Object* data]
[float sleep]
[int break_on])]{
Like @cpp{scheme_block_until}, but breaks are enabled while blocking
if @var{break_on} is true.}
@function[(int scheme_block_until_unless
[Scheme_Ready_Fun f]
[Scheme_Needs_Wakeup_Fun fdf]
[Scheme_Object* data]
[float sleep]
[Scheme_Object* unless_evt]
[int break_on])]{
Like @cpp{scheme_block_until_enable_break}, but the function
returns if @var{unless_evt} becomes ready, where @var{unless_evt}
is a port progress event implemented by
@cpp{scheme_progress_evt_via_get}. See
@cpp{scheme_make_input_port} for more information.}
@function[(void scheme_signal_received)]{
Indicates that an external event may have caused the result of a
synchronization poll to have a different result. Unlike most other
Scheme functions, this one can be called from any OS-level thread, and
it wakes up if the Scheme thread if it is sleeping.}
@function[(void scheme_check_threads)]{
This function is periodically called by the embedding program to give
background processes time to execute. See @secref["threadtime"]
for more information.}
@function[(void scheme_wake_up)]{
This function is called by the embedding program
when there is input on an external file descriptor. See
@secref["sleeping"] for more information.}
@function[(void* scheme_get_fdset
[void* fds]
[int pos])]{
Extracts an ``@cpp{fd_set}'' from an array passed to
@cpp{scheme_sleep}, a callback for @cpp{scheme_block_until}, or an
input port callback for @cpp{scheme_make_input_port}.}
@function[(void scheme_add_fd_handle
[void* h]
[void* fds]
[int repost])]{
Adds an OS-level semaphore (Windows) or other waitable handle
(Windows) to the ``@cpp{fd_set}'' @var{fds}. When Scheme performs
a ``@cpp{select}'' to sleep on @var{fds}, it also waits on the given
semaphore or handle. This feature makes it possible for Scheme to
sleep until it is awakened by an external process.
Scheme does not attempt to deallocate the given semaphore or handle,
and the ``@cpp{select}'' call using @var{fds} may be unblocked due to
some other file descriptor or handle in @var{fds}. If @var{repost} is
a true value, then @var{h} must be an OS-level semaphore, and if the
``@cpp{select}'' unblocks due to a post on @var{h}, then @var{h} is
reposted; this allows clients to treat @var{fds}-installed semaphores
uniformly, whether or not a post on the semaphore was consumed by
``@cpp{select}''.
The @cpp{scheme_add_fd_handle} function is useful for implementing
the second procedure passed to @cpp{scheme_wait_until}, or for
implementing a custom input port.
Under Unix and Mac OS X, this function has no effect.}
@function[(void scheme_add_fd_eventmask
[void* fds]
[int mask])]{
Adds an OS-level event type (Windows) to the set of types in the
``@cpp{fd_set}'' @var{fds}. When Scheme performs a
``@cpp{select}'' to sleep on @var{fds}, it also waits on events of
them specified type. This feature makes it possible for Scheme to
sleep until it is awakened by an external process.
The event mask is only used when some handle is installed with
@cpp{scheme_add_fd_handle}. This awkward restriction may force you
to create a dummy semaphore that is never posted.
Under Unix, and Mac OS X, this function has no effect.}
@function[(void scheme_add_evt
[Scheme_Type type]
[Scheme_Ready_Fun ready]
[Scheme_Needs_Wakeup_Fun wakeup]
[Scheme_Wait_Filter_Fun filter]
[int can_redirect])]{
The argument types are defined as follows:
@verbatim[#<<EOS
typedef int (*Scheme_Ready_Fun)(Scheme_Object *data);
typedef void (*Scheme_Needs_Wakeup_Fun)(Scheme_Object *data,
void *fds);
typedef int (*Scheme_Wait_Filter_Fun)(Scheme_Object *data);
EOS
]
Extends the set of waitable objects for @scheme[sync]
to those with the type tag @var{type}. If @var{filter} is
non-@cpp{NULL}, it constrains the new waitable set to those objects
for which @var{filter} returns a non-zero value.
The @var{ready} and @var{wakeup} functions are used in the same way
was the arguments to @cpp{scheme_block_until}.
The @var{can_redirect} argument should be @cpp{0}.}
@function[(void scheme_add_evt_through_sema
[Scheme_Type type]
[Scheme_Wait_Sema_Fun getsema]
[Scheme_Wait_Filter_Fun filter])]{
Like @cpp{scheme_add_evt}, but for objects where waiting is based
on a semaphore. Instead of @var{ready} and @var{wakeup} functions,
the @var{getsema} function extracts a semaphore for a given object:
@verbatim[#<<EOS
typedef
Scheme_Object *(*Scheme_Wait_Sema_Fun)(Scheme_Object *data,
int *repost);
EOS
]
If a successful wait should leave the semaphore waited, then
@var{getsema} should set @var{*repost} to @cpp{0}. Otherwise, the
given semaphore will be re-posted after a successful wait. A
@var{getsema} function should almost always set @var{*repost} to
@cpp{1}.}
@function[(void scheme_making_progress)]{
Notifies the scheduler that the current thread is not simply calling
@cppi{scheme_thread_block} in a loop, but that it is actually
making progress.}
@function[(int scheme_tls_allocate)]{
Allocates a thread local storage index to be used with
@cpp{scheme_tls_set} and @cpp{scheme_tls_get}.}
@function[(void scheme_tls_set
[int index]
[void* v])]{
Stores a thread-specific value using an index allocated with
@cpp{scheme_tls_allocate}.}
@function[(void* scheme_tls_get
[int index])]{
Retrieves a thread-specific value installed with @cpp{scheme_tls_set}.
If no thread-specific value is available for the given index, @cpp{NULL} is
returned.}
@function[(Scheme_Object* scheme_call_enable_break
[Scheme_Prim* prim]
[int argc]
[Scheme_Object** argv])]{
Calls @var{prim} with the given @var{argc} and @var{argv} with breaks
enabled. The @var{prim} function can block, in which case it might be
interrupted by a break. The @var{prim} function should not block,
yield, or check for breaks after it succeeds, where ``succeeds''
depends on the operation. For example,
@scheme[tcp-accept/enable-break] is implemented by wrapping this
function around the implementation of @scheme[tcp-accept]; the
@scheme[tcp-accept] implementation does not block or yield after it
accepts a connection.}
@function[(Scheme_Object* scheme_make_thread_cell
[Scheme_Object* def_val]
[int preserved]
[Scheme_Object* cell]
[Scheme_Thread_Cell_Table* cells]
[Scheme_Object* cell]
[Scheme_Thread_Cell_Table* cells]
[Scheme_Object* v])]{
Prevents Scheme thread swaps until @cpp{scheme_end_atomic} or
@cpp{scheme_end_atomic_no_swap} is called. Start-atomic and
end-atomic pairs can be nested.}
@function[(void scheme_end_atomic)]{
Ends an atomic region with respect to Scheme threads. The current
thread may be swapped out immediately (i.e., the call to
@cpp{scheme_end_atomic} is assumed to be a safe point for thread
swaps).}
@function[(void scheme_end_atomic_no_swap)]{
Ends an atomic region with respect to Scheme threads, and also
prevents an immediate thread swap. (In other words, no Scheme
thread swaps will occur until a future safe point.)}

View File

@ -0,0 +1,142 @@
#lang scheme/base
(require scribble/manual
scribble/struct
scribble/decode
(for-syntax scheme/base)
(for-label scheme/base))
(provide MzScheme
mzc cpp cppi cppdef (rename-out [*var var])
function subfunction
FormatD
(except-out (all-from-out scribble/manual) var)
(for-label (all-from-out scheme/base)))
(define-syntax (function stx)
(syntax-case stx ()
[(_ (ret name [type arg] ...) . body)
#'(*function (cpp/sym 'ret)
(as-index (cpp/sym 'name))
(list (type/sym 'type) ...)
(list (var/sym 'arg) ...)
(lambda ()
(list . body)))]))
(define-syntax (subfunction stx)
(syntax-case stx ()
[(_ (ret name [type arg] ...) . body)
#'(make-blockquote
"leftindent"
(flow-paragraphs
(decode-flow
(list
(*function (cpp/sym 'ret)
(var/sym 'name)
(list (type/sym 'type) ...)
(list (var/sym 'arg) ...)
(lambda ()
(list . body)))))))]))
(define (to-flow elem)
(make-flow (list (make-paragraph (list elem)))))
(define (*function ret name types args rest-thunk)
(let ([spacer (hspace 1)]
[pair-type (lambda (t v)
(make-element #f
(list
t
(hspace 1)
v)))]
[super-long? ((+ (element-width ret)
1
(element-width name)
1
(apply max 0 (map (lambda (t v)
(+ (element-width t)
1
(element-width v)))
types
args))
1)
. > .
65)])
(make-splice
(cons
(boxed
(make-table
#f
(append
(if super-long?
(list (list (to-flow ret) 'cont 'cont 'cont 'cont))
null)
(list
(append
(if super-long?
null
(list (to-flow ret)
(to-flow spacer)))
(list (to-flow name)
(to-flow (tt "("))
(if (null? types)
(to-flow (tt ")"))
(to-flow (make-element
#f
(cons (pair-type (car types) (car args))
(if (null? (cdr types))
(list (tt ")"))
(list (tt ","))))))))))
(if (null? types)
null
(let loop ([types (cdr types)]
[args (cdr args)])
(if (null? types)
null
(cons
(append
(if super-long?
null
(list (to-flow spacer)
(to-flow spacer)))
(list (to-flow spacer)
(to-flow spacer)
(to-flow (make-element
#f
(cons
(pair-type (car types) (car args))
(if (null? (cdr types))
(list (tt ")"))
(list (tt ","))))))))
(loop (cdr types) (cdr args)))))))))
(rest-thunk)))))
(define (boxed t)
(make-table
'boxed
(list (list (make-flow (list t))))))
(define (cpp/sym s)
(cpp (symbol->string s)))
(define (type/sym s)
(cpp (regexp-replace* #rx"-" (symbol->string s) " ")))
(define (var/sym s)
(*var (symbol->string s)))
(define cpp tt)
(define cppi tt)
(define cppdef (lambda (x) (as-index (tt x))))
(define *var italic)
(define mzc (exec "mzc"))
(define (refsecref s)
(secref #:doc '(lib "scribblings/reference/reference.scrbl") s))
(define MzScheme
(italic (refsecref "top")))
(define (FormatD s)
(litchar (string-append "%" s)))

View File

@ -0,0 +1,747 @@
#lang scribble/doc
@(require "utils.ss")
@title[#:tag "im:values+types"]{Values and Types}
A Scheme value is represented by a pointer-sized value. The low bit is
a mark bit: a 1 in the low bit indicates an immediate integer, a 0
indicates a (word-aligned) pointer.
A pointer Scheme value references a structure that begins with a
@cppi{Scheme_Object} sub-structure, which in turn starts with a tag
that has the C type @cppi{Scheme_Type}. The rest of the structure,
following the @cppi{Scheme_Object} header, is type-dependent.
PLT Scheme's C interface gives Scheme values the type
@cpp{Scheme_Object*}. (The ``object'' here does not refer to objects
in the sense of the @schememodname[scheme/class] library.)
Examples of @cpp{Scheme_Type} values include @cpp{scheme_pair_type}
and @cpp{scheme_symbol_type}. Some of these are implemented as
instances of @cppi{Scheme_Simple_Object}, which is defined in
@filepath{scheme.h}, but extension or embedding code should never access
this structure directly. Instead, the code should use macros, such as
@cpp{SCHEME_CAR}, that provide access to the data of common Scheme
types.
For most Scheme types, a constructor is provided for creating values
of the type. For example, @cpp{scheme_make_pair} takes two
@cpp{Scheme_Object*} values and returns the @scheme[cons] of the
values.
The macro @cppi{SCHEME_TYPE} takes a @cpp{Scheme_Object *} and returns
the type of the object. This macro performs the tag-bit check, and
returns @cppi{scheme_integer_type} when the value is an immediate
integer; otherwise, @cpp{SCHEME_TYPE} follows the pointer to get the
type tag. Macros are provided to test for common Scheme types; for
example, @cpp{SCHEME_PAIRP} returns @cpp{1} if the value is a cons
cell, @cpp{0} otherwise.
In addition to providing constructors, PLT Scheme defines six global
constant Scheme values: @cppi{scheme_true}, @cppi{scheme_false},
@cppi{scheme_null}, @cppi{scheme_eof}, @cppi{scheme_void}, and
@cppi{scheme_undefined}. Each of these has a type tag, but each is
normally recognized via its constant address.
@index['("types" "creating")]{An} extension or embedding application
can create new a primitive data type by calling
@cppi{scheme_make_type}, which returns a fresh @cpp{Scheme_Type}
value. To create a collectable instance of this type, allocate memory
for the instance with @cpp{scheme_malloc}. From PLT Scheme's
perspective, the main constraint on the data format of such an
instance is that the first @cpp{sizeof(Scheme_Object)} bytes must
correspond to a @cpp{Scheme_Object} record; furthermore, the first
@cpp{sizeof(Scheme_Type)} bytes must contain the value returned by
@cpp{scheme_make_type}. Extensions with modest needs can use
@cppi{scheme_make_cptr}, instead of creating an entirely new type.
Scheme values should never be allocated on the stack, and they should
never contain pointers to values on the stack. Besides the problem of
restricting the value's lifetime to that of the stack frame,
allocating values on the stack creates problems for continuations and
threads, both of which copy into and out of the stack.
@; ----------------------------------------------------------------------
@section[#:tag "im:stdtypes"]{Standard Types}
The following are the @cpp{Scheme_Type} values for the standard
types:
@itemize{
@item{@cppdef{scheme_bool_type} --- the constants
@cpp{scheme_true} and @cpp{scheme_false} are the only values of this
type; use @cpp{SCHEME_FALSEP} to recognize @cpp{scheme_false} and use
@cpp{SCHEME_TRUEP} to recognize anything except @cpp{scheme_false};
test for this type with @cppi{SCHEME_BOOLP}}
@item{@cppdef{scheme_char_type} --- @cppi{SCHEME_CHAR_VAL}
extracts the character (of type @cppi{mzchar}); test for this type
with @cppi{SCHEME_CHARP}}
@item{@cppdef{scheme_integer_type} --- fixnum integers, which are
identified via the tag bit rather than following a pointer to this
@cpp{Scheme_Type} value; @cppi{SCHEME_INT_VAL} extracts the integer;
test for this type with @cppi{SCHEME_INTP}}
@item{@cppdef{scheme_double_type} --- flonum inexact numbers;
@cppi{SCHEME_FLOAT_VAL} or @cppi{SCHEME_DBL_VAL} extracts the
floating-point value; test for this type with @cppi{SCHEME_DBLP}}
@item{@cppdef{scheme_float_type} --- single-precision flonum
inexact numbers, when specifically enabled when compiling PLT Scheme;
@cppi{SCHEME_FLOAT_VAL} or @cppi{SCHEME_FLT_VAL} extracts the
floating-point value; test for this type with @cppi{SCHEME_FLTP}}
@item{@cppdef{scheme_bignum_type} --- test for this type with
@cppi{SCHEME_BIGNUMP}}
@item{@cppdef{scheme_rational_type} --- test for this type with
@cppi{SCHEME_RATIONALP}}
@item{@cppdef{scheme_complex_type} --- test for this type or
@cpp{scheme_complex_izi_type} with @cppi{SCHEME_COMPLEXP}}
@item{@cppdef{scheme_complex_izi_type} --- complex number with an inexact
zero imaginary part (so it counts as a real number); test for this
type specifically with @cppi{SCHEME_COMPLEX_IZIP}}
@item{@cppdef{scheme_char_string_type} --- @index['("strings"
"conversion to C")]{@cppi{SCHEME_CHAR_STR_VAL}} extracts the string
as a @cpp{mzchar*}; the string is always nul-terminated, but may also
contain embedded nul characters, and the Scheme string is modified if
this string is modified; @cppi{SCHEME_CHAR_STRLEN_VAL} extracts the
string length (in characters, not counting the nul terminator); test
for this type with @cppi{SCHEME_CHAR_STRINGP}}
@item{@cppdef{scheme_byte_string_type} ---
@cppi{SCHEME_BYTE_STR_VAL} extracts the string as a @cpp{char*}; the
string is always nul-terminated, but may also contain embedded nul
characters, and the Scheme string is modified if this string is
modified; @cppi{SCHEME_BYTE_STRLEN_VAL} extracts the string length
(in bytes, not counting the nul terminator); test for this type with
@cppi{SCHEME_BYTE_STRINGP}}
@item{@cppdef{scheme_path_type} ---
@index['("strings" "conversion to C")] @cppi{SCHEME_PATH_VAL}
extracts the path as a @cpp{char*}; the string is always
nul-terminated; @cppi{SCHEME_PATH_LEN} extracts the path length (in
bytes, not counting the nul terminator); test for this type with
@cppi{SCHEME_PATHP}}
@item{@cppdef{scheme_symbol_type} --- @cppi{SCHEME_SYM_VAL}
extracts the symbol's string as a @cpp{char*} UTF-8 encoding (do not
modify this string); @cppi{SCHEME_SYM_LEN} extracts the number of
bytes in the symbol name (not counting the nul terminator); test for
this type with @cppi{SCHEME_SYMBOLP}; 3m: see @secref["im:3m"] for
a caution about @cppi{SCHEME_SYM_VAL}}
@item{@cppdef{scheme_keyword_type} --- @cppi{SCHEME_KEYWORD_VAL}
extracts the keywors's string (without the leading hash colon) as a
@cpp{char*} UTF-8 encoding (do not modify this string);
@cppi{SCHEME_KEYWORD_LEN} extracts the number of bytes in the keyword
name (not counting the nul terminator); test for this type with
@cppi{SCHEME_KEYWORDP}; 3m: see @secref["im:3m"] for a caution
about @cppi{SCHEME_KEYWORD_VAL}}
@item{@cppdef{scheme_box_type} --- @cppi{SCHEME_BOX_VAL}
extracts/sets the boxed value; test for this type with
@cppi{SCHEME_BOXP}}
@item{@cppdef{scheme_pair_type} --- @cppi{SCHEME_CAR} extracts/sets
the @scheme{car} and @cppi{SCHEME_CDR} extracts/sets the
@scheme{cdr}; test for this type with @cppi{SCHEME_PAIRP}}
@item{@cppdef{scheme_vector_type} --- @cppi{SCHEME_VEC_SIZE}
extracts the length and @cppi{SCHEME_VEC_ELS} extracts the array of
Scheme values (the Scheme vector is modified when this array is
modified); test for this type with @cppi{SCHEME_VECTORP}; 3m: see
@secref["im:3m"] for a caution about @cppi{SCHEME_VEC_ELS}}
@item{@cppdef{scheme_structure_type} --- structure instances; test
for this type with @cppi{SCHEME_STRUCTP}}
@item{@cppdef{scheme_struct_type_type} --- structure types; test for
this type with @cppi{SCHEME_STRUCT_TYPEP}}
@item{@cppdef{scheme_struct_property_type} --- structure type
properties}
@item{@cppdef{scheme_input_port_type} --- @cppi{SCHEME_INPORT_VAL}
extracts/sets the user data pointer; test for just this type with
@cppi{SCHEME_INPORTP}, but use @cppi{SCHEME_INPUT_PORTP} to recognize
all input ports (including structures with the
@scheme[prop:input-port] property)}
@item{@cppdef{scheme_output_port_type} --- @cppi{SCHEME_OUTPORT_VAL}
extracts/sets the user data pointer; test for just this type with
@cppi{SCHEME_OUTPORTP}, but use @cppi{SCHEME_OUTPUT_PORTP} to
recognize all output ports (including structures with the
@scheme[prop:output-port] property)}
@item{@cppdef{scheme_thread_type} --- thread descriptors; test for
this type with @cppi{SCHEME_THREADP}}
@item{@cppdef{scheme_sema_type} --- semaphores; test for this type
with @cppi{SCHEME_SEMAP}}
@item{@cppdef{scheme_hash_table_type} --- test for this type with
@cppi{SCHEME_HASHTP}}
@item{@cppdef{scheme_bucket_table_type} --- test for this type with
@cppi{SCHEME_BUCKTP}}
@item{@cppdef{scheme_weak_box_type} --- test for this type with
@cppi{SCHEME_WEAKP}; @cppi{SCHEME_WEAK_PTR} extracts the contained
object, or @cpp{NULL} after the content is collected; do not set the
content of a weak box}
@item{@cppdef{scheme_namespace_type} --- namespaces; test for this
type with @cppi{SCHEME_NAMESPACEP}}
@item{@cppdef{scheme_cpointer_type} --- @|void-const| pointer with a
type-describing @cpp{Scheme_Object}; @cppi{SCHEME_CPTR_VAL} extracts
the pointer and @cppi{SCHEME_CPTR_TYPE} extracts the type tag object;
test for this type with @cppi{SCHEME_CPTRP}. The tag is used when
printing such objects when it's a symbol, a byte string, a string, or
a pair holding one of these in its car.}
}
The following are the procedure types:
@itemize{
@item{@cppdef{scheme_prim_type} --- a primitive procedure,
possibly with data elements}
@item{@cppdef{scheme_closed_prim_type} --- an old-style primitive
procedure with a data pointer}
@item{@cppdef{scheme_compiled_closure_type} --- a Scheme
procedure}
@item{@cppdef{scheme_cont_type} --- a continuation}
@item{@cppdef{scheme_escaping_cont_type} --- an escape continuation}
@item{@cppdef{scheme_case_closure_type} --- a @scheme[case-lambda]
procedure}
@item{@cppdef{scheme_native_closure_type} --- a procedure with
native code generated by the just-in-time compiler}}
}
The predicate @cppi{SCHEME_PROCP} returns 1 for all procedure types
and 0 for anything else.
The following are additional number predicates:
@itemize{
@item{@cppi{SCHEME_NUMBERP} --- all numerical types}
@item{@cppi{SCHEME_REALP} --- all non-complex numerical types, plus
@cpp{scheme_complex_izi_type}}
@item{@cppi{SCHEME_EXACT_INTEGERP} --- fixnums and bignums}
@item{@cppi{SCHEME_EXACT_REALP} --- fixnums, bignums, and rationals}
@item{@cppi{SCHEME_FLOATP} --- both single-precision (when enabled)
and double-precision flonums}
}
@; ----------------------------------------------------------------------
@section{Global Constants}
There are six global constants:
@itemize{
@item{@cppdef{scheme_null} --- test for this value with
@cppi{SCHEME_NULLP}}
@item{@cppdef{scheme_eof} --- test for this value with
@cppi{SCHEME_EOFP}}
@item{@cppdef{scheme_true}}
@item{@cppdef{scheme_false} --- test for this value with
@cppi{SCHEME_FALSEP}; test @italic{against} it with
@cppi{SCHEME_TRUEP}}
@item{@cppdef{scheme_void} --- test for this value with
@cppi{SCHEME_VOIDP}}
@item{@cppdef{scheme_undefined}}
}
@; ----------------------------------------------------------------------
@section[#:tag "im:strings"]{Strings}
As noted in @secref["im:unicode"], a Scheme character is a Unicode
code point represented by a @cpp{mzchar} value, and character strings
are @cpp{mzchar} arrays. PLT Scheme also supplies byte strings, which
are @cpp{char} arrays.
For a character string @var{s}, @cpp{SCHEME_CHAR_STR_VAL(@var{s})}
produces a pointer to @cpp{mzchar}s, not @cpp{char}s. Convert a
character string to its UTF-8 encoding as byte string with
@cpp{scheme_char_string_to_byte_string}. For a byte string
@var{bs}, @cpp{SCHEME_BYTE_STR_VAL(@var{bs})} produces a pointer
to @cpp{char}s. The function
@cpp{scheme_byte_string_to_char_string} decodes a byte string as
UTF-8 and produces a character string. The functions
@cpp{scheme_char_string_to_byte_string_locale} and
@cpp{scheme_byte_string_to_char_string_locale} are similar, but
they use the current locale's encoding instead of UTF-8.
For more fine-grained control over UTF-8 encoding, use the
@cpp{scheme_utf8_decode} and @cpp{scheme_utf8_encode} functions, which
are described in @secref["im:encodings"].
@; ----------------------------------------------------------------------
@section{Value Functions}
@function[(Scheme_Object* scheme_make_char
[mzchar ch])]{
Returns the character value. The @var{ch} value must be a legal
Unicode code point (and not a surrogate, for example). The first 256
characters are represented by constant Scheme values, and others are
allocated.}
@function[(Scheme_Object* scheme_make_char_or_null
[mzchar ch])]{
Like @cpp{scheme_make_char}, but the result is @cpp{NULL} if @var{ch}
is not a legal Unicode code point.}
@function[(Scheme_Object* scheme_make_character
[mzchar ch])]{
Returns the character value. This is a macro that directly accesses
the array of constant characters when @var{ch} is less than 256.}
@function[(Scheme_Object* scheme_make_ascii_character
[mzchar ch])]{
Returns the character value, assuming that @var{ch} is less than 256. (This is a macro.)}
@function[(Scheme_Object* scheme_make_integer
[long i])]{
Returns the integer value; @var{i} must fit in a fixnum. (This is a macro.)}
@function[(Scheme_Object* scheme_make_integer_value
[long i])]{
Returns the integer value. If @var{i} does not fit in a fixnum,
a bignum is returned.}
@function[(Scheme_Object* scheme_make_integer_value_from_unsigned
[unsigned-long i])]{
Like @cpp{scheme_make_integer_value}, but for unsigned integers.}
@function[(Scheme_Object* scheme_make_integer_value_from_long_long
[mzlonglong i])]{
Like @cpp{scheme_make_integer_value}, but for @cpp{mzlonglong}
values (see @secref["im:intsize"]).}
@function[(Scheme_Object* scheme_make_integer_value_from_unsigned_long_long
[umzlonglong i])]{
Like @cpp{scheme_make_integer_value_from_long_long}, but for unsigned integers.}
@function[(Scheme_Object* scheme_make_integer_value_from_long_halves
[unsigned-long hi]
[unsigned-long lo])]{
Creates an integer given the high and low @cpp{long}s of a signed
integer. Note that on 64-bit platforms where @cpp{long long} is the
same as @cpp{long}, the resulting integer has 128 bits. (See also
@secref["im:intsize"].)}
@function[(Scheme_Object* scheme_make_integer_value_from_unsigned_long_halves
[unsigned-long hi]
[unsigned-long lo])]{
Creates an integer given the high and low @cpp{long}s of an unsigned
integer. Note that on 64-bit platforms where @cpp{long long} is the
same as @cpp{long}, the resulting integer has 128 bits.}
@function[(int scheme_get_int_val
[Scheme_Object* o]
[long* i])]{
Extracts the integer value. Unlike the @cppi{SCHEME_INT_VAL} macro,
this procedure will extract an integer that fits in a @cpp{long} from
a Scheme bignum. If @var{o} fits in a @cpp{long}, the extracted
integer is placed in @var{*i} and 1 is returned; otherwise, 0 is
returned and @var{*i} is unmodified.}
@function[(int scheme_get_unsigned_int_val
[Scheme_Object* o]
[unsigned-long* i])]{
Like @cpp{scheme_get_int_val}, but for unsigned integers.}
@function[(int scheme_get_long_long_val
[Scheme_Object* o]
[mzlonglong* i])]{
Like @cpp{scheme_get_int_val}, but for @cpp{mzlonglong} values (see
@secref["im:intsize"]).}
@function[(int scheme_get_unsigned_long_long_val
[Scheme_Object* o]
[umzlonglong* i])]{
Like @cpp{scheme_get_int_val}, but for unsigned @cpp{mzlonglong} values (see
@secref["im:intsize"]).}
@function[(Scheme_Object* scheme_make_double
[double d])]{
Creates a new floating-point value.}
@function[(Scheme_Object* scheme_make_float
[float d])]{
Creates a new single-precision floating-point value. The procedure is
available only when PLT Scheme is compiled with single-precision
numbers enabled.}
@function[(double scheme_real_to_double
[Scheme_Object* o])]{
Converts a Scheme real number to a double-precision floating-point
value.}
@function[(Scheme_Object* scheme_make_pair
[Scheme_Object* carv]
[Scheme_Object* cdrv])]{
Makes a \scmi{cons} pair.}
@function[(Scheme_Object* scheme_make_byte_string
[char* bytes])]{
Makes a Scheme byte string from a nul-terminated C string. The
@var{bytes} string is copied.}
@function[(Scheme_Object* scheme_make_byte_string_without_copying
[char* bytes])]{
Like @cpp{scheme_make_byte_string}, but the string is not copied.}
@function[(Scheme_Object* scheme_make_sized_byte_string
[char* bytes]
[long len]
[int copy])]{
Makes a byte string value with size @var{len}. A copy of @var{bytes}
is made if @var{copy} is not 0. The string @var{bytes} should
contain @var{len} bytes; @var{bytes} can contain the nul byte at any
position, and need not be nul-terminated if @var{copy} is
non-zero. However, if @var{len} is negative, then the nul-terminated
length of @var{bytes} is used for the length, and if @var{copy} is
zero, then @var{bytes} must be nul-terminated.}
@function[(Scheme_Object* scheme_make_sized_offset_byte_string
[char* bytes]
[long d]
[long len]
[int copy])]{
Like @cpp{scheme_make_sized_byte_string}, except the @var{len}
characters start from position @var{d} in @var{bytes}. If @var{d} is
non-zero, then @var{copy} must be non-zero.}
@function[(Scheme_Object* scheme_alloc_byte_string
[int size]
[char fill])]{
Allocates a new Scheme byte string.}
@function[(Scheme_Object* scheme_append_byte_string
[Scheme_Object* a]
[Scheme_Object* b])]{
Creates a new byte string by appending the two given byte strings.}
@function[(Scheme_Object* scheme_make_locale_string
[char* bytes])]{
Makes a Scheme string from a nul-terminated byte string that is a
locale-specific encoding of a character string; a new string is
allocated during decoding. The ``locale in the name of this function
thus refers to @var{bytes}, and not the resulting string (which is
internally stored as UCS-4).}
@function[(Scheme_Object* scheme_make_utf8_string
[char* bytes])]{
Makes a Scheme string from a nul-terminated byte string that is a
UTF-8 encoding. A new string is allocated during decoding. The
``utf8'' in the name of this function thus refers to @var{bytes}, and
not the resulting string (which is internally stored as UCS-4).}
@function[(Scheme_Object* scheme_make_sized_utf8_string
[char* bytes]
[long len])]{
Makes a string value, based on @var{len} UTF-8-encoding bytes (so the
resulting string is @var{len} characters or less). The string
@var{bytes} should contain at least @var{len} bytes; @var{bytes} can
contain the nul byte at any position, and need not be
null-terminated. However, if @var{len} is negative, then the
nul-terminated length of @var{bytes} is used for the length.}
@function[(Scheme_Object* scheme_make_sized_offset_utf8_string
[char* bytes]
[long d]
[long len])]{
Like @cpp{scheme_make_sized_char_string}, except the @var{len} characters
start from position @var{d} in @var{bytes}.}
@function[(Scheme_Object* scheme_make_char_string
[mzchar* chars])]{
Makes a Scheme string from a nul-terminated UCS-4 string. The
@var{chars} string is copied.}
@function[(Scheme_Object* scheme_make_char_string_without_copying
[mzchar* chars])]{
Like @cpp{scheme_make_char_string}, but the string is not copied.}
@function[(Scheme_Object* scheme_make_sized_char_string
[mzchar* chars]
[long len]
[int copy])]{
Makes a string value with size @var{len}. A copy of @var{chars} is
made if @var{copy} is not 0. The string @var{chars} should
contain @var{len} characters; @var{chars} can contain the nul
character at any position, and need not be nul-terminated
if @var{copy} is non-zero. However, if @var{len} is negative, then
the nul-terminated length of @var{chars} is used for the length, and
if @var{copy} is zero, then the @var{chars} must be nul-terminated.}
@function[(Scheme_Object* scheme_make_sized_offset_char_string
[mzchar* chars]
[long d]
[long len]
[int copy])]{
Like @cpp{scheme_make_sized_char_string}, except the @var{len}
characters start from position @var{d} in @var{chars}. If @var{d} is
non-zero, then @var{copy} must be non-zero.}
@function[(Scheme_Object* scheme_alloc_char_string
[int size]
[mzchar fill])]{
Allocates a new Scheme string.}
@function[(Scheme_Object* scheme_append_char_string
[Scheme_Object* a]
[Scheme_Object* b])]{
Creates a new string by appending the two given strings.}
@function[(Scheme_Object* scheme_char_string_to_byte_string
[Scheme_Object* s])]{
Converts a Scheme character string into a Scheme byte string via UTF-8.}
@function[(Scheme_Object* scheme_byte_string_to_char_string
[Scheme_Object* s])]{
Converts a Scheme byte string into a Scheme character string via UTF-8.}
@function[(Scheme_Object* scheme_char_string_to_byte_string_locale
[Scheme_Object* s])]{
Converts a Scheme character string into a Scheme byte string via the locale's encoding.}
@function[(Scheme_Object* scheme_byte_string_to_char_string_locale
[Scheme_Object* s])]{
Converts a Scheme byte string into a Scheme character string via the locale's encoding.}
@function[(Scheme_Object* scheme_intern_symbol
[char* name])]{
Finds (or creates) the symbol matching the given nul-terminated, ASCII
string (not UTF-8). The case of @var{name} is (non-destructively) normalized
before interning if @cppi{scheme_case_sensitive} is 0.}
@function[(Scheme_Object* scheme_intern_exact_symbol
[char* name]
[int len])]{
Creates or finds a symbol given the symbol's length in UTF-8-encoding
bytes. The the case of @var{name} is not normalized.}
@function[(Scheme_Object* scheme_intern_exact_char_symbol
[mzchar* name]
[int len])]{
Like @cpp{scheme_intern_exact_symbol}, but given a character array
instead of a UTF-8-encoding byte array.}
@function[(Scheme_Object* scheme_make_symbol
[char* name])]{
Creates an uninterned symbol from a nul-terminated, UTF-8-encoding
string. The case is not normalized.}
@function[(Scheme_Object* scheme_make_exact_symbol
[char* name]
[int len])]{
Creates an uninterned symbol given the symbol's length in
UTF-8-encoded bytes.}
@function[(Scheme_Object* scheme_intern_exact_keyword
[char* name]
[int len])]{
Creates or finds a keyword given the keywords length in UTF-8-encoding
bytes. The the case of @var{name} is not normalized, and it should
not include the leading hash and colon of the keyword's printed form.}
@function[(Scheme_Object* scheme_intern_exact_char_keyword
[mzchar* name]
[int len])]{
Like @cpp{scheme_intern_exact_keyword}, but given a character array
instead of a UTF-8-encoding byte array.}
@function[(Scheme_Object* scheme_make_vector
[int size]
[Scheme_Object* fill])]{
Allocates a new vector.}
@function[(Scheme_Object* scheme_box
[Scheme_Object* v])]{
Creates a new box containing the value @var{v}.}
@function[(Scheme_Object* scheme_make_weak_box
[Scheme_Object* v])]{
Creates a new weak box containing the value @var{v}.}
@function[(Scheme_Type scheme_make_type
[char* name])]{
Creates a new type (not a Scheme value).}
@function[(Scheme_Object* scheme_make_cptr
[void* ptr]
[const-Scheme_Object* typetag])]{
Creates a C-pointer object that encapsulates @var{ptr} and uses
@var{typetag} to identify the type of the pointer. The
@cppi{SCHEME_CPTRP} macro recognizes objects created by
@cpp{scheme_make_cptr}. The @cppi{SCHEME_CPTR_VAL} macro extracts
the original @var{ptr} from the Scheme object, and
@cppi{SCHEME_CPTR_TYPE} extracts the type tag.
The @cppi{SCHEME_CPTR_OFFSETVAL} macro returns @cpp{0}
for the result Scheme object.}
@function[(Scheme_Object* scheme_make_offset_cptr
[void* ptr]
[long offset]
[const-Scheme_Object* typetag])]{
Creates a C-pointer object that encapsulates both @var{ptr} and @var{offset}.
The @cppi{SCHEME_CPTR_OFFSETVAL} macro returns @var{offset}
for the result Scheme object (and the macro be used to change the offset,
since it also works on objects with no offset).}
@function[(void scheme_set_type_printer
[Scheme_Type type]
[Scheme_Type_Printer printer])]{
Installs a printer to be used for printing (or writing or displaying)
values that have the type tag @var{type}.
The type of @var{printer} is defined as follows:\cppIndex{scheme_Type_Printer}
%
@verbatim[#<<EOS
typedef void (*Scheme_Type_Printer)(Scheme_Object *v, int dis,
Scheme_Print_Params *pp);
EOS
]
%
Such a printer must print a representation of the value using
@cppi{scheme_print_bytes} and @cppi{scheme_print_string}. The
first argument to the printer, @var{v}, is the value to be printed.
The second argument indicates whether @var{v} is printed via
@scheme[write] or @scheme[display]. The last argument is to be passed
on to @cppi{scheme_print_bytes} or @cppi{scheme_print_string} to
identify the printing context.}
@function[(void scheme_print_bytes
[Scheme_Print_Params* pp]
[const-char* str]
[int offset]
[int len])]{
Writes the content of @var{str} --- starting from @var{offset} and
running @var{len} bytes --- into a printing context determined by
@var{pp}. This function is for use by a printer that is installed
with @cpp{scheme_set_type_printer}.}
@function[(void scheme_print_string
[Scheme_Print_Params* pp]
[const-mzchar* str]
[int offset]
[int len])]{
Writes the content of @var{str} --- starting from @var{offset} and
running @var{len} characters --- into a printing context determined
by @var{pp}. This function is for use by a printer that is installed
with @cpp{scheme_set_type_printer}.}
@function[(void scheme_set_type_equality
[Scheme_Type type]
[Scheme_Equal_Proc equalp]
[Scheme_Primary_Hash_Proc hash1]
[Scheme_Secondary_Hash_Proc hash2])]{
Installs an equality predicate and associated hash functions for
values that have the type tag @var{type}. The @var{equalp} predicate is
only applied to values that both have tag @var{type}.
The type of @var{equalp}, @var{hash1}, and @var{hash2} are defined as follows:
@verbatim[#<<EOS
typedef int (*Scheme_Equal_Proc)(Scheme_Object *obj1,
Scheme_Object *obj2);
typedef long (*Scheme_Primary_Hash_Proc)(Scheme_Object *obj,
long base);
typedef long (*Scheme_Secondary_Hash_Proc)(Scheme_Object *obj);
EOS
]
The two hash functions are use to generate primary and secondary keys
for double hashing in an @scheme[equal?]-based hash table. The result
of the primary-key function should depend on both @var{obj} and
@var{base}.}

View File

@ -165,11 +165,12 @@ handler}.
An @tech{extension-load handler} takes the same arguments as a An @tech{extension-load handler} takes the same arguments as a
@tech{load handler}, but the file should be a platform-specific @tech{load handler}, but the file should be a platform-specific
@deftech{dynamic extension}, typically with the file suffix @filepath{.so} @deftech{dynamic extension}, typically with the file suffix
(Unix), @filepath{.dll} (Windows), or @filepath{.dylib} (Mac OS X). The file @filepath{.so} (Unix), @filepath{.dll} (Windows), or @filepath{.dylib}
is loaded using internal, OS-specific primitives. See (Mac OS X). The file is loaded using internal, OS-specific
@secref["inside-mzscheme"] for more information on @tech{dynamic primitives. See @italic{@secref[#:doc '(lib
extensions}.} "scribblings/inside/inside.scrbl") "top"]} for more information on
@tech{dynamic extensions}.}
@defproc[(load-extension [file path-string?]) any]{ @defproc[(load-extension [file path-string?]) any]{

View File

@ -41,7 +41,6 @@ where @schememodname[scheme] includes all of
This chapter provides some temporary hyper-link targets. This chapter provides some temporary hyper-link targets.
@subsection[#:tag "inside-mzscheme"]{Inside MzScheme}
@subsection[#:tag "running-sa"]{Running MzScheme} @subsection[#:tag "running-sa"]{Running MzScheme}
@subsection[#:tag "async-channel"]{Asynchronous Channels} @subsection[#:tag "async-channel"]{Asynchronous Channels}
@subsection[#:tag "honu"]{Honu} @subsection[#:tag "honu"]{Honu}

View File

@ -142,11 +142,12 @@ which must be bound as a @tech{top-level variable} or
@tech{module-level variable}. @tech{module-level variable}.
The result is useful to low-level extensions; see The result is useful to low-level extensions; see
@secref["inside-mzscheme"]. It can also be used with @italic{@secref[#:doc '(lib "scribblings/inside/inside.scrbl")
"top"]}. It can also be used with
@scheme[variable-reference->empty-namespace], @scheme[variable-reference->empty-namespace],
@scheme[variable-reference->resolved-module-path], and @scheme[variable-reference->resolved-module-path], and
@scheme[variable-reference->top-level-namespace], but facilities @scheme[variable-reference->top-level-namespace], but facilities like
like @scheme[define-namespace-anchor] and @scheme[define-namespace-anchor] and
@scheme[namespace-anchor->namespace] wrap those to provide an clearer @scheme[namespace-anchor->namespace] wrap those to provide an clearer
interface.} interface.}

View File

@ -5,6 +5,4 @@
(define list-mutable/c #t) (define list-mutable/c #t)
(define cons-mutable/c #t) (define cons-mutable/c #t)
(define arity? #f)
(provide (all-defined))) (provide (all-defined)))

View File

@ -171,16 +171,18 @@ Like @scheme[index], but the word to index is determined by applying
@scheme[content->string] on the parsed @scheme[pre-content] list.} @scheme[content->string] on the parsed @scheme[pre-content] list.}
@defproc[(section-index [word string?] ...)]{ @defproc[(section-index [word string?] ...)
part-index-decl?]{
Creates a @scheme[part-index-decl] to be associated with the enclosing Creates a @scheme[part-index-decl] to be associated with the enclosing
section by @scheme[decode]. The @scheme[word]s serve as both the keys section by @scheme[decode]. The @scheme[word]s serve as both the keys
and as the rendered forms of the keys.} and as the rendered forms of the keys.}
@defproc[(index-section [#:tag tag (or/c false/c string?) "doc-index"])]{ @defproc[(index-section [#:tag tag (or/c false/c string?) "doc-index"])
part?]{
Produces a section that shows the index the enclosing document. The Produces a part that shows the index the enclosing document. The
optional @scheme[tag] argument is used as the index section's tag.} optional @scheme[tag] argument is used as the index section's tag.}