diff options
Diffstat (limited to 'doc/ref/libguile-smobs.texi')
-rw-r--r-- | doc/ref/libguile-smobs.texi | 670 |
1 files changed, 0 insertions, 670 deletions
diff --git a/doc/ref/libguile-smobs.texi b/doc/ref/libguile-smobs.texi deleted file mode 100644 index d68b71812..000000000 --- a/doc/ref/libguile-smobs.texi +++ /dev/null @@ -1,670 +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 will be called from a dedicated finalization thread. This -ensures that the finalization doesn't run within the critical section of -any other thread known to Guile. It also lowers latency, as your Guile -program doesn't have to wait for finalizers to run. However, if your -Guile is built without threads, the finalizers may be called within the -critical section of some other piece of code. - -In either case, finalizers (free functions) run concurrently with the -main program, and so they need to be 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 |