Next: Double Smobs, Previous: Garbage Collecting Simple Smobs, Up: Defining New Types (Smobs)
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.
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; }
In the loop, only the image
pointer is used and the C compiler
has no reason to keep the image_smob
value anywhere. If
scm_cons
results in a garbage collection, image_smob
might
not be on the stack or anywhere else and could be freed, leaving the
loop accessing freed data. The use of scm_remember_upto_here_1
prevents this, by creating a reference to image_smob
after all
data accesses.
There's no need to do the same for lst
, since that's the return
value and the compiler will certainly keep it in a register or
somewhere throughout the routine.
The clear_image
example previously shown (see Type checking)
also used scm_remember_upto_here_1
for this reason.
It's only in quite rare circumstances that a missing
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 SCM
of a smob is referenced past all accesses to its
insides. Do this by adding an 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.)