[Openmcl-devel] Calling foreign function with float array as argument?
Gary Byers
gb at clozure.com
Thu Nov 21 15:02:13 PST 2002
On Thu, 21 Nov 2002, Ronnie Hoogerwerf wrote:
>
> > There are a couple of approaches that would work in current and (near)
> > future versions of OpenMCL:
> >
> > a) Copy the contents of the lisp vector of single floats to a C vector
> > of single floats. Pass the C vector to foreign code; copy the C vector's
> > contents back into the lisp vector after the foreign call returns.
> >
> > b) Allocate the lisp vector in the C heap; pass the (fixed) address of
> > its first element to foreign code (which can then side-effect it directly.)
> > "Manually" dispose of the lisp vector when you're through with it.
> >
>
> > If you're interested, I'll try to explain (a) and (b) above in greater
> > detail.
>
> Thanks for the reply, I think I have some new ideas to try out now. However,
> I would appreciate it if you could go into some more detail on the suggestion
> you described above (and maybe give rough example of how to implement this).
>
> Thanks again.
This is the idea behind (a): it stack-allocates a C vector of single
floats, copies the contents of a lisp vector to that C vector, executes
an arbitrary body of code (perhaps a foreign function call), then optionally
copies the (possibly modified) floating-point values from the C vector back
into the lisp vector. (That is, it does all of this unless I misspelled
or misparenthesized something: I don't have an OpenMCL in front of me
at the moment.)
(defmacro with-c-single-float-vector ((c-vector lisp-vector &optional
copy-back) &body body)
(let* ((nbytes (gensym))
(cv (gensym))
(lv (gensym)))
`(let* ((,lv ,lisp-vector)
(,nbytes (* 4 (length ,lv))))
(ccl::%stack-block ((,cv ,nbytes))
;; Copy contents of the lisp vector to the C vector:
;; copy from byte offset 0 to byte offset 0.
(ccl::%copy-ivector-to-ptr ,lv 0 ,cv 0 ,nbytes)
(let* ((,c-vector ,cv))
(multiple-value-prog1 ; overkill, probably
(progn , at body)
,@(when copy-back
`((ccl::%copy-ptr-to-ivector ,cv 0 ,lv 0 ,nbytes)))))))))
(b) is a lot simpler, at least syntactically:
;;; Allocate a lisp vector of N SINGLE-FLOATs in the foreign heap;
;;; return the array and a MACPTR to its 0th element. The array will
;;; never move, but will never get GCed either.
(defun make-heap-single-float-vector (n)
(ccl::%make-heap-ivector arch::subtag-single-float-vector (* 4 n) n))
When "done" with that vector (assuming that the concept applies),
dispose of it:
(ccl::%dispose-heap-ivector v)
The function CCL::%MAKE-HEAP-IVECTOR could stand to be dressed up some:
it takes as arguments an "array type code", the vector's size in (8-bit)
bytes, and the vector's size in elements. (The size in bytes could obviously
be computed from the size in elements; the former's required, the latter's
optional but an error will be signalled if it's not provided.) I would
say "hey, don't blame me, I didn't write this" but I have a hunch that
I may have ...
Anyhow, baroque as its calling conventions may be, it works; it's used
by the code that implements many types of streams (so the buffer is
"nailed down" and can be passed to the OS, but can also be accessed as
a lisp string or byte vector.) The good news is that these things aren't
seen by the GC and so will never move; the bad news is that these things
aren't seen by the GC and therefore one has to manage their allocation/
deallocation "manually".
_______________________________________________
Openmcl-devel mailing list
Openmcl-devel at clozure.com
http://clozure.com/cgi-bin/mailman/listinfo/openmcl-devel
More information about the Openmcl-devel
mailing list