Next: Type checking, Previous: Describing a New Type, Up: Defining New Types (Smobs)
Normally, smobs can have one 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 SCM
value, a pointer to void
, or an
integer that fits into a size_t
or 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. See Double Smobs, for their discussion.
Guile provides functions for managing memory which are often helpful when implementing smobs. See Memory Blocks.
To retrieve the immediate word of a smob, you use the macro
SCM_SMOB_DATA
. It can be set with SCM_SET_SMOB_DATA
.
The 16 extra bits can be accessed with SCM_SMOB_FLAGS
and
SCM_SET_SMOB_FLAGS
.
The two macros SCM_SMOB_DATA
and SCM_SET_SMOB_DATA
treat
the immediate word as if it were of type scm_t_bits
, which is
an unsigned integer type large enough to hold a pointer to
void
. Thus you can use these macros to store arbitrary
pointers in the smob word.
When you want to store a SCM
value directly in the immediate
word of a smob, you should use the macros SCM_SMOB_OBJECT
and
SCM_SET_SMOB_OBJECT
to access it.
Creating a smob instance can be tricky when it consists of multiple steps that allocate resources and might fail. It is recommended that you go about creating a smob in the following way:
scm_gc_malloc
.
SCM
values in it that must be protected.
Initialize these fields with SCM_BOOL_F
.
A valid state is one that can be safely acted upon by the mark and free functions of your smob type.
SCM_NEWSMOB
, passing it the initialized
memory block. (This step will always succeed.)
This procedure ensures that the smob is in a valid state as soon as it
exists, that all resources that are allocated for the smob are
properly associated with it so that they can be properly freed, and
that no SCM
values that need to be protected are stored in it
while the smob does not yet competely exist and thus can not protect
them.
Continuing the example from above, if the global variable
image_tag
contains a tag returned by scm_make_smob_type
,
here is how we could construct a smob whose immediate word contains a
pointer to a freshly allocated struct image
:
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. */ SCM_NEWSMOB (smob, image_tag, image); /* Step 4: Finish the initialization. */ image->name = name; image->pixels = scm_gc_malloc (width * height, "image pixels"); return smob; }
Let us look at what might happen when make_image
is called.
The conversions of s_width and s_height to int
s might
fail and signal an error, thus causing a non-local exit. This is not a
problem since no resources have been allocated yet that would have to be
freed.
The allocation of image in step 1 might fail, but this is likewise no problem.
Step 2 can not exit non-locally. At the end of it, the image
struct is in a valid state for the mark_image
and
free_image
functions (see below).
Step 3 can not exit non-locally either. This is guaranteed by Guile. After it, smob contains a valid smob that is properly initialized and protected, and in turn can properly protect the Scheme values in its image struct.
But before the smob is completely created, SCM_NEWSMOB
might
cause the garbage collector to run. During this garbage collection, the
SCM
values in the image struct would be invisible to Guile.
It only gets to know about them via the mark_image
function, but
that function can not yet do its job since the smob has not been created
yet. Thus, it is important to not store SCM
values in the
image struct until after the smob has been created.
Step 4, finally, might fail and cause a non-local exit. In that case,
the complete creation of the smob has not been successful, but it does
nevertheless exist in a valid state. It will eventually be freed by
the garbage collector, and all the resources that have been allocated
for it will be correctly freed by free_image
.