Next: , Previous: Calling Scheme procedures from C, Up: C interface


7.7 Interacting with the Scheme heap in C

Scheme48 uses a precise copying garbage collector. Any code that allocates objects within the Scheme48 heap may trigger a garbage collection. Variables bound to values in the Scheme48 heap need to be registered with the garbage collector so that the value will be safely held and so that the variables will be updated if the garbage collector moves the object. The garbage collector has no facility for updating pointers to the interiors of objects, so such pointers, for example the ones returned by S48_EXTRACT_STRING, will likely become invalid when a garbage collection occurs.

— C macro: S48_DECLARE_GC_PROTECT (n)
— C macro: void S48_GC_PROTECT_n (s48_value var1, ..., s48_value varn)
— C macro: void S48_GC_UNPROTECT ()

S48_DECLARE_GC_PROTECT, where 1 <= n <= 9, allocates storage for registering n variables. At most one use of S48_DECLARE_GC_PROTECT may occur in a block. After declaring a GC protection, S48_GC_PROTECT_n registers the n variables with the garbage collector. It must be within the scope that the S48_DECLARE_GC_PROTECT occurred in and before any code that can cause a garbage collection. S48_GC_UNPROTECT removes the current block's protected variables from the garbage collector's list. It must be called at the end of the block after any code that may cause a garbage collection. Omitting any of the three may cause serious and hard-to-debug problems, because the garbage collector may relocate an object and invalidate unprotected s48_value pointers. If not S48_DECLARE_GC_PROTECT is matched with a S48_GC_UNPROTECT or vice versa, a gc-protection-mismatch exception is raised when a C procedure returns to Scheme.

— C macro: void * S48_GC_PROTECT_GLOBAL (global)
— C macro: void S48_GC_UNPROTECT_GLOBAL (void *handle)

S48_GC_PROTECT_GLOBAL permanently registers the l-value global with the system as a garbage collection root. It returns a pointer which may then be supplied to S48_GC_UNPROTECT_GLOBAL to unregister the l-value as a root.

7.7.1 Keeping C data structures in the Scheme heap

C data structures can be stored within the Scheme heap by embedding them inside byte vectors. The following macros can be used to create and access embedded C objects.

— C macro: s48_value S48_MAKE_VALUE (type)
— C macro: type S48_EXTRACT_VALUE (s48_value bytev, type)
— C macro: type * S48_EXTRACT_VALUE (s48_value bytev, type)
— C macro: void S48_SET_VALUE (s48_value bytev, type, type value)

S48_MAKE_VALUE allocates a byte vector large enough to hold a C value whose type is type. S48_EXTRACT_VALUE returns the contents of the byte vector bytev cast to type, and S48_EXTRACT_VALUE_POINTER returns a pointer to the contents of the byte vector, which is valid only until the next garbage collection. S48_SET_VALUE stores a value into the byte vector.

7.7.2 C code and heap images

Scheme48 uses dumped heap images to restore a previous system state. The Scheme48 heap is written into a file in a machine-independent and operating-system-independent format. The procedures described above, however, may be used to create objects in the Scheme heap that contain information specific to the current machine, operating system, or process. A heap image containing such objects may not work correctly when resumed.

To address this problem, a record type may be given a resumer procedure. On startup, the resumer procedure for a record type is applied to each record of that type in the image being restarted. This procedure can update the record in a manner appropriate to the machine, operating system, or process used to resume the image. Note, though, that there is no reliable order in which record resumer procedures are applied. To specify the resumer for a record type, use the define-record-resumer procedure from the record-types structure.