1
Fork 0
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:
Andy Wingo 2014-04-28 17:45:07 +02:00
parent 6e4630e01a
commit d9a4a1cde1
10 changed files with 205 additions and 884 deletions

View file

@ -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 \

View file

@ -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

View file

@ -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);

View file

@ -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

View file

@ -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

View file

@ -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.

View file

@ -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

View file

@ -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,10 +244,12 @@ 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
init_file_type (void) init_file_type (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

View file

@ -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

View file

@ -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