[cffi-devel] Static vectors suitable for FFI

Stelian Ionescu stelian.ionescu-zeus at poste.it
Tue May 5 00:44:41 UTC 2009


Attached is an implementation for SBCL. make-static-vector only
allocates instances of (simple-array (unsigned-byte 8) (*)) but that can
be extended to other unboxed arrays.
The current sharable vector interface doesn't work very well because it
doesn't allow me for instance to pin a list of vectors, but only a
single vector at a time. Also, I'd prefer to avoid pinning at all given
how it interferes with the GC.

-- 
Stelian Ionescu a.k.a. fe[nl]ix
Quidquid latine dictum sit, altum videtur.

-------------- next part --------------
(in-package :cffi)

(declaim (inline fill-foreign-memory))
(defun fill-foreign-memory (pointer length value)
  "Fill LENGTH octets in foreign memory area POINTER with VALUE."
  (declare (sb-ext:muffle-conditions sb-ext:compiler-note))
  (sb-kernel:system-area-ub8-fill value pointer 0 length))

(declaim (inline copy-foreign-memory))
(defun copy-foreign-memory (src-ptr dst-ptr length)
  "Copy LENGTH octets from foreign memory area SRC-PTR to DST-PTR."
  (sb-kernel:system-area-ub8-copy src-ptr 0 dst-ptr 0 length))

(defconstant +array-header-size+ (* 2 sb-vm:n-word-bytes))

(defun make-static-vector (size)
  "Create an (UNSIGNED-BYTE 8) simple vector of size SIZE which will
not be moved by the garbage collector. The vector might be allocated in
foreign memory so you must always call FREE-STATIC-VECTOR to free it."
  (declare (sb-ext:muffle-conditions sb-ext:compiler-note)
           (optimize speed))
  (check-type size alexandria:non-negative-fixnum)
  (let* ((allocation-size (+ size +array-header-size+))
         (memblock (foreign-alloc :char :count allocation-size)))
    (cond
      ((null-pointer-p memblock)
       ;; FIXME: signal proper error condition
       (error "Cannot allocate foreign memory!"))
      (t
       ;; the malloc'd memory must be aligned on a 2-word boundary
       ;; I'd expect malloc() to return a properly aligned pointer everywhere
       ;; but I'm not certain. SIONESCU 20090505
       (assert (zerop (mod (pointer-address memblock) (* 2 sb-vm:n-word-bytes))))
       (fill-foreign-memory memblock allocation-size 0)
       (let ((type-tag sb-vm:simple-array-unsigned-byte-8-widetag)
             (length (sb-vm:fixnumize size)))
         (setf (mem-aref memblock :int 0) type-tag
               (mem-aref memblock :int 1) length)
         (sb-kernel:%make-lisp-obj (logior (pointer-address memblock)
                                           sb-vm:other-pointer-lowtag)))))))

(declaim (inline static-vector-pointer))
(defun static-vector-pointer (vector)
  "Return a foreign pointer to VECTOR's data.
VECTOR must be a vector created by MAKE-STATIC-VECTOR."
  (make-pointer (sb-kernel:get-lisp-obj-address vector)))

(declaim (inline free-static-vector))
(defun free-static-vector (vector)
  "Free VECTOR if allocated in foreign memory."
  (declare (sb-ext:muffle-conditions sb-ext:compiler-note))
  (let ((pointer (static-vector-pointer vector)))
    (foreign-free (inc-pointer pointer (- 1 +array-header-size+)))))

(defmacro with-static-vector ((ptr-var size) &body body)
  "Bind PTR-VAR to a static vector of size SIZE and execute BODY
within its dynamic extent. The static vector is freed upon exit."
  (alexandria:with-gensyms (static-vector)
    `(let* ((,static-vector (make-static-vector ,size))
            (,ptr-var (static-vector-pointer ,static-vector)))
       (unwind-protect
            (progn , at body)
         (free-static-vector ,static-vector)))))
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 198 bytes
Desc: This is a digitally signed message part
URL: <https://mailman.common-lisp.net/pipermail/cffi-devel/attachments/20090505/4867f883/attachment.sig>


More information about the cffi-devel mailing list