mirror of
https://git.savannah.gnu.org/git/guile.git
synced 2025-04-30 11:50:28 +02:00
Remove SMOB tutorial; update manual.
* doc/ref/libguile-smobs.texi: Remove; this tutorial is superseded by libguile-foreign-objects. * doc/ref/libguile-foreign-objects.texi: Proofreading. * doc/ref/libguile-program.texi: Update Dia examples to refer to foreign objects. * doc/ref/libguile-concepts.texi (Garbage Collection): Update to accurately describe the BDW-GC, and to avoid reference to mark functions. * doc/ref/guile.texi: Remove libguile-smobs, and reword API menu. * doc/ref/api-utility.texi (Equality): Mention GOOPS instead of SMOBs. * doc/ref/api-smobs.texi (Smobs): Describe as a legacy interface. Exhort readers against the writing of mark functions. * doc/ref/api-foreign-objects.texi (Foreign Objects): Proofreading. * doc/ref/api-control.texi (Catch): Fix ref to point to foreign objects. * doc/ref/Makefile.am: Remove libguile-smobs.texi.
This commit is contained in:
parent
6e4630e01a
commit
d9a4a1cde1
10 changed files with 205 additions and 884 deletions
|
@ -83,7 +83,6 @@ guile_TEXINFOS = preface.texi \
|
||||||
compiler.texi \
|
compiler.texi \
|
||||||
fdl.texi \
|
fdl.texi \
|
||||||
libguile-concepts.texi \
|
libguile-concepts.texi \
|
||||||
libguile-smobs.texi \
|
|
||||||
libguile-foreign-objects.texi \
|
libguile-foreign-objects.texi \
|
||||||
libguile-snarf.texi \
|
libguile-snarf.texi \
|
||||||
libguile-linking.texi \
|
libguile-linking.texi \
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
@c -*-texinfo-*-
|
@c -*-texinfo-*-
|
||||||
@c This is part of the GNU Guile Reference Manual.
|
@c This is part of the GNU Guile Reference Manual.
|
||||||
@c Copyright (C) 1996, 1997, 2000, 2001, 2002, 2003, 2004, 2009, 2010,
|
@c Copyright (C) 1996, 1997, 2000, 2001, 2002, 2003, 2004, 2009, 2010,
|
||||||
@c 2011, 2012, 2013 Free Software Foundation, Inc.
|
@c 2011, 2012, 2013, 2014 Free Software Foundation, Inc.
|
||||||
@c See the file guile.texi for copying conditions.
|
@c See the file guile.texi for copying conditions.
|
||||||
|
|
||||||
@node Control Mechanisms
|
@node Control Mechanisms
|
||||||
|
@ -1184,13 +1184,13 @@ The @var{body_data} and @var{handler_data} parameters are passed to
|
||||||
the respective calls so an application can communicate extra
|
the respective calls so an application can communicate extra
|
||||||
information to those functions.
|
information to those functions.
|
||||||
|
|
||||||
If the data consists of an @code{SCM} object, care should be taken
|
If the data consists of an @code{SCM} object, care should be taken that
|
||||||
that it isn't garbage collected while still required. If the
|
it isn't garbage collected while still required. If the @code{SCM} is a
|
||||||
@code{SCM} is a local C variable, one way to protect it is to pass a
|
local C variable, one way to protect it is to pass a pointer to that
|
||||||
pointer to that variable as the data parameter, since the C compiler
|
variable as the data parameter, since the C compiler will then know the
|
||||||
will then know the value must be held on the stack. Another way is to
|
value must be held on the stack. Another way is to use
|
||||||
use @code{scm_remember_upto_here_1} (@pxref{Remembering During
|
@code{scm_remember_upto_here_1} (@pxref{Foreign Object Memory
|
||||||
Operations}).
|
Management}).
|
||||||
@end deftypefn
|
@end deftypefn
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -14,7 +14,8 @@ working with foreign objects. @xref{Defining New Foreign Object Types},
|
||||||
for a tutorial-like introduction to foreign objects.
|
for a tutorial-like introduction to foreign objects.
|
||||||
|
|
||||||
@deftp {C Type} scm_t_struct_finalize
|
@deftp {C Type} scm_t_struct_finalize
|
||||||
This type returns @code{void} and takes one @code{SCM} argument.
|
This function type returns @code{void} and takes one @code{SCM}
|
||||||
|
argument.
|
||||||
@end deftp
|
@end deftp
|
||||||
|
|
||||||
@deftypefn {C Function} SCM scm_make_foreign_object_type (SCM name, SCM slots, scm_t_struct_finalize finalizer)
|
@deftypefn {C Function} SCM scm_make_foreign_object_type (SCM name, SCM slots, scm_t_struct_finalize finalizer)
|
||||||
|
@ -73,9 +74,9 @@ initialize the first @var{n} fields to the given values, as appropriate.
|
||||||
The number of fields for objects of a given type is fixed when the type
|
The number of fields for objects of a given type is fixed when the type
|
||||||
is created. It is an error to give more initializers than there are
|
is created. It is an error to give more initializers than there are
|
||||||
fields in the value. It is perfectly fine to give fewer initializers
|
fields in the value. It is perfectly fine to give fewer initializers
|
||||||
than needed, however; this is convenient when some fields are of
|
than needed; this is convenient when some fields are of non-pointer
|
||||||
non-pointer types, and it would be easier to initialize them with the
|
types, and would be easier to initialize with the setters described
|
||||||
setters indicated below.
|
below.
|
||||||
@end deftypefn
|
@end deftypefn
|
||||||
|
|
||||||
@deftypefn {C Function} void* scm_foreign_object_ref (SCM obj, size_t n);
|
@deftypefn {C Function} void* scm_foreign_object_ref (SCM obj, size_t n);
|
||||||
|
|
|
@ -9,9 +9,17 @@
|
||||||
|
|
||||||
@cindex smob
|
@cindex smob
|
||||||
|
|
||||||
This chapter contains reference information related to defining and
|
A @dfn{smob} is a ``small object''. Before foreign objects were
|
||||||
working with smobs. See @ref{Defining New Types (Smobs)} for a
|
introduced in Guile 2.0.12 (@pxref{Foreign Objects}), smobs were the
|
||||||
tutorial-like introduction to smobs.
|
preferred way to for C code to define new kinds of Scheme objects. With
|
||||||
|
the exception of the so-called ``applicable SMOBs'' discussed below,
|
||||||
|
smobs are now a legacy interface and are headed for eventual
|
||||||
|
deprecation. @xref{Deprecation}. New code should use the foreign
|
||||||
|
object interface.
|
||||||
|
|
||||||
|
This section contains reference information related to defining and
|
||||||
|
working with smobs. For a tutorial-like introduction to smobs, see
|
||||||
|
``Defining New Types (Smobs)'' in previous versions of this manual.
|
||||||
|
|
||||||
@deftypefun scm_t_bits scm_make_smob_type (const char *name, size_t size)
|
@deftypefun scm_t_bits scm_make_smob_type (const char *name, size_t size)
|
||||||
This function adds a new smob type, named @var{name}, with instance size
|
This function adds a new smob type, named @var{name}, with instance size
|
||||||
|
@ -26,9 +34,8 @@ deallocate the memory block pointed to by @code{SCM_SMOB_DATA} with
|
||||||
@code{scm_gc_free} will be @var{name}.
|
@code{scm_gc_free} will be @var{name}.
|
||||||
|
|
||||||
Default values are provided for the @emph{mark}, @emph{free},
|
Default values are provided for the @emph{mark}, @emph{free},
|
||||||
@emph{print}, and @emph{equalp} functions, as described in
|
@emph{print}, and @emph{equalp} functions. If you want to customize any
|
||||||
@ref{Defining New Types (Smobs)}. If you want to customize any of
|
of these functions, the call to @code{scm_make_smob_type} should be
|
||||||
these functions, the call to @code{scm_make_smob_type} should be
|
|
||||||
immediately followed by calls to one or several of
|
immediately followed by calls to one or several of
|
||||||
@code{scm_set_smob_mark}, @code{scm_set_smob_free},
|
@code{scm_set_smob_mark}, @code{scm_set_smob_free},
|
||||||
@code{scm_set_smob_print}, and/or @code{scm_set_smob_equalp}.
|
@code{scm_set_smob_print}, and/or @code{scm_set_smob_equalp}.
|
||||||
|
@ -60,51 +67,30 @@ memory is automatically reclaimed by the garbage collector when it is no
|
||||||
longer needed (@pxref{Memory Blocks, @code{scm_gc_malloc}}).
|
longer needed (@pxref{Memory Blocks, @code{scm_gc_malloc}}).
|
||||||
@end deftypefn
|
@end deftypefn
|
||||||
|
|
||||||
Smob free functions must be thread-safe. @xref{Garbage Collecting
|
Smob free functions must be thread-safe. @xref{Foreign Object Memory
|
||||||
Smobs}, for a discussion on finalizers and concurrency. If you are
|
Management}, for a discussion on finalizers and concurrency. If you are
|
||||||
embedding Guile in an application that is not thread-safe, and you
|
embedding Guile in an application that is not thread-safe, and you
|
||||||
define smob types that need finalization, you might want to disable
|
define smob types that need finalization, you might want to disable
|
||||||
automatic finalization, and arrange to call
|
automatic finalization, and arrange to call
|
||||||
@code{scm_manually_run_finalizers ()} yourself.
|
@code{scm_manually_run_finalizers ()} yourself. @xref{Foreign Objects}.
|
||||||
|
|
||||||
@deftypefn {C Function} int scm_set_automatic_finalization_enabled (int enabled_p)
|
|
||||||
Enable or disable automatic finalization. By default, Guile arranges to
|
|
||||||
invoke object finalizers automatically, in a separate thread if
|
|
||||||
possible. Passing a zero value for @var{enabled_p} will disable
|
|
||||||
automatic finalization for Guile as a whole. If you disable automatic
|
|
||||||
finalization, you will have to call @code{scm_run_finalizers ()}
|
|
||||||
periodically.
|
|
||||||
|
|
||||||
Unlike most other Guile functions, you can call
|
|
||||||
@code{scm_set_automatic_finalization_enabled} before Guile has been
|
|
||||||
initialized.
|
|
||||||
|
|
||||||
Return the previous status of automatic finalization.
|
|
||||||
@end deftypefn
|
|
||||||
|
|
||||||
@deftypefn {C Function} int scm_run_finalizers (void)
|
|
||||||
Invoke any pending finalizers. Returns the number of finalizers that
|
|
||||||
were invoked. This function should be called when automatic
|
|
||||||
finalization is disabled, though it may be called if it is enabled as
|
|
||||||
well.
|
|
||||||
@end deftypefn
|
|
||||||
|
|
||||||
|
|
||||||
@cindex precise marking
|
|
||||||
|
|
||||||
@deftypefn {C Function} void scm_set_smob_mark (scm_t_bits tc, SCM (*mark) (SCM obj))
|
@deftypefn {C Function} void scm_set_smob_mark (scm_t_bits tc, SCM (*mark) (SCM obj))
|
||||||
This function sets the smob marking procedure for the smob type specified by
|
This function sets the smob marking procedure for the smob type specified by
|
||||||
the tag @var{tc}. @var{tc} is the tag returned by @code{scm_make_smob_type}.
|
the tag @var{tc}. @var{tc} is the tag returned by @code{scm_make_smob_type}.
|
||||||
|
|
||||||
Defining a marking procedure may sometimes be unnecessary because large
|
Defining a marking procedure is almost always the wrong thing to do. It
|
||||||
parts of the process' memory (with the exception of
|
is much, much preferable to allocate smob data with the
|
||||||
@code{scm_gc_malloc_pointerless} regions, and @code{malloc}- or
|
@code{scm_gc_malloc} and @code{scm_gc_malloc_pointerless} functions, and
|
||||||
@code{scm_malloc}-allocated memory) are scanned for live
|
allow the GC to trace pointers automatically.
|
||||||
pointers@footnote{Conversely, in Guile up to the 1.8 series, the marking
|
|
||||||
procedure was always required. The reason is that Guile's GC would only
|
Any mark procedures you see currently almost surely date from the time
|
||||||
look for pointers in the memory area used for built-in types (the
|
of Guile 1.8, before the switch to the Boehm-Demers-Weiser collector.
|
||||||
@dfn{cell heap}), not in user-allocated or statically allocated memory.
|
Such smob implementations should be changed to just use
|
||||||
This approach is often referred to as @dfn{precise marking}.}.
|
@code{scm_gc_malloc} and friends, and to lose their mark function.
|
||||||
|
|
||||||
|
If you decide to keep the mark function, note that it may be called on
|
||||||
|
objects that are on the free list. Please read and digest the comments
|
||||||
|
from the BDW GC's @code{gc/gc_mark.h} header.
|
||||||
|
|
||||||
The @var{mark} procedure must cause @code{scm_gc_mark} to be called
|
The @var{mark} procedure must cause @code{scm_gc_mark} to be called
|
||||||
for every @code{SCM} value that is directly referenced by the smob
|
for every @code{SCM} value that is directly referenced by the smob
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
@c -*-texinfo-*-
|
@c -*-texinfo-*-
|
||||||
@c This is part of the GNU Guile Reference Manual.
|
@c This is part of the GNU Guile Reference Manual.
|
||||||
@c Copyright (C) 1996, 1997, 2000, 2001, 2002, 2003, 2004, 2011, 2012, 2013
|
@c Copyright (C) 1996, 1997, 2000, 2001, 2002, 2003, 2004, 2011, 2012, 2013, 2014
|
||||||
@c Free Software Foundation, Inc.
|
@c Free Software Foundation, Inc.
|
||||||
@c See the file guile.texi for copying conditions.
|
@c See the file guile.texi for copying conditions.
|
||||||
|
|
||||||
|
@ -163,12 +163,14 @@ same.
|
||||||
into an infinite loop if asked to compare two circular lists or
|
into an infinite loop if asked to compare two circular lists or
|
||||||
similar.
|
similar.
|
||||||
|
|
||||||
New application-defined object types (@pxref{Defining New Types
|
GOOPS object types (@pxref{GOOPS}), including foreign object types
|
||||||
(Smobs)}) have an @code{equalp} handler which is called by
|
(@pxref{Defining New Foreign Object Types}), can have an @code{equal?}
|
||||||
@code{equal?}. This lets an application traverse the contents or
|
implementation specialized on two values of the same type. If
|
||||||
control what is considered @code{equal?} for two objects of such a
|
@code{equal?} is called on two GOOPS objects of the same type,
|
||||||
type. If there's no such handler, the default is to just compare as
|
@code{equal?} will dispatch out to a generic function. This lets an
|
||||||
per @code{eq?}.
|
application traverse the contents or control what is considered
|
||||||
|
@code{equal?} for two objects of such a type. If there's no such
|
||||||
|
handler, the default is to just compare as per @code{eq?}.
|
||||||
@end deffn
|
@end deffn
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -268,7 +268,6 @@ etc. that make up Guile's application programming interface (API),
|
||||||
* Linking Guile with Libraries:: To extend Guile itself.
|
* Linking Guile with Libraries:: To extend Guile itself.
|
||||||
* General Libguile Concepts:: General concepts for using libguile.
|
* General Libguile Concepts:: General concepts for using libguile.
|
||||||
* Defining New Foreign Object Types:: Adding new types to Guile.
|
* Defining New Foreign Object Types:: Adding new types to Guile.
|
||||||
* Defining New Types (Smobs):: Adding new types to Guile.
|
|
||||||
* Function Snarfing:: A way to define new functions.
|
* Function Snarfing:: A way to define new functions.
|
||||||
* Programming Overview:: An overview of Guile programming.
|
* Programming Overview:: An overview of Guile programming.
|
||||||
* Autoconf Support:: Putting m4 to good use.
|
* Autoconf Support:: Putting m4 to good use.
|
||||||
|
@ -279,7 +278,6 @@ etc. that make up Guile's application programming interface (API),
|
||||||
@include libguile-extensions.texi
|
@include libguile-extensions.texi
|
||||||
@include libguile-concepts.texi
|
@include libguile-concepts.texi
|
||||||
@include libguile-foreign-objects.texi
|
@include libguile-foreign-objects.texi
|
||||||
@include libguile-smobs.texi
|
|
||||||
@include libguile-snarf.texi
|
@include libguile-snarf.texi
|
||||||
@include libguile-program.texi
|
@include libguile-program.texi
|
||||||
@include libguile-autoconf.texi
|
@include libguile-autoconf.texi
|
||||||
|
@ -302,7 +300,7 @@ available through both Scheme and C interfaces.
|
||||||
* Simple Data Types:: Numbers, strings, booleans and so on.
|
* Simple Data Types:: Numbers, strings, booleans and so on.
|
||||||
* Compound Data Types:: Data types for holding other data.
|
* Compound Data Types:: Data types for holding other data.
|
||||||
* Foreign Objects:: Defining new data types in C.
|
* Foreign Objects:: Defining new data types in C.
|
||||||
* Smobs:: Defining new data types in C.
|
* Smobs:: Legacy version of foreign objects.
|
||||||
* Procedures:: Procedures.
|
* Procedures:: Procedures.
|
||||||
* Macros:: Extending the syntax of Scheme.
|
* Macros:: Extending the syntax of Scheme.
|
||||||
* Utility Functions:: General utility functions.
|
* Utility Functions:: General utility functions.
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
@c -*-texinfo-*-
|
@c -*-texinfo-*-
|
||||||
@c This is part of the GNU Guile Reference Manual.
|
@c This is part of the GNU Guile Reference Manual.
|
||||||
@c Copyright (C) 1996, 1997, 2000, 2001, 2002, 2003, 2004, 2005, 2010, 2013
|
@c Copyright (C) 1996, 1997, 2000, 2001, 2002, 2003, 2004, 2005, 2010, 2013, 2014
|
||||||
@c Free Software Foundation, Inc.
|
@c Free Software Foundation, Inc.
|
||||||
@c See the file guile.texi for copying conditions.
|
@c See the file guile.texi for copying conditions.
|
||||||
|
|
||||||
|
@ -191,38 +191,34 @@ periodically free all blocks that have been allocated but are not used
|
||||||
by any active Scheme values. This activity is called @dfn{garbage
|
by any active Scheme values. This activity is called @dfn{garbage
|
||||||
collection}.
|
collection}.
|
||||||
|
|
||||||
It is easy for Guile to remember all blocks of memory that it has
|
Guile's garbage collector will automatically discover references to
|
||||||
allocated for use by Scheme values, but you need to help it with finding
|
@code{SCM} objects that originate in global variables, static data
|
||||||
all Scheme values that are in use by C code.
|
sections, function arguments or local variables on the C and Scheme
|
||||||
|
stacks, and values in machine registers. Other references to @code{SCM}
|
||||||
|
objects, such as those in other random data structures in the C heap
|
||||||
|
that contain fields of type @code{SCM}, can be made visible to the
|
||||||
|
garbage collector by calling the functions @code{scm_gc_protect} or
|
||||||
|
@code{scm_permanent_object}. Collectively, these values form the ``root
|
||||||
|
set'' of garbage collection; any value on the heap that is referenced
|
||||||
|
directly or indirectly by a member of the root set is preserved, and all
|
||||||
|
other objects are eligible for reclamation.
|
||||||
|
|
||||||
You do this when writing a SMOB mark function, for example
|
The Scheme stack and heap are scanned precisely; that is to say, Guile
|
||||||
(@pxref{Garbage Collecting Smobs}). By calling this function, the
|
knows about all inter-object pointers on the Scheme stack and heap.
|
||||||
garbage collector learns about all references that your SMOB has to
|
This is not the case, unfortunately, for pointers on the C stack and
|
||||||
other @code{SCM} values.
|
static data segment. For this reason we have to scan the C stack and
|
||||||
|
static data segment @dfn{conservatively}; any value that looks like a
|
||||||
Other references to @code{SCM} objects, such as global variables of type
|
pointer to a GC-managed object is treated as such, whether it actually
|
||||||
@code{SCM} or other random data structures in the heap that contain
|
is a reference or not. Thus, scanning the C stack and static data
|
||||||
fields of type @code{SCM}, can be made visible to the garbage collector
|
segment is guaranteed to find all actual references, but it might also
|
||||||
by calling the functions @code{scm_gc_protect} or
|
find words that only accidentally look like references. These ``false
|
||||||
@code{scm_permanent_object}. You normally use these functions for long
|
positives'' might keep @code{SCM} objects alive that would otherwise be
|
||||||
lived objects such as a hash table that is stored in a global variable.
|
considered dead. While this might waste memory, keeping an object
|
||||||
For temporary references in local variables or function arguments, using
|
around longer than it strictly needs to is harmless. This is why this
|
||||||
these functions would be too expensive.
|
technique is called ``conservative garbage collection''. In practice,
|
||||||
|
the wasted memory seems to be no problem, as the static C root set is
|
||||||
These references are handled differently: Local variables (and function
|
almost always finite and small, given that the Scheme stack is separate
|
||||||
arguments) of type @code{SCM} are automatically visible to the garbage
|
from the C stack.
|
||||||
collector. This works because the collector scans the stack for
|
|
||||||
potential references to @code{SCM} objects and considers all referenced
|
|
||||||
objects to be alive. The scanning considers each and every word of the
|
|
||||||
stack, regardless of what it is actually used for, and then decides
|
|
||||||
whether it could possibly be a reference to a @code{SCM} object. Thus,
|
|
||||||
the scanning is guaranteed to find all actual references, but it might
|
|
||||||
also find words that only accidentally look like references. These
|
|
||||||
`false positives' might keep @code{SCM} objects alive that would
|
|
||||||
otherwise be considered dead. While this might waste memory, keeping an
|
|
||||||
object around longer than it strictly needs to is harmless. This is why
|
|
||||||
this technique is called ``conservative garbage collection''. In
|
|
||||||
practice, the wasted memory seems to be no problem.
|
|
||||||
|
|
||||||
The stack of every thread is scanned in this way and the registers of
|
The stack of every thread is scanned in this way and the registers of
|
||||||
the CPU and all other memory locations where local variables or function
|
the CPU and all other memory locations where local variables or function
|
||||||
|
@ -245,17 +241,17 @@ wanted.
|
||||||
There are situations, however, where a @code{SCM} object needs to be
|
There are situations, however, where a @code{SCM} object needs to be
|
||||||
around longer than its reference from a local variable or function
|
around longer than its reference from a local variable or function
|
||||||
parameter. This happens, for example, when you retrieve some pointer
|
parameter. This happens, for example, when you retrieve some pointer
|
||||||
from a smob and work with that pointer directly. The reference to the
|
from a foreign object and work with that pointer directly. The
|
||||||
@code{SCM} smob object might be dead after the pointer has been
|
reference to the @code{SCM} foreign object might be dead after the
|
||||||
retrieved, but the pointer itself (and the memory pointed to) is still
|
pointer has been retrieved, but the pointer itself (and the memory
|
||||||
in use and thus the smob object must be protected. The compiler does
|
pointed to) is still in use and thus the foreign object must be
|
||||||
not know about this connection and might overwrite the @code{SCM}
|
protected. The compiler does not know about this connection and might
|
||||||
reference too early.
|
overwrite the @code{SCM} reference too early.
|
||||||
|
|
||||||
To get around this problem, you can use @code{scm_remember_upto_here_1}
|
To get around this problem, you can use @code{scm_remember_upto_here_1}
|
||||||
and its cousins. It will keep the compiler from overwriting the
|
and its cousins. It will keep the compiler from overwriting the
|
||||||
reference. For a typical example of its use, see @ref{Remembering
|
reference. @xref{Foreign Object Memory Management}.
|
||||||
During Operations}.
|
|
||||||
|
|
||||||
@node Control Flow
|
@node Control Flow
|
||||||
@subsection Control Flow
|
@subsection Control Flow
|
||||||
|
|
|
@ -86,8 +86,8 @@ All objects of a given foreign type have the same number of slots. In
|
||||||
the example from the previous section, the @code{image} type has one
|
the example from the previous section, the @code{image} type has one
|
||||||
slot, because the slots list passed to
|
slot, because the slots list passed to
|
||||||
@code{scm_make_foreign_object_type} is of length one. (The actual names
|
@code{scm_make_foreign_object_type} is of length one. (The actual names
|
||||||
given to slots are unimportant for most users the C interface, but can
|
given to slots are unimportant for most users of the C interface, but
|
||||||
be used on the Scheme side to introspect on the foreign object.)
|
can be used on the Scheme side to introspect on the foreign object.)
|
||||||
|
|
||||||
To construct a foreign object and initialize its first slot, call
|
To construct a foreign object and initialize its first slot, call
|
||||||
@code{scm_make_foreign_object_1 (@var{type}, @var{first_slot_value})}.
|
@code{scm_make_foreign_object_1 (@var{type}, @var{first_slot_value})}.
|
||||||
|
@ -113,7 +113,7 @@ allocated by some other, Guile-unaware part of your program -- then you
|
||||||
will probably need to implement a finalizer. @xref{Foreign Object
|
will probably need to implement a finalizer. @xref{Foreign Object
|
||||||
Memory Management}, for more.
|
Memory Management}, for more.
|
||||||
|
|
||||||
Continuing the example from above, if the global variable
|
Continuing the example from the previous section, if the global variable
|
||||||
@code{image_type} contains the type returned by
|
@code{image_type} contains the type returned by
|
||||||
@code{scm_make_foreign_object_type}, here is how we could construct a
|
@code{scm_make_foreign_object_type}, here is how we could construct a
|
||||||
foreign object whose ``data'' field contains a pointer to a freshly
|
foreign object whose ``data'' field contains a pointer to a freshly
|
||||||
|
@ -214,15 +214,15 @@ resources when the foreign object is reclaimed.
|
||||||
As discussed in @pxref{Garbage Collection}, Guile's garbage collector
|
As discussed in @pxref{Garbage Collection}, Guile's garbage collector
|
||||||
will reclaim inaccessible memory as needed. This reclamation process
|
will reclaim inaccessible memory as needed. This reclamation process
|
||||||
runs concurrently with the main program. When Guile analyzes the heap
|
runs concurrently with the main program. When Guile analyzes the heap
|
||||||
and detemines that an object's memory can be reclaimed, that memory is
|
and determines that an object's memory can be reclaimed, that memory is
|
||||||
simply put on a ``free list'' of objects that can be reclaimed. Usually
|
put on a ``free list'' of objects that can be reclaimed. Usually that's
|
||||||
that's the end of it -- that's all that garbage collection does, in
|
the end of it---the object is available for immediate re-use. However
|
||||||
Guile. However some objects can have ``finalizers'' associated with
|
some objects can have ``finalizers'' associated with them---functions
|
||||||
them -- functions that are called on reclaimable objects to effect any
|
that are called on reclaimable objects to effect any external cleanup
|
||||||
external cleanup actions.
|
actions.
|
||||||
|
|
||||||
Finalizers are tricky business and it is best to avoid them. They can
|
Finalizers are tricky business and it is best to avoid them. They can
|
||||||
be invoked at unexpected times, or not at all -- for example, they are
|
be invoked at unexpected times, or not at all---for example, they are
|
||||||
not invoked on process exit. They don't help the garbage collector do
|
not invoked on process exit. They don't help the garbage collector do
|
||||||
its job; in fact, they are a hindrance. Furthermore, they perturb the
|
its job; in fact, they are a hindrance. Furthermore, they perturb the
|
||||||
garbage collector's internal accounting. The GC decides to scan the
|
garbage collector's internal accounting. The GC decides to scan the
|
||||||
|
@ -234,8 +234,8 @@ is higher than what the GC thinks it should be.
|
||||||
|
|
||||||
All those caveats aside, some foreign object types will need finalizers.
|
All those caveats aside, some foreign object types will need finalizers.
|
||||||
For example, if we had a foreign object type that wrapped file
|
For example, if we had a foreign object type that wrapped file
|
||||||
descriptors -- and we aren't suggesting this, as Guile already has ports
|
descriptors---and we aren't suggesting this, as Guile already has ports
|
||||||
-- then you might define the type like this:
|
---then you might define the type like this:
|
||||||
|
|
||||||
@example
|
@example
|
||||||
static SCM file_type;
|
static SCM file_type;
|
||||||
|
@ -244,9 +244,11 @@ static void
|
||||||
finalize_file (SCM file)
|
finalize_file (SCM file)
|
||||||
@{
|
@{
|
||||||
int fd = scm_foreign_object_signed_ref (file, 0);
|
int fd = scm_foreign_object_signed_ref (file, 0);
|
||||||
scm_foreign_object_set_x (file, 0, -1);
|
|
||||||
if (fd >= 0)
|
if (fd >= 0)
|
||||||
|
@{
|
||||||
|
scm_foreign_object_signed_set_x (file, 0, -1);
|
||||||
close (fd);
|
close (fd);
|
||||||
|
@}
|
||||||
@}
|
@}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -273,13 +275,14 @@ make_file (int fd)
|
||||||
@cindex finalizer
|
@cindex finalizer
|
||||||
@cindex finalization
|
@cindex finalization
|
||||||
|
|
||||||
Note that the finalizer can be called in any context. In particular, if
|
Note that the finalizer may be invoked in ways and at times you might
|
||||||
the user's Guile is built with support for threads, the finalizer may be
|
not expect. In particular, if the user's Guile is built with support
|
||||||
called from any thread that is running Guile. In Guile 2.0, finalizers
|
for threads, the finalizer may be called from any thread that is running
|
||||||
are invoked via ``asyncs'', which interleaves them with running Scheme
|
Guile. In Guile 2.0, finalizers are invoked via ``asyncs'', which
|
||||||
code; @pxref{System asyncs}. In Guile 2.2 there will be a dedicated
|
interleaves them with running Scheme code; @pxref{System asyncs}. In
|
||||||
finalization thread, to ensure that the finalization doesn't run within
|
Guile 2.2 there will be a dedicated finalization thread, to ensure that
|
||||||
the critical section of any other thread known to Guile.
|
the finalization doesn't run within the critical section of any other
|
||||||
|
thread known to Guile.
|
||||||
|
|
||||||
In either case, finalizers run concurrently with the main program, and
|
In either case, finalizers run concurrently with the main program, and
|
||||||
so they need to be async-safe and thread-safe. If for some reason this
|
so they need to be async-safe and thread-safe. If for some reason this
|
||||||
|
@ -399,8 +402,8 @@ the equivalent of @code{scm_make_foreign_object_type}, is a struct
|
||||||
vtable. @xref{Vtables}, for more information. To instantiate the
|
vtable. @xref{Vtables}, for more information. To instantiate the
|
||||||
foreign object, which is really a Guile struct, we use @code{make}. (We
|
foreign object, which is really a Guile struct, we use @code{make}. (We
|
||||||
could have used @code{make-struct/no-tail}, but as an implementation
|
could have used @code{make-struct/no-tail}, but as an implementation
|
||||||
detail, finalizer are attached in the @code{initialize} method called by
|
detail, finalizers are attached in the @code{initialize} method called
|
||||||
@code{make}). To access the fields, we use @code{struct-ref} and
|
by @code{make}). To access the fields, we use @code{struct-ref} and
|
||||||
@code{struct-set!}. @xref{Structure Basics}.
|
@code{struct-set!}. @xref{Structure Basics}.
|
||||||
|
|
||||||
There is a convenience syntax, @code{define-foreign-object-type}, that
|
There is a convenience syntax, @code{define-foreign-object-type}, that
|
||||||
|
@ -463,21 +466,21 @@ As a final note, you might wonder how this system supports encapsulation
|
||||||
of sensitive values. First, we have to recognize that some facilities
|
of sensitive values. First, we have to recognize that some facilities
|
||||||
are essentially unsafe and have global scope. For example, in C, the
|
are essentially unsafe and have global scope. For example, in C, the
|
||||||
integrity and confidentiality of a part of a program is at the mercy of
|
integrity and confidentiality of a part of a program is at the mercy of
|
||||||
every other part of that program -- because any memory could potentially
|
every other part of that program -- because any part of the program can
|
||||||
access any other. At the same time, principled access to structured
|
read and write anything in its address space. At the same time,
|
||||||
data is organized in C on lexical boundaries; if you don't expose
|
principled access to structured data is organized in C on lexical
|
||||||
accessors for your object, you trust other parts of the program not to
|
boundaries; if you don't expose accessors for your object, you trust
|
||||||
access it.
|
other parts of the program not to work around that barrier.
|
||||||
|
|
||||||
The answer is similar in Scheme. Although Scheme's unsafe constructs
|
The situation is not dissimilar in Scheme. Although Scheme's unsafe
|
||||||
are fewer in number than in C, they do exist. The @code{(system
|
constructs are fewer in number than in C, they do exist. The
|
||||||
foreign)} module can be used to violate confidentiality and integrity,
|
@code{(system foreign)} module can be used to violate confidentiality
|
||||||
and shouldn't be exposed to untrusted code. Although @code{struct-ref}
|
and integrity, and shouldn't be exposed to untrusted code. Although
|
||||||
and @code{struct-set!} are less unsafe, they still have a cross-cutting
|
@code{struct-ref} and @code{struct-set!} are less unsafe, they still
|
||||||
capability of drilling through abstractions. Performing a
|
have a cross-cutting capability of drilling through abstractions.
|
||||||
@code{struct-set!} on a foreign object slot could cause unsafe foreign
|
Performing a @code{struct-set!} on a foreign object slot could cause
|
||||||
code to crash. Ultimately, structures in Scheme are capabilities for
|
unsafe foreign code to crash. Ultimately, structures in Scheme are
|
||||||
abstraction, and not abstractions themselves.
|
capabilities for abstraction, and not abstractions themselves.
|
||||||
|
|
||||||
That leaves us with the lexical capabilities, like constructors and
|
That leaves us with the lexical capabilities, like constructors and
|
||||||
accessors. Here is where encapsulation lies: the practical degree to
|
accessors. Here is where encapsulation lies: the practical degree to
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
@c -*-texinfo-*-
|
@c -*-texinfo-*-
|
||||||
@c This is part of the GNU Guile Reference Manual.
|
@c This is part of the GNU Guile Reference Manual.
|
||||||
@c Copyright (C) 1996, 1997, 2000, 2001, 2002, 2003, 2004, 2005
|
@c Copyright (C) 1996, 1997, 2000, 2001, 2002, 2003, 2004, 2005, 2014
|
||||||
@c Free Software Foundation, Inc.
|
@c Free Software Foundation, Inc.
|
||||||
@c See the file guile.texi for copying conditions.
|
@c See the file guile.texi for copying conditions.
|
||||||
|
|
||||||
|
@ -46,7 +46,7 @@ applications in general.
|
||||||
@menu
|
@menu
|
||||||
* Dia Objective:: Deciding why you want to add Guile.
|
* Dia Objective:: Deciding why you want to add Guile.
|
||||||
* Dia Steps:: Four steps required to add Guile.
|
* Dia Steps:: Four steps required to add Guile.
|
||||||
* Dia Smobs:: How to represent Dia data in Scheme.
|
* Dia Objects:: How to represent Dia data in Scheme.
|
||||||
* Dia Primitives:: Writing Guile primitives for Dia.
|
* Dia Primitives:: Writing Guile primitives for Dia.
|
||||||
* Dia Hook:: Providing a hook for Scheme evaluation.
|
* Dia Hook:: Providing a hook for Scheme evaluation.
|
||||||
* Dia Structure:: Overall structure for adding Guile.
|
* Dia Structure:: Overall structure for adding Guile.
|
||||||
|
@ -115,8 +115,8 @@ First, you need a way of representing your application-specific objects
|
||||||
--- such as @code{shape} in the previous example --- when they are
|
--- such as @code{shape} in the previous example --- when they are
|
||||||
passed into the Scheme world. Unless your objects are so simple that
|
passed into the Scheme world. Unless your objects are so simple that
|
||||||
they map naturally into builtin Scheme data types like numbers and
|
they map naturally into builtin Scheme data types like numbers and
|
||||||
strings, you will probably want to use Guile's @dfn{SMOB} interface to
|
strings, you will probably want to use Guile's @dfn{foreign object}
|
||||||
create a new Scheme data type for your objects.
|
interface to create a new Scheme data type for your objects.
|
||||||
|
|
||||||
Second, you need to write code for the basic operations like
|
Second, you need to write code for the basic operations like
|
||||||
@code{for-each-shape} and @code{square?} such that they access and
|
@code{for-each-shape} and @code{square?} such that they access and
|
||||||
|
@ -129,17 +129,18 @@ evaluated.
|
||||||
|
|
||||||
Finally, you need to restructure your top-level application C code a
|
Finally, you need to restructure your top-level application C code a
|
||||||
little so that it initializes the Guile interpreter correctly and
|
little so that it initializes the Guile interpreter correctly and
|
||||||
declares your @dfn{SMOBs} and @dfn{primitives} to the Scheme world.
|
declares your @dfn{foreign objects} and @dfn{primitives} to the Scheme
|
||||||
|
world.
|
||||||
|
|
||||||
The following subsections expand on these four points in turn.
|
The following subsections expand on these four points in turn.
|
||||||
|
|
||||||
|
|
||||||
@node Dia Smobs
|
@node Dia Objects
|
||||||
@subsubsection How to Represent Dia Data in Scheme
|
@subsubsection How to Represent Dia Data in Scheme
|
||||||
|
|
||||||
For all but the most trivial applications, you will probably want to
|
For all but the most trivial applications, you will probably want to
|
||||||
allow some representation of your domain objects to exist on the Scheme
|
allow some representation of your domain objects to exist on the Scheme
|
||||||
level. This is where the idea of SMOBs comes in, and with it issues of
|
level. This is where foreign objects come in, and with them issues of
|
||||||
lifetime management and garbage collection.
|
lifetime management and garbage collection.
|
||||||
|
|
||||||
To get more concrete about this, let's look again at the example we gave
|
To get more concrete about this, let's look again at the example we gave
|
||||||
|
@ -189,21 +190,21 @@ finished evaluation. How do we avoid this happening?
|
||||||
@end itemize
|
@end itemize
|
||||||
|
|
||||||
One resolution of these issues is for the Scheme-level representation of
|
One resolution of these issues is for the Scheme-level representation of
|
||||||
a shape to be a new, Scheme-specific C structure wrapped up as a SMOB.
|
a shape to be a new, Scheme-specific C structure wrapped up as a foreign
|
||||||
The SMOB is what is passed into and out of Scheme code, and the
|
object. The foreign object is what is passed into and out of Scheme
|
||||||
Scheme-specific C structure inside the SMOB points to Dia's underlying C
|
code, and the Scheme-specific C structure inside the foreign object
|
||||||
structure so that the code for primitives like @code{square?} can get at
|
points to Dia's underlying C structure so that the code for primitives
|
||||||
it.
|
like @code{square?} can get at it.
|
||||||
|
|
||||||
To cope with an underlying shape being deleted while Scheme code is
|
To cope with an underlying shape being deleted while Scheme code is
|
||||||
still holding onto a Scheme shape value, the underlying C structure
|
still holding onto a Scheme shape value, the underlying C structure
|
||||||
should have a new field that points to the Scheme-specific SMOB. When a
|
should have a new field that points to the Scheme-specific foreign
|
||||||
shape is deleted, the relevant code chains through to the
|
object. When a shape is deleted, the relevant code chains through to
|
||||||
Scheme-specific structure and sets its pointer back to the underlying
|
the Scheme-specific structure and sets its pointer back to the
|
||||||
structure to NULL. Thus the SMOB value for the shape continues to
|
underlying structure to NULL. Thus the foreign object value for the
|
||||||
exist, but any primitive code that tries to use it will detect that the
|
shape continues to exist, but any primitive code that tries to use it
|
||||||
underlying shape has been deleted because the underlying structure
|
will detect that the underlying shape has been deleted because the
|
||||||
pointer is NULL.
|
underlying structure pointer is NULL.
|
||||||
|
|
||||||
So, to summarize the steps involved in this resolution of the problem
|
So, to summarize the steps involved in this resolution of the problem
|
||||||
(and assuming that the underlying C structure for a shape is
|
(and assuming that the underlying C structure for a shape is
|
||||||
|
@ -238,33 +239,33 @@ struct dia_shape
|
||||||
underlying shape is deleted.
|
underlying shape is deleted.
|
||||||
|
|
||||||
@item
|
@item
|
||||||
Wrap @code{struct dia_guile_shape} as a SMOB type.
|
Wrap @code{struct dia_guile_shape} as a foreign object type.
|
||||||
|
|
||||||
@item
|
@item
|
||||||
Whenever you need to represent a C shape onto the Scheme level, create a
|
Whenever you need to represent a C shape onto the Scheme level, create a
|
||||||
SMOB instance for it, and pass that.
|
foreign object instance for it, and pass that.
|
||||||
|
|
||||||
@item
|
@item
|
||||||
In primitive code that receives a shape SMOB instance, check the
|
In primitive code that receives a shape foreign object instance, check the
|
||||||
@code{c_shape} field when decoding it, to find out whether the
|
@code{c_shape} field when decoding it, to find out whether the
|
||||||
underlying C shape is still there.
|
underlying C shape is still there.
|
||||||
@end itemize
|
@end itemize
|
||||||
|
|
||||||
As far as memory management is concerned, the SMOB values and their
|
As far as memory management is concerned, the foreign object values and
|
||||||
Scheme-specific structures are under the control of the garbage
|
their Scheme-specific structures are under the control of the garbage
|
||||||
collector, whereas the underlying C structures are explicitly managed in
|
collector, whereas the underlying C structures are explicitly managed in
|
||||||
exactly the same way that Dia managed them before we thought of adding
|
exactly the same way that Dia managed them before we thought of adding
|
||||||
Guile.
|
Guile.
|
||||||
|
|
||||||
When the garbage collector decides to free a shape SMOB value, it calls
|
When the garbage collector decides to free a shape foreign object value,
|
||||||
the @dfn{SMOB free} function that was specified when defining the shape
|
it calls the @dfn{finalizer} function that was specified when defining
|
||||||
SMOB type. To maintain the correctness of the @code{guile_shape} field
|
the shape foreign object type. To maintain the correctness of the
|
||||||
in the underlying C structure, this function should chain through to the
|
@code{guile_shape} field in the underlying C structure, this function
|
||||||
underlying C structure (if it still exists) and set its
|
should chain through to the underlying C structure (if it still exists)
|
||||||
@code{guile_shape} field to NULL.
|
and set its @code{guile_shape} field to NULL.
|
||||||
|
|
||||||
For full documentation on defining and using SMOB types, see
|
For full documentation on defining and using foreign object types, see
|
||||||
@ref{Defining New Types (Smobs)}.
|
@ref{Defining New Foreign Object Types}.
|
||||||
|
|
||||||
|
|
||||||
@node Dia Primitives
|
@node Dia Primitives
|
||||||
|
@ -283,11 +284,11 @@ static SCM square_p (SCM shape)
|
||||||
@{
|
@{
|
||||||
struct dia_guile_shape * guile_shape;
|
struct dia_guile_shape * guile_shape;
|
||||||
|
|
||||||
/* Check that arg is really a shape SMOB. */
|
/* Check that arg is really a shape object. */
|
||||||
scm_assert_smob_type (shape_tag, shape);
|
scm_assert_foreign_object_type (shape_type, shape);
|
||||||
|
|
||||||
/* Access Scheme-specific shape structure. */
|
/* Access Scheme-specific shape structure. */
|
||||||
guile_shape = SCM_SMOB_DATA (shape);
|
guile_shape = scm_foreign_object_ref (shape, 0);
|
||||||
|
|
||||||
/* Find out if underlying shape exists and is a
|
/* Find out if underlying shape exists and is a
|
||||||
square; return answer as a Scheme boolean. */
|
square; return answer as a Scheme boolean. */
|
||||||
|
@ -297,26 +298,28 @@ static SCM square_p (SCM shape)
|
||||||
@end lisp
|
@end lisp
|
||||||
|
|
||||||
Notice how easy it is to chain through from the @code{SCM shape}
|
Notice how easy it is to chain through from the @code{SCM shape}
|
||||||
parameter that @code{square_p} receives --- which is a SMOB --- to the
|
parameter that @code{square_p} receives --- which is a foreign object
|
||||||
Scheme-specific structure inside the SMOB, and thence to the underlying
|
--- to the Scheme-specific structure inside the foreign object, and
|
||||||
C structure for the shape.
|
thence to the underlying C structure for the shape.
|
||||||
|
|
||||||
In this code, @code{scm_assert_smob_type}, @code{SCM_SMOB_DATA}, and
|
In this code, @code{scm_assert_foreign_object_type},
|
||||||
@code{scm_from_bool} are from the standard Guile API. We assume that
|
@code{scm_foreign_object_ref}, and @code{scm_from_bool} are from the
|
||||||
@code{shape_tag} was given to us when we made the shape SMOB type, using
|
standard Guile API. We assume that @code{shape_type} was given to us
|
||||||
@code{scm_make_smob_type}. The call to @code{scm_assert_smob_type}
|
when we made the shape foreign object type, using
|
||||||
ensures that @var{shape} is indeed a shape. This is needed to guard
|
@code{scm_make_foreign_object_type}. The call to
|
||||||
against Scheme code using the @code{square?} procedure incorrectly, as
|
@code{scm_assert_foreign_object_type} ensures that @var{shape} is indeed
|
||||||
in @code{(square? "hello")}; Scheme's latent typing means that usage
|
a shape. This is needed to guard against Scheme code using the
|
||||||
errors like this must be caught at run time.
|
@code{square?} procedure incorrectly, as in @code{(square? "hello")};
|
||||||
|
Scheme's latent typing means that usage errors like this must be caught
|
||||||
|
at run time.
|
||||||
|
|
||||||
Having written the C code for your primitives, you need to make them
|
Having written the C code for your primitives, you need to make them
|
||||||
available as Scheme procedures by calling the @code{scm_c_define_gsubr}
|
available as Scheme procedures by calling the @code{scm_c_define_gsubr}
|
||||||
function. @code{scm_c_define_gsubr} (@pxref{Primitive Procedures}) takes arguments that
|
function. @code{scm_c_define_gsubr} (@pxref{Primitive Procedures})
|
||||||
specify the Scheme-level name for the primitive and how many required,
|
takes arguments that specify the Scheme-level name for the primitive and
|
||||||
optional and rest arguments it can accept. The @code{square?} primitive
|
how many required, optional and rest arguments it can accept. The
|
||||||
always requires exactly one argument, so the call to make it available
|
@code{square?} primitive always requires exactly one argument, so the
|
||||||
in Scheme reads like this:
|
call to make it available in Scheme reads like this:
|
||||||
|
|
||||||
@lisp
|
@lisp
|
||||||
scm_c_define_gsubr ("square?", 1, 0, 0, square_p);
|
scm_c_define_gsubr ("square?", 1, 0, 0, square_p);
|
||||||
|
@ -384,7 +387,7 @@ do lots of initialization and setup stuff
|
||||||
|
|
||||||
@itemize @bullet
|
@itemize @bullet
|
||||||
@item
|
@item
|
||||||
define all SMOB types
|
define all foreign object types
|
||||||
@item
|
@item
|
||||||
export primitives to Scheme using @code{scm_c_define_gsubr}
|
export primitives to Scheme using @code{scm_c_define_gsubr}
|
||||||
@item
|
@item
|
||||||
|
@ -397,13 +400,13 @@ In other words, you move the guts of what was previously in your
|
||||||
then add a @code{scm_boot_guile} call, with @code{inner_main} as a
|
then add a @code{scm_boot_guile} call, with @code{inner_main} as a
|
||||||
parameter, to the end of @code{main}.
|
parameter, to the end of @code{main}.
|
||||||
|
|
||||||
Assuming that you are using SMOBs and have written primitive code as
|
Assuming that you are using foreign objects and have written primitive
|
||||||
described in the preceding subsections, you also need to insert calls to
|
code as described in the preceding subsections, you also need to insert
|
||||||
declare your new SMOBs and export the primitives to Scheme. These
|
calls to declare your new foreign objects and export the primitives to
|
||||||
declarations must happen @emph{inside} the dynamic scope of the
|
Scheme. These declarations must happen @emph{inside} the dynamic scope
|
||||||
@code{scm_boot_guile} call, but also @emph{before} any code is run that
|
of the @code{scm_boot_guile} call, but also @emph{before} any code is
|
||||||
could possibly use them --- the beginning of @code{inner_main} is an
|
run that could possibly use them --- the beginning of @code{inner_main}
|
||||||
ideal place for this.
|
is an ideal place for this.
|
||||||
|
|
||||||
|
|
||||||
@node Dia Advanced
|
@node Dia Advanced
|
||||||
|
@ -425,7 +428,8 @@ move the code that lays out and displays Dia objects from C to Scheme.
|
||||||
|
|
||||||
As you follow this path, it naturally becomes less useful to maintain a
|
As you follow this path, it naturally becomes less useful to maintain a
|
||||||
distinction between Dia's original non-Guile-related source code, and
|
distinction between Dia's original non-Guile-related source code, and
|
||||||
its later code implementing SMOBs and primitives for the Scheme world.
|
its later code implementing foreign objects and primitives for the
|
||||||
|
Scheme world.
|
||||||
|
|
||||||
For example, suppose that the original source code had a
|
For example, suppose that the original source code had a
|
||||||
@code{dia_change_fill_pattern} function:
|
@code{dia_change_fill_pattern} function:
|
||||||
|
@ -440,8 +444,8 @@ void dia_change_fill_pattern (struct dia_shape * shape,
|
||||||
|
|
||||||
During initial Guile integration, you add a @code{change_fill_pattern}
|
During initial Guile integration, you add a @code{change_fill_pattern}
|
||||||
primitive for Scheme purposes, which accesses the underlying structures
|
primitive for Scheme purposes, which accesses the underlying structures
|
||||||
from its SMOB values and uses @code{dia_change_fill_pattern} to do the
|
from its foreign object values and uses @code{dia_change_fill_pattern}
|
||||||
real work:
|
to do the real work:
|
||||||
|
|
||||||
@lisp
|
@lisp
|
||||||
SCM change_fill_pattern (SCM shape, SCM pattern)
|
SCM change_fill_pattern (SCM shape, SCM pattern)
|
||||||
|
@ -487,22 +491,23 @@ So further Guile integration progressively @emph{reduces} the amount of
|
||||||
functional C code that you have to maintain over the long term.
|
functional C code that you have to maintain over the long term.
|
||||||
|
|
||||||
A similar argument applies to data representation. In the discussion of
|
A similar argument applies to data representation. In the discussion of
|
||||||
SMOBs earlier, issues arose because of the different memory management
|
foreign objects earlier, issues arose because of the different memory
|
||||||
and lifetime models that normally apply to data structures in C and in
|
management and lifetime models that normally apply to data structures in
|
||||||
Scheme. However, with further Guile integration, you can resolve this
|
C and in Scheme. However, with further Guile integration, you can
|
||||||
issue in a more radical way by allowing all your data structures to be
|
resolve this issue in a more radical way by allowing all your data
|
||||||
under the control of the garbage collector, and kept alive by references
|
structures to be under the control of the garbage collector, and kept
|
||||||
from the Scheme world. Instead of maintaining an array or linked list
|
alive by references from the Scheme world. Instead of maintaining an
|
||||||
of shapes in C, you would instead maintain a list in Scheme.
|
array or linked list of shapes in C, you would instead maintain a list
|
||||||
|
in Scheme.
|
||||||
|
|
||||||
Rather like the coalescing of @code{dia_change_fill_pattern} and
|
Rather like the coalescing of @code{dia_change_fill_pattern} and
|
||||||
@code{change_fill_pattern}, the practical upshot of such a change is
|
@code{change_fill_pattern}, the practical upshot of such a change is
|
||||||
that you would no longer have to keep the @code{dia_shape} and
|
that you would no longer have to keep the @code{dia_shape} and
|
||||||
@code{dia_guile_shape} structures separate, and so wouldn't need to
|
@code{dia_guile_shape} structures separate, and so wouldn't need to
|
||||||
worry about the pointers between them. Instead, you could change the
|
worry about the pointers between them. Instead, you could change the
|
||||||
SMOB definition to wrap the @code{dia_shape} structure directly, and
|
foreign object definition to wrap the @code{dia_shape} structure
|
||||||
send @code{dia_guile_shape} off to the scrap yard. Cut out the middle
|
directly, and send @code{dia_guile_shape} off to the scrap yard. Cut
|
||||||
man!
|
out the middle man!
|
||||||
|
|
||||||
Finally, we come to the holy grail of Guile's free software / extension
|
Finally, we come to the holy grail of Guile's free software / extension
|
||||||
language approach. Once you have a Scheme representation for
|
language approach. Once you have a Scheme representation for
|
||||||
|
|
|
@ -1,669 +0,0 @@
|
||||||
@c -*-texinfo-*-
|
|
||||||
@c This is part of the GNU Guile Reference Manual.
|
|
||||||
@c Copyright (C) 1996, 1997, 2000, 2001, 2002, 2003, 2004, 2005, 2010, 2011, 2013, 2014
|
|
||||||
@c Free Software Foundation, Inc.
|
|
||||||
@c See the file guile.texi for copying conditions.
|
|
||||||
|
|
||||||
@node Defining New Types (Smobs)
|
|
||||||
@section Defining New Types (Smobs)
|
|
||||||
|
|
||||||
@dfn{Smobs} are Guile's mechanism for adding new primitive types to
|
|
||||||
the system. The term ``smob'' was coined by Aubrey Jaffer, who says
|
|
||||||
it comes from ``small object'', referring to the fact that they are
|
|
||||||
quite limited in size: they can hold just one pointer to a larger
|
|
||||||
memory block plus 16 extra bits.
|
|
||||||
|
|
||||||
To define a new smob type, the programmer provides Guile with some
|
|
||||||
essential information about the type --- how to print it, how to
|
|
||||||
garbage collect it, and so on --- and Guile allocates a fresh type tag
|
|
||||||
for it. The programmer can then use @code{scm_c_define_gsubr} to make
|
|
||||||
a set of C functions visible to Scheme code that create and operate on
|
|
||||||
these objects.
|
|
||||||
|
|
||||||
(You can find a complete version of the example code used in this
|
|
||||||
section in the Guile distribution, in @file{doc/example-smob}. That
|
|
||||||
directory includes a makefile and a suitable @code{main} function, so
|
|
||||||
you can build a complete interactive Guile shell, extended with the
|
|
||||||
datatypes described here.)
|
|
||||||
|
|
||||||
@menu
|
|
||||||
* Describing a New Type::
|
|
||||||
* Creating Smob Instances::
|
|
||||||
* Type checking::
|
|
||||||
* Garbage Collecting Smobs::
|
|
||||||
* Remembering During Operations::
|
|
||||||
* Double Smobs::
|
|
||||||
* The Complete Example::
|
|
||||||
@end menu
|
|
||||||
|
|
||||||
@node Describing a New Type
|
|
||||||
@subsection Describing a New Type
|
|
||||||
|
|
||||||
To define a new type, the programmer must write two functions to
|
|
||||||
manage instances of the type:
|
|
||||||
|
|
||||||
@table @code
|
|
||||||
@item print
|
|
||||||
Guile will apply this function to each instance of the new type to print
|
|
||||||
the value, as for @code{display} or @code{write}. The default print
|
|
||||||
function prints @code{#<NAME ADDRESS>} where @code{NAME} is the first
|
|
||||||
argument passed to @code{scm_make_smob_type}.
|
|
||||||
|
|
||||||
@item equalp
|
|
||||||
If Scheme code asks the @code{equal?} function to compare two instances
|
|
||||||
of the same smob type, Guile calls this function. It should return
|
|
||||||
@code{SCM_BOOL_T} if @var{a} and @var{b} should be considered
|
|
||||||
@code{equal?}, or @code{SCM_BOOL_F} otherwise. If @code{equalp} is
|
|
||||||
@code{NULL}, @code{equal?} will assume that two instances of this type are
|
|
||||||
never @code{equal?} unless they are @code{eq?}.
|
|
||||||
|
|
||||||
@end table
|
|
||||||
|
|
||||||
When the only resource associated with a smob is memory managed by the
|
|
||||||
garbage collector---i.e., memory allocated with the @code{scm_gc_malloc}
|
|
||||||
functions---this is sufficient. However, when a smob is associated with
|
|
||||||
other kinds of resources, it may be necessary to define one of the
|
|
||||||
following functions, or both:
|
|
||||||
|
|
||||||
@table @code
|
|
||||||
@item mark
|
|
||||||
Guile will apply this function to each instance of the new type it
|
|
||||||
encounters during garbage collection. This function is responsible for
|
|
||||||
telling the collector about any other @code{SCM} values that the object
|
|
||||||
has stored, and that are in memory regions not already scanned by the
|
|
||||||
garbage collector. @xref{Garbage Collecting Smobs}, for more details.
|
|
||||||
|
|
||||||
@item free
|
|
||||||
Guile will apply this function to each instance of the new type that is
|
|
||||||
to be deallocated. The function should release all resources held by
|
|
||||||
the object. This is analogous to the Java finalization method---it is
|
|
||||||
invoked at an unspecified time (when garbage collection occurs) after
|
|
||||||
the object is dead. @xref{Garbage Collecting Smobs}, for more details.
|
|
||||||
|
|
||||||
This function operates while the heap is in an inconsistent state and
|
|
||||||
must therefore be careful. @xref{Smobs}, for details about what this
|
|
||||||
function is allowed to do.
|
|
||||||
@end table
|
|
||||||
|
|
||||||
To actually register the new smob type, call @code{scm_make_smob_type}.
|
|
||||||
It returns a value of type @code{scm_t_bits} which identifies the new
|
|
||||||
smob type.
|
|
||||||
|
|
||||||
The four special functions described above are registered by calling
|
|
||||||
one of @code{scm_set_smob_mark}, @code{scm_set_smob_free},
|
|
||||||
@code{scm_set_smob_print}, or @code{scm_set_smob_equalp}, as
|
|
||||||
appropriate. Each function is intended to be used at most once per
|
|
||||||
type, and the call should be placed immediately following the call to
|
|
||||||
@code{scm_make_smob_type}.
|
|
||||||
|
|
||||||
There can only be at most 256 different smob types in the system.
|
|
||||||
Instead of registering a huge number of smob types (for example, one
|
|
||||||
for each relevant C struct in your application), it is sometimes
|
|
||||||
better to register just one and implement a second layer of type
|
|
||||||
dispatching on top of it. This second layer might use the 16 extra
|
|
||||||
bits to extend its type, for example.
|
|
||||||
|
|
||||||
Here is how one might declare and register a new type representing
|
|
||||||
eight-bit gray-scale images:
|
|
||||||
|
|
||||||
@example
|
|
||||||
#include <libguile.h>
|
|
||||||
|
|
||||||
struct image @{
|
|
||||||
int width, height;
|
|
||||||
char *pixels;
|
|
||||||
|
|
||||||
/* The name of this image */
|
|
||||||
SCM name;
|
|
||||||
|
|
||||||
/* A function to call when this image is
|
|
||||||
modified, e.g., to update the screen,
|
|
||||||
or SCM_BOOL_F if no action necessary */
|
|
||||||
SCM update_func;
|
|
||||||
@};
|
|
||||||
|
|
||||||
static scm_t_bits image_tag;
|
|
||||||
|
|
||||||
void
|
|
||||||
init_image_type (void)
|
|
||||||
@{
|
|
||||||
image_tag = scm_make_smob_type ("image", sizeof (struct image));
|
|
||||||
scm_set_smob_mark (image_tag, mark_image);
|
|
||||||
scm_set_smob_free (image_tag, free_image);
|
|
||||||
scm_set_smob_print (image_tag, print_image);
|
|
||||||
@}
|
|
||||||
@end example
|
|
||||||
|
|
||||||
|
|
||||||
@node Creating Smob Instances
|
|
||||||
@subsection Creating Smob Instances
|
|
||||||
|
|
||||||
Normally, smobs can have one @emph{immediate} word of data. This word
|
|
||||||
stores either a pointer to an additional memory block that holds the
|
|
||||||
real data, or it might hold the data itself when it fits. The word is
|
|
||||||
large enough for a @code{SCM} value, a pointer to @code{void}, or an
|
|
||||||
integer that fits into a @code{size_t} or @code{ssize_t}.
|
|
||||||
|
|
||||||
You can also create smobs that have two or three immediate words, and
|
|
||||||
when these words suffice to store all data, it is more efficient to use
|
|
||||||
these super-sized smobs instead of using a normal smob plus a memory
|
|
||||||
block. @xref{Double Smobs}, for their discussion.
|
|
||||||
|
|
||||||
Guile provides functions for managing memory which are often helpful
|
|
||||||
when implementing smobs. @xref{Memory Blocks}.
|
|
||||||
|
|
||||||
To retrieve the immediate word of a smob, you use the macro
|
|
||||||
@code{SCM_SMOB_DATA}. It can be set with @code{SCM_SET_SMOB_DATA}.
|
|
||||||
The 16 extra bits can be accessed with @code{SCM_SMOB_FLAGS} and
|
|
||||||
@code{SCM_SET_SMOB_FLAGS}.
|
|
||||||
|
|
||||||
The two macros @code{SCM_SMOB_DATA} and @code{SCM_SET_SMOB_DATA} treat
|
|
||||||
the immediate word as if it were of type @code{scm_t_bits}, which is
|
|
||||||
an unsigned integer type large enough to hold a pointer to
|
|
||||||
@code{void}. Thus you can use these macros to store arbitrary
|
|
||||||
pointers in the smob word.
|
|
||||||
|
|
||||||
When you want to store a @code{SCM} value directly in the immediate
|
|
||||||
word of a smob, you should use the macros @code{SCM_SMOB_OBJECT} and
|
|
||||||
@code{SCM_SET_SMOB_OBJECT} to access it.
|
|
||||||
|
|
||||||
Creating a smob instance can be tricky when it consists of multiple
|
|
||||||
steps that allocate resources. Most of the time, this is mainly about
|
|
||||||
allocating memory to hold associated data structures. Using memory
|
|
||||||
managed by the garbage collector simplifies things: the garbage
|
|
||||||
collector will automatically scan those data structures for pointers,
|
|
||||||
and reclaim them when they are no longer referenced.
|
|
||||||
|
|
||||||
Continuing the example from above, if the global variable
|
|
||||||
@code{image_tag} contains a tag returned by @code{scm_make_smob_type},
|
|
||||||
here is how we could construct a smob whose immediate word contains a
|
|
||||||
pointer to a freshly allocated @code{struct image}:
|
|
||||||
|
|
||||||
@example
|
|
||||||
SCM
|
|
||||||
make_image (SCM name, SCM s_width, SCM s_height)
|
|
||||||
@{
|
|
||||||
SCM smob;
|
|
||||||
struct image *image;
|
|
||||||
int width = scm_to_int (s_width);
|
|
||||||
int height = scm_to_int (s_height);
|
|
||||||
|
|
||||||
/* Step 1: Allocate the memory block.
|
|
||||||
*/
|
|
||||||
image = (struct image *)
|
|
||||||
scm_gc_malloc (sizeof (struct image), "image");
|
|
||||||
|
|
||||||
/* Step 2: Initialize it with straight code.
|
|
||||||
*/
|
|
||||||
image->width = width;
|
|
||||||
image->height = height;
|
|
||||||
image->pixels = NULL;
|
|
||||||
image->name = SCM_BOOL_F;
|
|
||||||
image->update_func = SCM_BOOL_F;
|
|
||||||
|
|
||||||
/* Step 3: Create the smob.
|
|
||||||
*/
|
|
||||||
smob = scm_new_smob (image_tag, image);
|
|
||||||
|
|
||||||
/* Step 4: Finish the initialization.
|
|
||||||
*/
|
|
||||||
image->name = name;
|
|
||||||
image->pixels =
|
|
||||||
scm_gc_malloc_pointerless (width * height, "image pixels");
|
|
||||||
|
|
||||||
return smob;
|
|
||||||
@}
|
|
||||||
@end example
|
|
||||||
|
|
||||||
We use @code{scm_gc_malloc_pointerless} for the pixel buffer to tell the
|
|
||||||
garbage collector not to scan it for pointers. Calls to
|
|
||||||
@code{scm_gc_malloc}, @code{scm_new_smob}, and
|
|
||||||
@code{scm_gc_malloc_pointerless} raise an exception in out-of-memory
|
|
||||||
conditions; the garbage collector is able to reclaim previously
|
|
||||||
allocated memory if that happens.
|
|
||||||
|
|
||||||
|
|
||||||
@node Type checking
|
|
||||||
@subsection Type checking
|
|
||||||
|
|
||||||
Functions that operate on smobs should check that the passed
|
|
||||||
@code{SCM} value indeed is a suitable smob before accessing its data.
|
|
||||||
They can do this with @code{scm_assert_smob_type}.
|
|
||||||
|
|
||||||
For example, here is a simple function that operates on an image smob,
|
|
||||||
and checks the type of its argument.
|
|
||||||
|
|
||||||
@example
|
|
||||||
SCM
|
|
||||||
clear_image (SCM image_smob)
|
|
||||||
@{
|
|
||||||
int area;
|
|
||||||
struct image *image;
|
|
||||||
|
|
||||||
scm_assert_smob_type (image_tag, image_smob);
|
|
||||||
|
|
||||||
image = (struct image *) SCM_SMOB_DATA (image_smob);
|
|
||||||
area = image->width * image->height;
|
|
||||||
memset (image->pixels, 0, area);
|
|
||||||
|
|
||||||
/* Invoke the image's update function.
|
|
||||||
*/
|
|
||||||
if (scm_is_true (image->update_func))
|
|
||||||
scm_call_0 (image->update_func);
|
|
||||||
|
|
||||||
scm_remember_upto_here_1 (image_smob);
|
|
||||||
|
|
||||||
return SCM_UNSPECIFIED;
|
|
||||||
@}
|
|
||||||
@end example
|
|
||||||
|
|
||||||
See @ref{Remembering During Operations} for an explanation of the call
|
|
||||||
to @code{scm_remember_upto_here_1}.
|
|
||||||
|
|
||||||
|
|
||||||
@node Garbage Collecting Smobs
|
|
||||||
@subsection Garbage Collecting Smobs
|
|
||||||
|
|
||||||
Once a smob has been released to the tender mercies of the Scheme
|
|
||||||
system, it must be prepared to survive garbage collection. In the
|
|
||||||
example above, all the memory associated with the smob is managed by the
|
|
||||||
garbage collector because we used the @code{scm_gc_} allocation
|
|
||||||
functions. Thus, no special care must be taken: the garbage collector
|
|
||||||
automatically scans them and reclaims any unused memory.
|
|
||||||
|
|
||||||
However, when data associated with a smob is managed in some other
|
|
||||||
way---e.g., @code{malloc}'d memory or file descriptors---it is possible
|
|
||||||
to specify a @emph{free} function to release those resources when the
|
|
||||||
smob is reclaimed, and a @emph{mark} function to mark Scheme objects
|
|
||||||
otherwise invisible to the garbage collector.
|
|
||||||
|
|
||||||
As described in more detail elsewhere (@pxref{Conservative GC}), every
|
|
||||||
object in the Scheme system has a @dfn{mark bit}, which the garbage
|
|
||||||
collector uses to tell live objects from dead ones. When collection
|
|
||||||
starts, every object's mark bit is clear. The collector traces pointers
|
|
||||||
through the heap, starting from objects known to be live, and sets the
|
|
||||||
mark bit on each object it encounters. When it can find no more
|
|
||||||
unmarked objects, the collector walks all objects, live and dead, frees
|
|
||||||
those whose mark bits are still clear, and clears the mark bit on the
|
|
||||||
others.
|
|
||||||
|
|
||||||
The two main portions of the collection are called the @dfn{mark phase},
|
|
||||||
during which the collector marks live objects, and the @dfn{sweep
|
|
||||||
phase}, during which the collector frees all unmarked objects.
|
|
||||||
|
|
||||||
The mark bit of a smob lives in a special memory region. When the
|
|
||||||
collector encounters a smob, it sets the smob's mark bit, and uses the
|
|
||||||
smob's type tag to find the appropriate @emph{mark} function for that
|
|
||||||
smob. It then calls this @emph{mark} function, passing it the smob as
|
|
||||||
its only argument.
|
|
||||||
|
|
||||||
The @emph{mark} function is responsible for marking any other Scheme
|
|
||||||
objects the smob refers to. If it does not do so, the objects' mark
|
|
||||||
bits will still be clear when the collector begins to sweep, and the
|
|
||||||
collector will free them. If this occurs, it will probably break, or at
|
|
||||||
least confuse, any code operating on the smob; the smob's @code{SCM}
|
|
||||||
values will have become dangling references.
|
|
||||||
|
|
||||||
To mark an arbitrary Scheme object, the @emph{mark} function calls
|
|
||||||
@code{scm_gc_mark}.
|
|
||||||
|
|
||||||
Thus, here is how we might write @code{mark_image}---again this is not
|
|
||||||
needed in our example since we used the @code{scm_gc_} allocation
|
|
||||||
routines, so this is just for the sake of illustration:
|
|
||||||
|
|
||||||
@example
|
|
||||||
@group
|
|
||||||
SCM
|
|
||||||
mark_image (SCM image_smob)
|
|
||||||
@{
|
|
||||||
/* Mark the image's name and update function. */
|
|
||||||
struct image *image = (struct image *) SCM_SMOB_DATA (image_smob);
|
|
||||||
|
|
||||||
scm_gc_mark (image->name);
|
|
||||||
scm_gc_mark (image->update_func);
|
|
||||||
|
|
||||||
return SCM_BOOL_F;
|
|
||||||
@}
|
|
||||||
@end group
|
|
||||||
@end example
|
|
||||||
|
|
||||||
Note that, even though the image's @code{update_func} could be an
|
|
||||||
arbitrarily complex structure (representing a procedure and any values
|
|
||||||
enclosed in its environment), @code{scm_gc_mark} will recurse as
|
|
||||||
necessary to mark all its components. Because @code{scm_gc_mark} sets
|
|
||||||
an object's mark bit before it recurses, it is not confused by
|
|
||||||
circular structures.
|
|
||||||
|
|
||||||
As an optimization, the collector will mark whatever value is returned
|
|
||||||
by the @emph{mark} function; this helps limit depth of recursion during
|
|
||||||
the mark phase. Thus, the code above should really be written as:
|
|
||||||
@example
|
|
||||||
@group
|
|
||||||
SCM
|
|
||||||
mark_image (SCM image_smob)
|
|
||||||
@{
|
|
||||||
/* Mark the image's name and update function. */
|
|
||||||
struct image *image = (struct image *) SCM_SMOB_DATA (image_smob);
|
|
||||||
|
|
||||||
scm_gc_mark (image->name);
|
|
||||||
return image->update_func;
|
|
||||||
@}
|
|
||||||
@end group
|
|
||||||
@end example
|
|
||||||
|
|
||||||
|
|
||||||
Finally, when the collector encounters an unmarked smob during the sweep
|
|
||||||
phase, it uses the smob's tag to find the appropriate @emph{free}
|
|
||||||
function for the smob. It then calls that function, passing it the smob
|
|
||||||
as its only argument.
|
|
||||||
|
|
||||||
The @emph{free} function must release any resources used by the smob.
|
|
||||||
However, it must not free objects managed by the collector; the
|
|
||||||
collector will take care of them. For historical reasons, the return
|
|
||||||
type of the @emph{free} function should be @code{size_t}, an unsigned
|
|
||||||
integral type; the @emph{free} function should always return zero.
|
|
||||||
|
|
||||||
Here is how we might write the @code{free_image} function for the image
|
|
||||||
smob type---again for the sake of illustration, since our example does
|
|
||||||
not need it thanks to the use of the @code{scm_gc_} allocation routines:
|
|
||||||
@example
|
|
||||||
size_t
|
|
||||||
free_image (SCM image_smob)
|
|
||||||
@{
|
|
||||||
struct image *image = (struct image *) SCM_SMOB_DATA (image_smob);
|
|
||||||
|
|
||||||
scm_gc_free (image->pixels,
|
|
||||||
image->width * image->height,
|
|
||||||
"image pixels");
|
|
||||||
scm_gc_free (image, sizeof (struct image), "image");
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
@}
|
|
||||||
@end example
|
|
||||||
|
|
||||||
During the sweep phase, the garbage collector will clear the mark bits
|
|
||||||
on all live objects. The code which implements a smob need not do this
|
|
||||||
itself.
|
|
||||||
|
|
||||||
@cindex finalizer
|
|
||||||
@cindex finalization
|
|
||||||
|
|
||||||
Note that the free function can be called in any context. In
|
|
||||||
particular, if your Guile is built with support for threads, the
|
|
||||||
finalizer may be called from any thread that is running Guile. In Guile
|
|
||||||
2.0, finalizers are invoked via ``asyncs'', which interleaves them with
|
|
||||||
running Scheme code; @pxref{System asyncs}. In Guile 2.2 there will be
|
|
||||||
a dedicated finalization thread, to ensure that the finalization doesn't
|
|
||||||
run within the critical section of any other thread known to Guile.
|
|
||||||
|
|
||||||
In either case, finalizers (free functions) run concurrently with the
|
|
||||||
main program, and so they need to be async-safe and thread-safe. If for
|
|
||||||
some reason this is impossible, perhaps because you are embedding Guile
|
|
||||||
in some application that is not itself thread-safe, you have a few
|
|
||||||
options. One is to use guardians instead of free functions, and arrange
|
|
||||||
to pump the guardians for finalizable objects. @xref{Guardians}, for
|
|
||||||
more information. The other option is to disable automatic finalization
|
|
||||||
entirely, and arrange to call @code{scm_run_finalizers ()} at
|
|
||||||
appropriate points. @xref{Smobs}, for more on these interfaces.
|
|
||||||
|
|
||||||
There is no way for smob code to be notified when collection is
|
|
||||||
complete.
|
|
||||||
|
|
||||||
It is usually a good idea to minimize the amount of processing done
|
|
||||||
during garbage collection; keep the @emph{mark} and @emph{free}
|
|
||||||
functions very simple. Since collections occur at unpredictable times,
|
|
||||||
it is easy for any unusual activity to interfere with normal code.
|
|
||||||
|
|
||||||
@node Remembering During Operations
|
|
||||||
@subsection Remembering During Operations
|
|
||||||
@cindex remembering
|
|
||||||
|
|
||||||
@c FIXME: Remove this section?
|
|
||||||
|
|
||||||
It's important that a smob is visible to the garbage collector
|
|
||||||
whenever its contents are being accessed. Otherwise it could be freed
|
|
||||||
while code is still using it.
|
|
||||||
|
|
||||||
For example, consider a procedure to convert image data to a list of
|
|
||||||
pixel values.
|
|
||||||
|
|
||||||
@example
|
|
||||||
SCM
|
|
||||||
image_to_list (SCM image_smob)
|
|
||||||
@{
|
|
||||||
struct image *image;
|
|
||||||
SCM lst;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
scm_assert_smob_type (image_tag, image_smob);
|
|
||||||
|
|
||||||
image = (struct image *) SCM_SMOB_DATA (image_smob);
|
|
||||||
lst = SCM_EOL;
|
|
||||||
for (i = image->width * image->height - 1; i >= 0; i--)
|
|
||||||
lst = scm_cons (scm_from_char (image->pixels[i]), lst);
|
|
||||||
|
|
||||||
scm_remember_upto_here_1 (image_smob);
|
|
||||||
return lst;
|
|
||||||
@}
|
|
||||||
@end example
|
|
||||||
|
|
||||||
In the loop, only the @code{image} pointer is used and the C compiler
|
|
||||||
has no reason to keep the @code{image_smob} value anywhere. If
|
|
||||||
@code{scm_cons} results in a garbage collection, @code{image_smob} might
|
|
||||||
not be on the stack or anywhere else and could be freed, leaving the
|
|
||||||
loop accessing freed data. The use of @code{scm_remember_upto_here_1}
|
|
||||||
prevents this, by creating a reference to @code{image_smob} after all
|
|
||||||
data accesses.
|
|
||||||
|
|
||||||
There's no need to do the same for @code{lst}, since that's the return
|
|
||||||
value and the compiler will certainly keep it in a register or
|
|
||||||
somewhere throughout the routine.
|
|
||||||
|
|
||||||
The @code{clear_image} example previously shown (@pxref{Type checking})
|
|
||||||
also used @code{scm_remember_upto_here_1} for this reason.
|
|
||||||
|
|
||||||
It's only in quite rare circumstances that a missing
|
|
||||||
@code{scm_remember_upto_here_1} will bite, but when it happens the
|
|
||||||
consequences are serious. Fortunately the rule is simple: whenever
|
|
||||||
calling a Guile library function or doing something that might, ensure
|
|
||||||
that the @code{SCM} of a smob is referenced past all accesses to its
|
|
||||||
insides. Do this by adding an @code{scm_remember_upto_here_1} if
|
|
||||||
there are no other references.
|
|
||||||
|
|
||||||
In a multi-threaded program, the rule is the same. As far as a given
|
|
||||||
thread is concerned, a garbage collection still only occurs within a
|
|
||||||
Guile library function, not at an arbitrary time. (Guile waits for all
|
|
||||||
threads to reach one of its library functions, and holds them there
|
|
||||||
while the collector runs.)
|
|
||||||
|
|
||||||
@node Double Smobs
|
|
||||||
@subsection Double Smobs
|
|
||||||
|
|
||||||
@c FIXME: Remove this section?
|
|
||||||
|
|
||||||
Smobs are called smob because they are small: they normally have only
|
|
||||||
room for one @code{void*} or @code{SCM} value plus 16 bits. The
|
|
||||||
reason for this is that smobs are directly implemented by using the
|
|
||||||
low-level, two-word cells of Guile that are also used to implement
|
|
||||||
pairs, for example. (@pxref{Data Representation} for the
|
|
||||||
details.) One word of the two-word cells is used for
|
|
||||||
@code{SCM_SMOB_DATA} (or @code{SCM_SMOB_OBJECT}), the other contains
|
|
||||||
the 16-bit type tag and the 16 extra bits.
|
|
||||||
|
|
||||||
In addition to the fundamental two-word cells, Guile also has
|
|
||||||
four-word cells, which are appropriately called @dfn{double cells}.
|
|
||||||
You can use them for @dfn{double smobs} and get two more immediate
|
|
||||||
words of type @code{scm_t_bits}.
|
|
||||||
|
|
||||||
A double smob is created with @code{scm_new_double_smob}. Its immediate
|
|
||||||
words can be retrieved as @code{scm_t_bits} with @code{SCM_SMOB_DATA_2}
|
|
||||||
and @code{SCM_SMOB_DATA_3} in addition to @code{SCM_SMOB_DATA}.
|
|
||||||
Unsurprisingly, the words can be set to @code{scm_t_bits} values with
|
|
||||||
@code{SCM_SET_SMOB_DATA_2} and @code{SCM_SET_SMOB_DATA_3}.
|
|
||||||
|
|
||||||
Of course there are also @code{SCM_SMOB_OBJECT_2},
|
|
||||||
@code{SCM_SMOB_OBJECT_3}, @code{SCM_SET_SMOB_OBJECT_2}, and
|
|
||||||
@code{SCM_SET_SMOB_OBJECT_3}.
|
|
||||||
|
|
||||||
@node The Complete Example
|
|
||||||
@subsection The Complete Example
|
|
||||||
|
|
||||||
Here is the complete text of the implementation of the image datatype,
|
|
||||||
as presented in the sections above. We also provide a definition for
|
|
||||||
the smob's @emph{print} function, and make some objects and functions
|
|
||||||
static, to clarify exactly what the surrounding code is using.
|
|
||||||
|
|
||||||
As mentioned above, you can find this code in the Guile distribution, in
|
|
||||||
@file{doc/example-smob}. That directory includes a makefile and a
|
|
||||||
suitable @code{main} function, so you can build a complete interactive
|
|
||||||
Guile shell, extended with the datatypes described here.)
|
|
||||||
|
|
||||||
@example
|
|
||||||
/* file "image-type.c" */
|
|
||||||
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <libguile.h>
|
|
||||||
|
|
||||||
static scm_t_bits image_tag;
|
|
||||||
|
|
||||||
struct image @{
|
|
||||||
int width, height;
|
|
||||||
char *pixels;
|
|
||||||
|
|
||||||
/* The name of this image */
|
|
||||||
SCM name;
|
|
||||||
|
|
||||||
/* A function to call when this image is
|
|
||||||
modified, e.g., to update the screen,
|
|
||||||
or SCM_BOOL_F if no action necessary */
|
|
||||||
SCM update_func;
|
|
||||||
@};
|
|
||||||
|
|
||||||
static SCM
|
|
||||||
make_image (SCM name, SCM s_width, SCM s_height)
|
|
||||||
@{
|
|
||||||
SCM smob;
|
|
||||||
struct image *image;
|
|
||||||
int width = scm_to_int (s_width);
|
|
||||||
int height = scm_to_int (s_height);
|
|
||||||
|
|
||||||
/* Step 1: Allocate the memory block.
|
|
||||||
*/
|
|
||||||
image = (struct image *)
|
|
||||||
scm_gc_malloc (sizeof (struct image), "image");
|
|
||||||
|
|
||||||
/* Step 2: Initialize it with straight code.
|
|
||||||
*/
|
|
||||||
image->width = width;
|
|
||||||
image->height = height;
|
|
||||||
image->pixels = NULL;
|
|
||||||
image->name = SCM_BOOL_F;
|
|
||||||
image->update_func = SCM_BOOL_F;
|
|
||||||
|
|
||||||
/* Step 3: Create the smob.
|
|
||||||
*/
|
|
||||||
smob = scm_new_smob (image_tag, image);
|
|
||||||
|
|
||||||
/* Step 4: Finish the initialization.
|
|
||||||
*/
|
|
||||||
image->name = name;
|
|
||||||
image->pixels =
|
|
||||||
scm_gc_malloc (width * height, "image pixels");
|
|
||||||
|
|
||||||
return smob;
|
|
||||||
@}
|
|
||||||
|
|
||||||
SCM
|
|
||||||
clear_image (SCM image_smob)
|
|
||||||
@{
|
|
||||||
int area;
|
|
||||||
struct image *image;
|
|
||||||
|
|
||||||
scm_assert_smob_type (image_tag, image_smob);
|
|
||||||
|
|
||||||
image = (struct image *) SCM_SMOB_DATA (image_smob);
|
|
||||||
area = image->width * image->height;
|
|
||||||
memset (image->pixels, 0, area);
|
|
||||||
|
|
||||||
/* Invoke the image's update function.
|
|
||||||
*/
|
|
||||||
if (scm_is_true (image->update_func))
|
|
||||||
scm_call_0 (image->update_func);
|
|
||||||
|
|
||||||
scm_remember_upto_here_1 (image_smob);
|
|
||||||
|
|
||||||
return SCM_UNSPECIFIED;
|
|
||||||
@}
|
|
||||||
|
|
||||||
static SCM
|
|
||||||
mark_image (SCM image_smob)
|
|
||||||
@{
|
|
||||||
/* Mark the image's name and update function. */
|
|
||||||
struct image *image = (struct image *) SCM_SMOB_DATA (image_smob);
|
|
||||||
|
|
||||||
scm_gc_mark (image->name);
|
|
||||||
return image->update_func;
|
|
||||||
@}
|
|
||||||
|
|
||||||
static size_t
|
|
||||||
free_image (SCM image_smob)
|
|
||||||
@{
|
|
||||||
struct image *image = (struct image *) SCM_SMOB_DATA (image_smob);
|
|
||||||
|
|
||||||
scm_gc_free (image->pixels,
|
|
||||||
image->width * image->height,
|
|
||||||
"image pixels");
|
|
||||||
scm_gc_free (image, sizeof (struct image), "image");
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
@}
|
|
||||||
|
|
||||||
static int
|
|
||||||
print_image (SCM image_smob, SCM port, scm_print_state *pstate)
|
|
||||||
@{
|
|
||||||
struct image *image = (struct image *) SCM_SMOB_DATA (image_smob);
|
|
||||||
|
|
||||||
scm_puts ("#<image ", port);
|
|
||||||
scm_display (image->name, port);
|
|
||||||
scm_puts (">", port);
|
|
||||||
|
|
||||||
/* non-zero means success */
|
|
||||||
return 1;
|
|
||||||
@}
|
|
||||||
|
|
||||||
void
|
|
||||||
init_image_type (void)
|
|
||||||
@{
|
|
||||||
image_tag = scm_make_smob_type ("image", sizeof (struct image));
|
|
||||||
scm_set_smob_mark (image_tag, mark_image);
|
|
||||||
scm_set_smob_free (image_tag, free_image);
|
|
||||||
scm_set_smob_print (image_tag, print_image);
|
|
||||||
|
|
||||||
scm_c_define_gsubr ("clear-image", 1, 0, 0, clear_image);
|
|
||||||
scm_c_define_gsubr ("make-image", 3, 0, 0, make_image);
|
|
||||||
@}
|
|
||||||
@end example
|
|
||||||
|
|
||||||
Here is a sample build and interaction with the code from the
|
|
||||||
@file{example-smob} directory, on the author's machine:
|
|
||||||
|
|
||||||
@example
|
|
||||||
zwingli:example-smob$ make CC=gcc
|
|
||||||
gcc `pkg-config --cflags guile-@value{EFFECTIVE-VERSION}` -c image-type.c -o image-type.o
|
|
||||||
gcc `pkg-config --cflags guile-@value{EFFECTIVE-VERSION}` -c myguile.c -o myguile.o
|
|
||||||
gcc image-type.o myguile.o `pkg-config --libs guile-@value{EFFECTIVE-VERSION}` -o myguile
|
|
||||||
zwingli:example-smob$ ./myguile
|
|
||||||
guile> make-image
|
|
||||||
#<primitive-procedure make-image>
|
|
||||||
guile> (define i (make-image "Whistler's Mother" 100 100))
|
|
||||||
guile> i
|
|
||||||
#<image Whistler's Mother>
|
|
||||||
guile> (clear-image i)
|
|
||||||
guile> (clear-image 4)
|
|
||||||
ERROR: In procedure clear-image in expression (clear-image 4):
|
|
||||||
ERROR: Wrong type (expecting image): 4
|
|
||||||
ABORT: (wrong-type-arg)
|
|
||||||
|
|
||||||
Type "(backtrace)" to get more information.
|
|
||||||
guile>
|
|
||||||
@end example
|
|
Loading…
Add table
Add a link
Reference in a new issue