Subject: [clisp-list] FFI guru/wizard award to be rewarded

From: "Hoehle, Joerg-Cyril" <[email-masked]>
Date: Fri Mar 14 05:08:03 2003

Hi,

trying to obtain more feedback on CLISP FFI issues (not just Sam and me), I'll give the title of CLISP FFI guru to anybody who can explain why the following works:

;this one does not preserve the foreign-pointer object
; which is bad, but ignore it
(defun fcast (ff c-type)
  "Create a funcall'able FOREIGN-FUNCTION object at the given address, according to the supplied C type declaration"
  (with-c-var (new-function 'c-pointer (foreign-address ff))
    (cast new-function c-type)))

;(fcast #'c-self '(c-function (:return-type int)))
;(setf (symbol-function 'GUI-great-server)
;      (fcast (obtain-address "foo") '(c-function ...))

:)

Regards,
	Jorg Hohle.
You may wish to test using
(def-call-out c-self
  (:name "ffi_identity")
  (:arguments (obj c-pointer))
  (:return-type c-pointer) (:language :stdc))

---

From: Aurelio Bignoli <[email-masked]>
Date: Sun Mar 16 12:58:22 2003

Hoehle, Joerg-Cyril writes:
 > Hi,
 > 
 > trying to obtain more feedback on CLISP FFI issues (not just Sam
 > and me), I'll give the title of CLISP FFI guru to anybody who can
 > explain why the following works:

well, it depends on what you mean by "why": I have a very high level
explanation, but details and intricacies of CLISP FFI are still far
from my understanding...

 >     (cast new-function c-type)))

ffi:with-c-var allocates space on the C stack for a c-pointer foreign
place, calls it new-function and assigns to it the foreign address
associated with ff. Then ffi:cast creates a new foreign place of type
c-type having the same value of new-function (i.e., it "points" to the
same address). The value of the new foreign place is returned, and
new-function is lost.

I used the same "pattern" in a different situation: I have a foreign
functions (let's say my-func) that accepts, as an :out parameter, a
pointer to the following structure:

(def-c-struct my-struct
  (data c-pointer)
  (size uint32))

The function allocates some memory and assign its address to the data
member of the structure and the size of allocated memory to the size
member. I wrote the following function to read the returned data as a
vector of unsigned-bytes:

(defun my-func-wrapper (...)
  (let* ((result (my-func ...))
         (data (my-struct-data result)))
    (unwind-protect
        (with-c-var (p 'c-pointer data)
          (cast p `(c-ptr (c-array uint8 ,(my-struct-size result))))))
      (linux:free data)))

This technique is really convenient when the size of returned data can
be determined only at runtime. If, on the contrary, data returned is a
well known C type, it is better to avoid with-c-var/cast overhead by
using an ad-hoc foreign function for the conversion. For example, if
the function returns a C int (size is always sizeof(int)), better
perfomances can be obtained this way:

(defun my-func-int-wrapper (...)
  (let* ((result (my-func ...))
         (data (my-struct-data result)))
    (unwind-protect
        (get-int-foreign-data data)
      (linux:free data))))

(def-c-call get-int-data
  (:name "get_int_data")
  (:arguments (p c-pointer :in))
  (:return-type int))

int
get_int_data (void *p)
{
  return *(int *)p;
}

Not elegant, but quite fast :)