🚀 go-pugleaf

RetroBBS NetNews Server

Inspired by RockSolid Light RIP Retro Guy

Article View: comp.lang.lisp.franz
Article #25

Re: Calling LISP functions from C.

#25
From: Andy Rapo
Date: Fri, 10 May 1991 15:34
111 lines
4379 bytes
Emily,

	I've been doing a lot of C/Lisp interfacing lately with
allegro.  In order to call a lisp function from C, you need to load
the C code into your lisp image.  Then you need to make your lisp  
functions c-callable and register them with Lisp.  Lisp stores a
pointer to the function in a table that C can access.  If the
registered Lisp function moves, the pointer in the table is updated.
In this way, C can always find the Lisp function.


  (defun-c-callable scale_z-callback (val)
    (format t "This is Lisp called with value ~A. ~%" val))
  
  (multiple-value-setq (*ptr1* *index1* *prev-ptr1*)
    (register-function 'scale_z-callback))

*ptr1* is a pointer to the Lisp function. *index1* is an index into 
the table of pointers.  I haven't used *prev-ptr1* yet.  *ptr1* is the
value you need for now.
  
You have to pass C the address of the Lisp function that you want to
call. The way I have done this is to set up a structure in C
that holds poiters to functions. In C the struct looks like this:

/* these are all pointer to functions that return int */
typedef struct ptr_type {
  int (*scale_z)();
  int (*scale_y)();
  int (*scale_x)();
	.
	.
	.
} ptr_type;

ptr_type ptr;

This C code would be in a file like c-interface.c.  This file would be compiled and the resulting object file, c-interface.o, would be loaded into Lisp.  More on this in a sec.

In order to assign values to members of the struct I make the struct
accessible to Lisp using the defcstruct function.  This function makes
accessor functions for a c-struct.  

;;; MAKE-PTR-STRUCT-ACCESSORS makes accessor functions which, when
;;; supplied with a pointer to a C struct, will return the value
;;; stored there.  Setf can be used to modify the C struct.  The C
;;; struct exists in C space and is not moved by Lisp garbage collection.
(defun make-ptr-struct-accessors ()
  (defcstruct (ptr :malloc)
      (scale_z :unsigned-long)
      (scale_y :unsigned-long)
      (scale_x :unsigned-long)
	.
	.
	.     ))

Then I can get the value of a c-struct member (i.e. scale_z) by typing

(ptr-scale_x *pointer-to-cstruct*).

These are like CLOS accessors.

I have to supply a pointer to the (ptr-scale_z ...)
function so that Lisp can find the c-struct.  In C, I've defined the
following function which returns the address of the c-struct.

ptr_type *get_ptr_address()
{
  return &ptr;
}

I make this function (and the other C objects I need) available to Lisp by loading the .o file that it is defined in.

  (load "" :foreign-files '("c-interface.o")
	:system-libraries '("m" "gl_s"))

Next I make Lisp aware of the newly loaded c function.
  
  (defforeign 'get_ptr_address :arguments nil
	      :return-type :integer))

And then I call the c function, get_ptr_address, to get the address of
the c-struct, *ptr*, and use it with the Lisp accessor functions to get at the values of the c-struct.

;;; SET-PTR-STRUCT-ADDRESS sets *ptr* to be the address of the C
;;; struct which contains pointers to Lisp functions.
;;; These pointers are used by C to "callback" to Lisp.
(defun set-ptr-struct-address ()
  (setf *ptr* (get_ptr_address)))

(defun set-callback-ptrs ()
  (setf (ptr-scale_z *ptr*) *ptr1*))

Now, the c-struct member, ptr.scale_z, contains *ptr1* which is the
address of the Lisp function, scale_z-callback.

C can call this Lisp function like this:

(*ptr.scale_z)(val);

Whew....


Well, its actually very easy to do, and worth the effort.  Interfacing
between C and Lisp can make life very easy for you later on.  If you
have any questions let me know.  As I said, I've been doing this a lot
lately and would be glad to share what I've learned.

Andrew Rapo
Cornell University
Simulation/Robotics
Technical Details
Message-ID: <1991May10.153446.7573@cs.cornell.edu>
Path: arc1-ca.pugleaf.net!utzoo!utgpu!news-server.csri.toronto.edu!cs.utexas.edu!wuarchive!usc!rpi!batcomputer!cornell!cs.cornell.edu!rapo
References: <DICKINSN.91May8223931@pele.cs.unm.edu>

Show Full Headers
Complete Article Headers
Path: arc1-ca.pugleaf.net!utzoo!utgpu!news-server.csri.toronto.edu!cs.utexas.edu!wuarchive!usc!rpi!batcomputer!cornell!cs.cornell.edu!rapo
From: rapo@cs.cornell.edu (Andy Rapo)
Newsgroups: comp.lang.lisp.franz
Subject: Re: Calling LISP functions from C.
Message-ID: <1991May10.153446.7573@cs.cornell.edu>
Date: 10 May 91 15:34:46 GMT
References: <DICKINSN.91May8223931@pele.cs.unm.edu>
Sender: news@cs.cornell.edu (USENET news user)
Distribution: comp.lang.lisp.franz
Organization: Cornell University, CS Dept., Ithaca, NY
Lines: 111
Nntp-Posting-Host: spinet.cs.cornell.edu