When an extension allocates resources that must be explicitly freed (in the same way that a port must be explicitly closed), a Racket object associated with the resource should be placed into the management of the current custodian with scheme_add_managed.
Before allocating the resource, call scheme_custodian_check_available to ensure that the relevant custodian is not already shut down. If it is, scheme_custodian_check_available will raise an exception. If the custodian is shut down when scheme_add_managed is called, the close function provided to scheme_add_managed will be called immediately, and no exception will be reported.
The f function is called by the custodian if it is ever asked to “shutdown” its values; o and data are passed on to f, which has the type
typedef void (*Scheme_Close_Custodian_Client)(Scheme_Object *o,
If strong is non-zero, then the newly managed value will be remembered until either the custodian shuts it down or scheme_remove_managed is called. If strong is zero, the value is allowed to be garbage collected (and automatically removed from the custodian).
Independent of whether strong is zero, the value o is initially weakly held. A value associated with a custodian can therefore be finalized via will executors.
If m (or the current custodian if m is NULL)is shut down, then f is called immediately, and the result is NULL.
void (*Scheme_Exit_Closer_Func)(Scheme_Object *o,
where d is the second argument for f.
At-exit functions are run in reverse of the order that they are added. An at-exit function is initially registered (and therefore runs last) that flushes each file-stream output port.
An at-exit function should not necessarily apply the closer function for every object that it is given. In particular, shutting down a file-stream output port would disable the flushing action of the final at-exit function. Typically, an at-exit function ignores most objects while handling a specific type of object that requires a specific clean-up action before the OS-level process terminates.