Peter Seibel | 14 Mar 2007 05:57
Gravatar

Passing Lisp values into and back out of C?

This must either be really trivial or completely impossible: suppose I 
need to create an instance of a C structure that has a void* slot. I 
want to fill that slot with (some representation of) an arbitrary Lisp 
value so that when that structure is handed back to my Lisp code I can 
get back to the Lisp object. Other than keeping my own integer->object 
mapping and passing the integer to C and translating it back to the 
object when I get it back, is there some easier way to do this in CFFI?

-Peter

--

-- 
Peter Seibel            :  peter <at> gigamonkeys.com
Gigamonkeys Consulting  :  http://www.gigamonkeys.com/
Luis Oliveira | 14 Mar 2007 18:03
Picon
Gravatar

Re: Passing Lisp values into and back out of C?

Peter Seibel <peter <at> gigamonkeys.com> writes:
> Other than keeping my own integer->object mapping and passing the
> integer to C and translating it back to the object when I get it back,
> is there some easier way to do this in CFFI?

AFAIK, that is the best way to do it.  You could also serialize Lisp
objects into a foreign array, though the situations where that would be
a better approach seem limited and you loose object identity.

SBCL and some other Lisps will let you get pointers to vectors of some
types.  With Allegro you apparently can get pointers to arbitrary Lisp
objects with EXCL:LISPVAL-TO-ADDRESS and then get it back with
SYS:MEMREF (though you have to get the offset right, and AFAICT handle
immediate values yourself); it seems easier to do your own mapping
instead.  You have to worry about the GC moving objects around too.

Hmm, since you're asking whether this is doable in *CFFI*, the answer is
no then. :-)  You can, however, make good use of CFFI's type system!

(use-package :cffi)

(define-foreign-type lisp-object-type ()
  ((weakp :initarg :weakp))
  (:actual-type :unsigned-int))

(define-parse-method lisp-object (&key weak-mapping)
  (make-instance 'lisp-object-type :weakp weak-mapping))

(defvar *regular-hashtable* (make-hash-table))

(Continue reading)

James Bielman | 14 Mar 2007 20:04

Re: Re: Passing Lisp values into and back out of C?

On Wed, 2007-03-14 at 17:03 +0000, Luis Oliveira wrote:
> Peter Seibel <peter <at> gigamonkeys.com> writes:
> > Other than keeping my own integer->object mapping and passing the
> > integer to C and translating it back to the object when I get it back,
> > is there some easier way to do this in CFFI?
>
> Hmm, since you're asking whether this is doable in *CFFI*, the answer is
> no then. :-)  You can, however, make good use of CFFI's type system!

If the use case is passing Lisp data to callbacks limited to a certain
dynamic extent, you could do this easily by consing bindings from ints
to Lisp objects on an association list...  Something like:

;;; Counter used to generate unique IDs for Lisp objects passed to
;;; foreign code.  The counters are only guaranteed to be unique
;;; during the dynamic extent of which they are bound.
(defvar *lisp-object-counter* 0)

;;; Association list of Lisp object IDs to Lisp objects.
(defvar *lisp-objects* nil)

;;; Create a binding for a unique ID to a Lisp object during the
;;; extent of BODY.  The ID may be coerced to a pointer and passed to
;;; foreign code, then looked up from callback functions.
(defmacro with-lisp-object-id ((id object) &body body)
  `(let* ((,id *lisp-object-counter*)
          (*lisp-object-counter* (1+ *lisp-object-counter*))
          (*lisp-objects* (acons ,id ,object *lisp-objects*)))
     , <at> body))

(Continue reading)

Luís Oliveira | 14 Mar 2007 20:09
Picon
Gravatar

Re: Re: Passing Lisp values into and back out of C?

On 14/03/07, Robert Goldman <rpgoldman <at> real-time.com> wrote:
> IIUC, this is pretty similar to what Allegro does with its memref trick.
>  So you might want a big #-allegro around this if you were going to do it!

Hmm, I don't think so. SYS:MEMREF seems pretty low-level to me:
<http://www.franz.com/support/documentation/8.0/doc/operators/system/memref.htm>

--

-- 
Luís Oliveira
http://student.dei.uc.pt/~lmoliv/
Jack Unrue | 15 Mar 2007 04:51
Picon

how to revise foreign type translators to work with cffi-newtypes

Hi there. I'm looking into some compile errors that are reported by SBCL
when compiling Graphic-Forms using the cffi-newtypes branch. I have
a number of foreign types defined, and for a couple of these, I also
declare aliases for :pointer such that I am then able to implement
type translators.

Here's an example (assume there are existing CL structures called
RECTANGLE, SIZE, and POINT, and it is instances of RECTANGLE
which are to be translated into and out of the foreign struct RECT
that I'm defining below):

(cffi:defctype rect-pointer :pointer)

(cffi:defcstruct rect
  (left :long)
  (top :long)
  (right :long)
  (bottom :long))

(defmethod cffi:free-translated-object (ptr (name (eql 'rect-pointer)) param)
  (declare (ignore param))
  (cffi:foreign-free ptr))

(defmethod cffi:translate-from-foreign (ptr (name (eql 'rect-pointer)))
  (if (cffi:null-pointer-p ptr)
    (make-rectangle)
    (cffi:with-foreign-slots ((left top right bottom) ptr rect)
      (let ((pnt (make-point :x left :y top))
            (size (make-size :width (- right left) :height (- bottom top))))
        (make-rectangle :location pnt :size size)))))
(Continue reading)

Luis Oliveira | 15 Mar 2007 06:14
Picon
Gravatar

Re: how to revise foreign type translators to work with cffi-newtypes

"Jack Unrue" <jdunrue <at> gmail.com> writes:
> (cffi:defctype rect-pointer :pointer)

(define-foreign-type rect-pointer-type ()
  ()
  (:actual-type :pointer)
  (:simple-parser rect-pointer))

> (defmethod cffi:free-translated-object (ptr (name (eql 'rect-pointer)) param)
>  (declare (ignore param))
>  (cffi:foreign-free ptr))

Now RECT-POINTER-TYPE is actually a CLOS class. So you should use a
normal specializer instead of an EQL specializer.

(defmethod free-translate-object (ptr (type rect-pointer-type) param)
  ...)

> Can anyone make suggestions as to what I should change to be compatible
> with the cffi-newtypes branch?

That's basically it.  Change the type definition and change EQL
specializers to normal specializers.  I've compiled the cffi-newtypes
manual and uploaded it here:

  <http://common-lisp.net/~loliveira/tmp/cffi-newtypes/>

The section about foreign types should be updated.  (Not all of the
reference nodes are though, I think.)

(Continue reading)

Jack Unrue | 16 Mar 2007 03:45
Picon

cffi-sys::default-encoding returns nil on clisp/mingw

Running CLISP on my system with the newtypes branch, I find that the
CFFI-SYS::DEFAULT-ENCODING function is returning NIL. Some poking
around reveals that CUSTOM:*FOREIGN-ENCODING* is set to
#<ENCODING CHARSET:CP1252 :DOS>

I looked at the symbol values for everything in the :charset package,
and they all specify :UNIX instead of :DOS and so that's what
CFFI-SYS::*ENCODINGS* and CFFI-SYS::*CLISP-ENCODINGS*
get populated with.

So I can see why DEFAULT-ENCODING is returning NIL. Before I head
over to clisp-devel and ask about this, I just wanted to see whether
this situation surprises anyone here, or if you think it might be a CLISP
build configuration issue (which would be funny because I'm one of
the MingW package maintainers), or ???

For instance, can anyone point me at a spot in the CLISP manual that
states that *FOREIGN-ENCODING* will always correspond to the value
of one of the symbols in the :charset package?

This is on WinXP SP2, CLISP 2.41 (mingw special) with nothing related
to encoding for command-line arguments.

--

-- 
Jack Unrue
Luis Oliveira | 17 Mar 2007 01:26
Picon
Gravatar

Re: cffi-sys::default-encoding returns nil on clisp/mingw

"Jack Unrue" <jdunrue <at> gmail.com> writes:
> So I can see why DEFAULT-ENCODING is returning NIL. Before I head
> over to clisp-devel and ask about this, I just wanted to see whether
> this situation surprises anyone here, or if you think it might be a CLISP
> build configuration issue (which would be funny because I'm one of
> the MingW package maintainers), or ???

Hmm, it's somewhat strange, I guess.  BTW, should we worry about line
terminator conversions?

> This is on WinXP SP2, CLISP 2.41 (mingw special) with nothing related
> to encoding for command-line arguments.

I've applied a fix and a regression test for this.  Should work now,
though I haven't tested on windows.

Thanks for the bug report.

--

-- 
Luís Oliveira
http://student.dei.uc.pt/~lmoliv/
Luis Oliveira | 17 Mar 2007 20:10
Picon
Gravatar

cffi-tests coverage report

Hello,

Juho Snellman recently[1] posted a very useful SBCL-specific coverage
tool.  I did this for CFFI to test the coverage of cffi-tests.  The
report can be found here:

  <http://common-lisp.net/~loliveira/tmp/cffi-tests-coverage/>

The results seem pretty good to me: 80.5% code coverage.  It does reveal
some missed spots so if someone feels like writing some tests, look at
this report for picking where to start. :-)

A significant percentage of these missed spots are a result of compiler
macros (or type expansions) kicking in or error branches not being
exercised.

[1] http://thread.gmane.org/gmane.lisp.steel-bank.devel/8721

--

-- 
Luís Oliveira
http://student.dei.uc.pt/~lmoliv/
Jack Unrue | 17 Mar 2007 20:34
Picon

Re: Re: cffi-sys::default-encoding returns nil on clisp/mingw

On 3/16/07, Luís Oliveira <luismbo <at> gmail.com> wrote:
>
> BTW, should we worry about line terminator conversions?

The code I write that needs CFFI is UI-related, so I'm not really
affected by EOL conversion in that context[1]. Maybe folks that
have to interact with databases or HTTP are more sensitive to it.

> I've applied a fix and a regression test for this.  Should work now,
> though I haven't tested on windows.
>
> Thanks for the bug report.

Thank you for the fix, it works great here.

--

-- 
Jack Unrue

[1] I do have to worry about EOL chars embedded in string values
for certain GUI functions to work in the desired way, but I don't have
any code that uses CFFI and does stream I/O.

Gmane