Subject: [clisp-list] :malloc-free allocation -- here: instance methods

From: "Hoehle, Joerg-Cyril" <[email-masked]>
Date: Wed Apr 16 05:28:13 2003

Aurelio Bignoli wrote:

>this problem could be solved by a program that translates C
>declarations into FFI declarations. Such a program is available for
>some Common Lisp implementations, e.g LispWorks.

I still don't like this approach.
It introduces a dependency between .fas and .h files.
I believe there are several unwritten coding/design rules about CLISP which I  have integrated during the 10 years I've lived with CLISP.
One was portability of user's .fas files. That's why e.g. with-keyboard is a macro that encloses its body in a closure and calls an internal function. I don't know whether other developers [still/ever] share this goal.
Having C constant offsets live in a .fas file destroys this portability.
Probably more than 80% of the users don't care about this portability, since they work on a single system.

I still believe modules is a way to go to interface to foreign stuff. That implies C code, be it automatically generated or not. This C code should then contain the offsets and other architecture/platform dependent forms. Let the .fas file and Lisp code remain free of that.

This rule (design goal) also serves as a design guideline itself, since it answers what sort of code should go into either C or Lisp.

Another reason I don't like embedding C offsets in Lisp is that this approach IMHO only suits well to a native code compiler like CMUCL or CormanLisp. There, the offsets can be absent at the run-time. In CLISP, they could not. Also, tree shaking of unneeded C structures works with native code. In CLISP it would not (unless somebody implemented it *and* took care that it's easy to use). And one of my goals, which profoundly influenced the design of my AFFI, was to *not* reflect the myriads of C includes and structures of the Amiga in Lisp. MS-Windows even has more of these.

>Another solution could be a C program which, using the offsetof macro,
>prints the offset of the relevant DB function pointer members. Its

A program close to this already exists: utils/modprep
I bet very few people know about it. It's not even mentioned in impnotes (well, it has nothing to do with the implementation proper).
It allows to write C code with helpers macros for accessing Lisp objects. I never used it myself...

Another approach which I had thought of is to extent FFI:C-LINES
(C-LINES :defun 'MEM-WRITE "LISPFUN(mem_write,3,1,norest,nokey,0,NIL)" "
{
  // C or .d code of this function;
}")
would generate 3 pieces of code to go into the subr_table and maintain the subr_count.
A similar extension to C:LINES would be needed for objects.

Maybe that would be most useful for your polymorphic db-get/put functions.

>returned function prototype could be a problem: every DB fuction has
>its own parameter list. Probably the C factory function should return
I don't understand this.
>a c-pointer which has to be casted to the appropriate FFI:C-FUNCTION
>type before APPLYing it.

I've been thinking about extending C-POINTER to allow (C-POINTER c-type) to return a foreign-variable object of the given c-type. In other words, it returns a typed reference to a foreign object.

It might be useful for BDB and other situations (e.g. errno). But it also has its own set of problems (I'll talk about them another time).

(def-c-struct DB ; Beware: I don't know what the db struct looks like!
  (get (c-function (:arguments (db c-pointer) (txn c-pointer)
                    (key c-pointer) (value c-pointer) (flags uint32))
		   (:return-type bool) (:language :stdc)))
  (put (c-function (:arguments (db c-pointer) (txn c-pointer)
                    (key c-pointer) (value c-pointer) (flags uint32))
		   (:return-type bool) (:language :stdc)))
  (close (c-function (:arguments (db c-pointer))
		     (:return-type nil) (:language :stdc))))
(def-call-out db-create
  (:arguments ...)
  (:return-type (c-pointer DB)))

(setq *db* (db-create ...))
(funcall (foreign-value (ffi::%slot *db* 'get)) ; TODO factory
   *db* *txn* *key* ...)

(def-call-out __errno_location (:arguments) (:return-type (c-pointer int)))
(define-symbol-macro errno (foreign-value (__errno_location)))
; also works with setf errno!

I cannot recommend this implementation of errno, since every call would generate a garbage FOREIGN-ADDRESS and -VARIABLE object.

(C-LINES :defun 'get_errno "LISPFUNN(get_errno,0)"
"{ values1=L_to_I((sintL)errno); mv_count=1; }")
would be just as easy to add to linux.lisp, and much more performant.

Regards,
	Jorg Hohle.