Paul Khuong mostly on Lisp

rss feed

Sun, 13 Nov 2011

 

Finalizing foreign pointers just late enough

SBCL exposes a low-level type, system-area-pointers (SAPs), which are roughtly equivalent to void * pointers in C. Since it’s so low level, we allow ourselves a lot of tricks to ensure performance. In particular, SAPs may be represented as raw addresses in machine registers. In order to simplify the implementation of this fairly useful optimization, they are given the same leeway as numbers with respect to EQ: SAPs that represent the same address, even from multiple evaluations of the same bindings or value, are not guaranteed to be EQ. When SAPs are compiled to machine registers, this lets us simply re-create a type-generic heap value as needed.

CFFI chose to directly expose SAPs in its user-facing interface. Finalizing SAPs is obviously a no-no: multiple references to the same (semantically) SAP can randomly be transformed into references to an arbitrary number of (physically) different objects.

If you want to finalize potentially-strange system-provided types, it’s probably better to wrap them in a read-only structure, and finalize that structure; for example:

(defstruct (wrapper 
            (:constructor make-wrapper (pointer))) 
  (pointer nil :read-only t)) 
 
(defun gced-foreign-alloc (type &rest rest) 
  (let* ((ptr (apply #’foreign-alloc type rest)) 
         (wrapper (make-wrapper ptr))) 
    (tg:finalize wrapper 
                 (lambda () 
                   (foreign-free ptr)))))

posted at: 00:48 | /Lisp | permalink

Made with PyBlosxom Contact me by email: pvk@pvk.ca.