diff --git a/doc/ref/Makefile.am b/doc/ref/Makefile.am index 1e4abf201..31c26a7ad 100644 --- a/doc/ref/Makefile.am +++ b/doc/ref/Makefile.am @@ -83,7 +83,6 @@ guile_TEXINFOS = preface.texi \ compiler.texi \ fdl.texi \ libguile-concepts.texi \ - libguile-smobs.texi \ libguile-foreign-objects.texi \ libguile-snarf.texi \ libguile-linking.texi \ diff --git a/doc/ref/api-control.texi b/doc/ref/api-control.texi index 7ffb3f740..0b08dced1 100644 --- a/doc/ref/api-control.texi +++ b/doc/ref/api-control.texi @@ -1,7 +1,7 @@ @c -*-texinfo-*- @c This is part of the GNU Guile Reference Manual. @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. @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 information to those functions. -If the data consists of an @code{SCM} object, care should be taken -that it isn't garbage collected while still required. If the -@code{SCM} is a local C variable, one way to protect it is to pass a -pointer to that variable as the data parameter, since the C compiler -will then know the value must be held on the stack. Another way is to -use @code{scm_remember_upto_here_1} (@pxref{Remembering During -Operations}). +If the data consists of an @code{SCM} object, care should be taken that +it isn't garbage collected while still required. If the @code{SCM} is a +local C variable, one way to protect it is to pass a pointer to that +variable as the data parameter, since the C compiler will then know the +value must be held on the stack. Another way is to use +@code{scm_remember_upto_here_1} (@pxref{Foreign Object Memory +Management}). @end deftypefn diff --git a/doc/ref/api-foreign-objects.texi b/doc/ref/api-foreign-objects.texi index eb7a462e1..f27f9c154 100644 --- a/doc/ref/api-foreign-objects.texi +++ b/doc/ref/api-foreign-objects.texi @@ -14,7 +14,8 @@ working with foreign objects. @xref{Defining New Foreign Object Types}, for a tutorial-like introduction to foreign objects. @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 @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 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 -than needed, however; this is convenient when some fields are of -non-pointer types, and it would be easier to initialize them with the -setters indicated below. +than needed; this is convenient when some fields are of non-pointer +types, and would be easier to initialize with the setters described +below. @end deftypefn @deftypefn {C Function} void* scm_foreign_object_ref (SCM obj, size_t n); diff --git a/doc/ref/api-smobs.texi b/doc/ref/api-smobs.texi index cfabd3988..f09474eef 100644 --- a/doc/ref/api-smobs.texi +++ b/doc/ref/api-smobs.texi @@ -9,9 +9,17 @@ @cindex smob -This chapter contains reference information related to defining and -working with smobs. See @ref{Defining New Types (Smobs)} for a -tutorial-like introduction to smobs. +A @dfn{smob} is a ``small object''. Before foreign objects were +introduced in Guile 2.0.12 (@pxref{Foreign Objects}), smobs were the +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) 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}. Default values are provided for the @emph{mark}, @emph{free}, -@emph{print}, and @emph{equalp} functions, as described in -@ref{Defining New Types (Smobs)}. If you want to customize any of -these functions, the call to @code{scm_make_smob_type} should be +@emph{print}, and @emph{equalp} functions. If you want to customize any +of these functions, the call to @code{scm_make_smob_type} should be immediately followed by calls to one or several of @code{scm_set_smob_mark}, @code{scm_set_smob_free}, @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}}). @end deftypefn -Smob free functions must be thread-safe. @xref{Garbage Collecting -Smobs}, for a discussion on finalizers and concurrency. If you are +Smob free functions must be thread-safe. @xref{Foreign Object Memory +Management}, for a discussion on finalizers and concurrency. If you are embedding Guile in an application that is not thread-safe, and you define smob types that need finalization, you might want to disable automatic finalization, and arrange to call -@code{scm_manually_run_finalizers ()} yourself. - -@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 +@code{scm_manually_run_finalizers ()} yourself. @xref{Foreign Objects}. @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 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 -parts of the process' memory (with the exception of -@code{scm_gc_malloc_pointerless} regions, and @code{malloc}- or -@code{scm_malloc}-allocated memory) are scanned for live -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 -look for pointers in the memory area used for built-in types (the -@dfn{cell heap}), not in user-allocated or statically allocated memory. -This approach is often referred to as @dfn{precise marking}.}. +Defining a marking procedure is almost always the wrong thing to do. It +is much, much preferable to allocate smob data with the +@code{scm_gc_malloc} and @code{scm_gc_malloc_pointerless} functions, and +allow the GC to trace pointers automatically. + +Any mark procedures you see currently almost surely date from the time +of Guile 1.8, before the switch to the Boehm-Demers-Weiser collector. +Such smob implementations should be changed to just use +@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 for every @code{SCM} value that is directly referenced by the smob diff --git a/doc/ref/api-utility.texi b/doc/ref/api-utility.texi index 76c50b2ca..ffdf27687 100644 --- a/doc/ref/api-utility.texi +++ b/doc/ref/api-utility.texi @@ -1,6 +1,6 @@ @c -*-texinfo-*- @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 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 similar. -New application-defined object types (@pxref{Defining New Types -(Smobs)}) have an @code{equalp} handler which is called by -@code{equal?}. This lets an 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?}. +GOOPS object types (@pxref{GOOPS}), including foreign object types +(@pxref{Defining New Foreign Object Types}), can have an @code{equal?} +implementation specialized on two values of the same type. If +@code{equal?} is called on two GOOPS objects of the same type, +@code{equal?} will dispatch out to a generic function. This lets an +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 diff --git a/doc/ref/guile.texi b/doc/ref/guile.texi index 87cea5de8..a06e49558 100644 --- a/doc/ref/guile.texi +++ b/doc/ref/guile.texi @@ -268,7 +268,6 @@ etc. that make up Guile's application programming interface (API), * Linking Guile with Libraries:: To extend Guile itself. * General Libguile Concepts:: General concepts for using libguile. * 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. * Programming Overview:: An overview of Guile programming. * 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-concepts.texi @include libguile-foreign-objects.texi -@include libguile-smobs.texi @include libguile-snarf.texi @include libguile-program.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. * Compound Data Types:: Data types for holding other data. * Foreign Objects:: Defining new data types in C. -* Smobs:: Defining new data types in C. +* Smobs:: Legacy version of foreign objects. * Procedures:: Procedures. * Macros:: Extending the syntax of Scheme. * Utility Functions:: General utility functions. diff --git a/doc/ref/libguile-concepts.texi b/doc/ref/libguile-concepts.texi index 50c435584..ea2bdbe9f 100644 --- a/doc/ref/libguile-concepts.texi +++ b/doc/ref/libguile-concepts.texi @@ -1,6 +1,6 @@ @c -*-texinfo-*- @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 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 collection}. -It is easy for Guile to remember all blocks of memory that it has -allocated for use by Scheme values, but you need to help it with finding -all Scheme values that are in use by C code. +Guile's garbage collector will automatically discover references to +@code{SCM} objects that originate in global variables, static data +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 -(@pxref{Garbage Collecting Smobs}). By calling this function, the -garbage collector learns about all references that your SMOB has to -other @code{SCM} values. - -Other references to @code{SCM} objects, such as global variables of type -@code{SCM} or other random data structures in the 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}. You normally use these functions for long -lived objects such as a hash table that is stored in a global variable. -For temporary references in local variables or function arguments, using -these functions would be too expensive. - -These references are handled differently: Local variables (and function -arguments) of type @code{SCM} are automatically visible to the garbage -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 Scheme stack and heap are scanned precisely; that is to say, Guile +knows about all inter-object pointers on the Scheme stack and heap. +This is not the case, unfortunately, for pointers on the C stack and +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 +pointer to a GC-managed object is treated as such, whether it actually +is a reference or not. Thus, scanning the C stack and static data +segment 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, as the static C root set is +almost always finite and small, given that the Scheme stack is separate +from the C stack. 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 @@ -245,17 +241,17 @@ wanted. There are situations, however, where a @code{SCM} object needs to be around longer than its reference from a local variable or function parameter. This happens, for example, when you retrieve some pointer -from a smob and work with that pointer directly. The reference to the -@code{SCM} smob object might be dead after the pointer has been -retrieved, but the pointer itself (and the memory pointed to) is still -in use and thus the smob object must be protected. The compiler does -not know about this connection and might overwrite the @code{SCM} -reference too early. +from a foreign object and work with that pointer directly. The +reference to the @code{SCM} foreign object might be dead after the +pointer has been retrieved, but the pointer itself (and the memory +pointed to) is still in use and thus the foreign object must be +protected. The compiler does not know about this connection and might +overwrite the @code{SCM} reference too early. 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 -reference. For a typical example of its use, see @ref{Remembering -During Operations}. +reference. @xref{Foreign Object Memory Management}. + @node Control Flow @subsection Control Flow diff --git a/doc/ref/libguile-foreign-objects.texi b/doc/ref/libguile-foreign-objects.texi index 4980ef5ab..11941d566 100644 --- a/doc/ref/libguile-foreign-objects.texi +++ b/doc/ref/libguile-foreign-objects.texi @@ -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 slot, because the slots list passed to @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 -be used on the Scheme side to introspect on the foreign object.) +given to slots are unimportant for most users of the C interface, but +can be used on the Scheme side to introspect on the foreign object.) To construct a foreign object and initialize its first slot, call @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 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{scm_make_foreign_object_type}, here is how we could construct a 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 will reclaim inaccessible memory as needed. This reclamation process runs concurrently with the main program. When Guile analyzes the heap -and detemines that an object's memory can be reclaimed, that memory is -simply put on a ``free list'' of objects that can be reclaimed. Usually -that's the end of it -- that's all that garbage collection does, in -Guile. However some objects can have ``finalizers'' associated with -them -- functions that are called on reclaimable objects to effect any -external cleanup actions. +and determines that an object's memory can be reclaimed, that memory is +put on a ``free list'' of objects that can be reclaimed. Usually that's +the end of it---the object is available for immediate re-use. However +some objects can have ``finalizers'' associated with them---functions +that are called on reclaimable objects to effect any external cleanup +actions. 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 its job; in fact, they are a hindrance. Furthermore, they perturb 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. For example, if we had a foreign object type that wrapped file -descriptors -- and we aren't suggesting this, as Guile already has ports --- then you might define the type like this: +descriptors---and we aren't suggesting this, as Guile already has ports +---then you might define the type like this: @example static SCM file_type; @@ -244,9 +244,11 @@ static void finalize_file (SCM file) @{ int fd = scm_foreign_object_signed_ref (file, 0); - scm_foreign_object_set_x (file, 0, -1); if (fd >= 0) - close (fd); + @{ + scm_foreign_object_signed_set_x (file, 0, -1); + close (fd); + @} @} static void @@ -273,13 +275,14 @@ make_file (int fd) @cindex finalizer @cindex finalization -Note that the finalizer can be called in any context. In particular, if -the user's 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. +Note that the finalizer may be invoked in ways and at times you might +not expect. In particular, if the user's 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 run concurrently with the main program, and 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 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 -detail, finalizer are attached in the @code{initialize} method called by -@code{make}). To access the fields, we use @code{struct-ref} and +detail, finalizers are attached in the @code{initialize} method called +by @code{make}). To access the fields, we use @code{struct-ref} and @code{struct-set!}. @xref{Structure Basics}. 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 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 -every other part of that program -- because any memory could potentially -access any other. At the same time, principled access to structured -data is organized in C on lexical boundaries; if you don't expose -accessors for your object, you trust other parts of the program not to -access it. +every other part of that program -- because any part of the program can +read and write anything in its address space. At the same time, +principled access to structured data is organized in C on lexical +boundaries; if you don't expose accessors for your object, you trust +other parts of the program not to work around that barrier. -The answer is similar in Scheme. Although Scheme's unsafe constructs -are fewer in number than in C, they do exist. The @code{(system -foreign)} module can be used to violate confidentiality and integrity, -and shouldn't be exposed to untrusted code. Although @code{struct-ref} -and @code{struct-set!} are less unsafe, they still have a cross-cutting -capability of drilling through abstractions. Performing a -@code{struct-set!} on a foreign object slot could cause unsafe foreign -code to crash. Ultimately, structures in Scheme are capabilities for -abstraction, and not abstractions themselves. +The situation is not dissimilar in Scheme. Although Scheme's unsafe +constructs are fewer in number than in C, they do exist. The +@code{(system foreign)} module can be used to violate confidentiality +and integrity, and shouldn't be exposed to untrusted code. Although +@code{struct-ref} and @code{struct-set!} are less unsafe, they still +have a cross-cutting capability of drilling through abstractions. +Performing a @code{struct-set!} on a foreign object slot could cause +unsafe foreign code to crash. Ultimately, structures in Scheme are +capabilities for abstraction, and not abstractions themselves. That leaves us with the lexical capabilities, like constructors and accessors. Here is where encapsulation lies: the practical degree to diff --git a/doc/ref/libguile-program.texi b/doc/ref/libguile-program.texi index f565b916f..3b7408398 100644 --- a/doc/ref/libguile-program.texi +++ b/doc/ref/libguile-program.texi @@ -1,6 +1,6 @@ @c -*-texinfo-*- @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 See the file guile.texi for copying conditions. @@ -46,7 +46,7 @@ applications in general. @menu * Dia Objective:: Deciding why you want 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 Hook:: Providing a hook for Scheme evaluation. * 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 passed into the Scheme world. Unless your objects are so simple that they map naturally into builtin Scheme data types like numbers and -strings, you will probably want to use Guile's @dfn{SMOB} interface to -create a new Scheme data type for your objects. +strings, you will probably want to use Guile's @dfn{foreign object} +interface to create a new Scheme data type for your objects. Second, you need to write code for the basic operations like @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 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. -@node Dia Smobs +@node Dia Objects @subsubsection How to Represent Dia Data in Scheme For all but the most trivial applications, you will probably want to 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. 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 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. -The SMOB is what is passed into and out of Scheme code, and the -Scheme-specific C structure inside the SMOB points to Dia's underlying C -structure so that the code for primitives like @code{square?} can get at -it. +a shape to be a new, Scheme-specific C structure wrapped up as a foreign +object. The foreign object is what is passed into and out of Scheme +code, and the Scheme-specific C structure inside the foreign object +points to Dia's underlying C structure so that the code for primitives +like @code{square?} can get at it. To cope with an underlying shape being deleted while Scheme code is 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 -shape is deleted, the relevant code chains through to the -Scheme-specific structure and sets its pointer back to the underlying -structure to NULL. Thus the SMOB value for the shape continues to -exist, but any primitive code that tries to use it will detect that the -underlying shape has been deleted because the underlying structure -pointer is NULL. +should have a new field that points to the Scheme-specific foreign +object. When a shape is deleted, the relevant code chains through to +the Scheme-specific structure and sets its pointer back to the +underlying structure to NULL. Thus the foreign object value for the +shape continues to exist, but any primitive code that tries to use it +will detect that the underlying shape has been deleted because the +underlying structure pointer is NULL. So, to summarize the steps involved in this resolution of the problem (and assuming that the underlying C structure for a shape is @@ -238,33 +239,33 @@ struct dia_shape underlying shape is deleted. @item -Wrap @code{struct dia_guile_shape} as a SMOB type. +Wrap @code{struct dia_guile_shape} as a foreign object type. @item 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 -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 underlying C shape is still there. @end itemize -As far as memory management is concerned, the SMOB values and their -Scheme-specific structures are under the control of the garbage +As far as memory management is concerned, the foreign object values and +their Scheme-specific structures are under the control of the garbage collector, whereas the underlying C structures are explicitly managed in exactly the same way that Dia managed them before we thought of adding Guile. -When the garbage collector decides to free a shape SMOB value, it calls -the @dfn{SMOB free} function that was specified when defining the shape -SMOB type. To maintain the correctness of the @code{guile_shape} field -in the underlying C structure, this function should chain through to the -underlying C structure (if it still exists) and set its -@code{guile_shape} field to NULL. +When the garbage collector decides to free a shape foreign object value, +it calls the @dfn{finalizer} function that was specified when defining +the shape foreign object type. To maintain the correctness of the +@code{guile_shape} field in the underlying C structure, this function +should chain through to the underlying C structure (if it still exists) +and set its @code{guile_shape} field to NULL. -For full documentation on defining and using SMOB types, see -@ref{Defining New Types (Smobs)}. +For full documentation on defining and using foreign object types, see +@ref{Defining New Foreign Object Types}. @node Dia Primitives @@ -283,11 +284,11 @@ static SCM square_p (SCM shape) @{ struct dia_guile_shape * guile_shape; - /* Check that arg is really a shape SMOB. */ - scm_assert_smob_type (shape_tag, shape); + /* Check that arg is really a shape object. */ + scm_assert_foreign_object_type (shape_type, shape); /* 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 square; return answer as a Scheme boolean. */ @@ -297,26 +298,28 @@ static SCM square_p (SCM shape) @end lisp 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 -Scheme-specific structure inside the SMOB, and thence to the underlying -C structure for the shape. +parameter that @code{square_p} receives --- which is a foreign object +--- to the Scheme-specific structure inside the foreign object, and +thence to the underlying C structure for the shape. -In this code, @code{scm_assert_smob_type}, @code{SCM_SMOB_DATA}, and -@code{scm_from_bool} are from the standard Guile API. We assume that -@code{shape_tag} was given to us when we made the shape SMOB type, using -@code{scm_make_smob_type}. The call to @code{scm_assert_smob_type} -ensures that @var{shape} is indeed a shape. This is needed to guard -against Scheme code using the @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. +In this code, @code{scm_assert_foreign_object_type}, +@code{scm_foreign_object_ref}, and @code{scm_from_bool} are from the +standard Guile API. We assume that @code{shape_type} was given to us +when we made the shape foreign object type, using +@code{scm_make_foreign_object_type}. The call to +@code{scm_assert_foreign_object_type} ensures that @var{shape} is indeed +a shape. This is needed to guard against Scheme code using the +@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 available as Scheme procedures by calling the @code{scm_c_define_gsubr} -function. @code{scm_c_define_gsubr} (@pxref{Primitive Procedures}) takes arguments that -specify the Scheme-level name for the primitive and how many required, -optional and rest arguments it can accept. The @code{square?} primitive -always requires exactly one argument, so the call to make it available -in Scheme reads like this: +function. @code{scm_c_define_gsubr} (@pxref{Primitive Procedures}) +takes arguments that specify the Scheme-level name for the primitive and +how many required, optional and rest arguments it can accept. The +@code{square?} primitive always requires exactly one argument, so the +call to make it available in Scheme reads like this: @lisp scm_c_define_gsubr ("square?", 1, 0, 0, square_p); @@ -384,7 +387,7 @@ do lots of initialization and setup stuff @itemize @bullet @item -define all SMOB types +define all foreign object types @item export primitives to Scheme using @code{scm_c_define_gsubr} @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 parameter, to the end of @code{main}. -Assuming that you are using SMOBs and have written primitive code as -described in the preceding subsections, you also need to insert calls to -declare your new SMOBs and export the primitives to Scheme. These -declarations must happen @emph{inside} the dynamic scope of the -@code{scm_boot_guile} call, but also @emph{before} any code is run that -could possibly use them --- the beginning of @code{inner_main} is an -ideal place for this. +Assuming that you are using foreign objects and have written primitive +code as described in the preceding subsections, you also need to insert +calls to declare your new foreign objects and export the primitives to +Scheme. These declarations must happen @emph{inside} the dynamic scope +of the @code{scm_boot_guile} call, but also @emph{before} any code is +run that could possibly use them --- the beginning of @code{inner_main} +is an ideal place for this. @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 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 @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} primitive for Scheme purposes, which accesses the underlying structures -from its SMOB values and uses @code{dia_change_fill_pattern} to do the -real work: +from its foreign object values and uses @code{dia_change_fill_pattern} +to do the real work: @lisp 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. A similar argument applies to data representation. In the discussion of -SMOBs earlier, issues arose because of the different memory management -and lifetime models that normally apply to data structures in C and in -Scheme. However, with further Guile integration, you can resolve this -issue in a more radical way by allowing all your data structures to be -under the control of the garbage collector, and kept alive by references -from the Scheme world. Instead of maintaining an array or linked list -of shapes in C, you would instead maintain a list in Scheme. +foreign objects earlier, issues arose because of the different memory +management and lifetime models that normally apply to data structures in +C and in Scheme. However, with further Guile integration, you can +resolve this issue in a more radical way by allowing all your data +structures to be under the control of the garbage collector, and kept +alive by references from the Scheme world. Instead of maintaining an +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 @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 @code{dia_guile_shape} structures separate, and so wouldn't need to worry about the pointers between them. Instead, you could change the -SMOB definition to wrap the @code{dia_shape} structure directly, and -send @code{dia_guile_shape} off to the scrap yard. Cut out the middle -man! +foreign object definition to wrap the @code{dia_shape} structure +directly, and send @code{dia_guile_shape} off to the scrap yard. Cut +out the middle man! Finally, we come to the holy grail of Guile's free software / extension language approach. Once you have a Scheme representation for diff --git a/doc/ref/libguile-smobs.texi b/doc/ref/libguile-smobs.texi deleted file mode 100644 index f12ab1303..000000000 --- a/doc/ref/libguile-smobs.texi +++ /dev/null @@ -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{#} 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 - -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 -#include - -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 ("#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 -# -guile> (define i (make-image "Whistler's Mother" 100 100)) -guile> i -# -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