Return-Path: Received: from b.gp.cs.cmu.edu by G.GP.CS.CMU.EDU id aa10485; 4 Dec 91 20:20:28 EST Received: from lisp-pmax2.slisp.cs.cmu.edu by B.GP.CS.CMU.EDU id aa08611; 4 Dec 91 20:18:39 EST Received: from BatMail.robin.v2.12.CUILIB.3.45.SNAP.NOT.LINKED.LISP.PMAX2.SLISP.CS.CMU.EDU.pmax.ul4 via MS.5.6.LISP-PMAX2.SLISP.CS.CMU.EDU.pmax_ul4; Wed, 4 Dec 1991 20:18:12 -0500 (EST) Message-ID: Date: Wed, 4 Dec 1991 20:18:12 -0500 (EST) From: William.Lott@cs.cmu.edu To: cmucl-bugs@cs.cmu.edu, Jussi Rintanen Subject: Re: Calling Lisp from C (not a software bug) In-Reply-To: Message from "Rob_MacLachlan@LISP-PMAX2.SLISP.CS.CMU.EDU" dated "Wed, 04 Dec 91 18:00:31 EST" Rob_MacLachlan@LISP-PMAX2.SLISP.CS.CMU.EDU writes: > Uhhh... Actually, if you look at the subject, you will see he wants to call > Lisp *from* C. There is a C function which can take a small number of > integer/pointer arguments, call a Lisp function, and get one return value. > But I don't know what it is called. > > Rob Oops. Silly me. This time I'll address the question that was asked. The problem is not doing the actual function call, but making sure your pointer to the Lisp function gets handled correctly during GC. Unfortunately, there is no clean way to do this currently. The simplest way would be to load your lisp function, call PURIFY, and then pass the address of the lisp function to C. Purify does a special GC where everything that survives gets moved to either static or read-only space, and never moved again. But if you redefine the lisp function, you will have to call purify again, and pass the new pointer to C. Otherwise, the C code will continue to call the old version. Or better yet, you could just pass the symbol to C and have it indirect the function cell each time: 'your-symbol (lisp::purify) (def-c-routine "note_your_symbol" (void) (sym unsigned-long)) (note_your_symbol (kernel:get-lisp-obj-address 'your-symbol)) If you don't want to call PURIFY, then you need to tell the C code the new pointer value every time you GC. You could easily do that by adding a function to *AFTER-GC-HOOKS* that called note_your_symbol with the new address. Once C knows about the function, you can use some internal magic stuff to do the funcall: #include "lisp.h" static lispobj your_symbol; void note_your_symbol(symbol) lispobj symbol; { your_symbol = symbol; } void invoke_your_function(num, str) long num; char *str; { extern lispobj *current_control_stack_pointer; lispobj *args = current_control_stack_pointer; lispobj result; int oldmask; oldmask = sigblock(sigmask(SIGINT)); current_control_stack_pointer += 2; args[0] = alloc_number(num); args[1] = alloc_string(str); result = call_into_lisp(your_symbol, ((struct symbol *)PTR(your_symbol))->function, args, 2); /* Do something with result. */ sigsetmask(oldmask); } Note: you can't keep any pointers to lisp objects alive in your C code. The garbage collector will not see them, and hence won't fix them up when it moves the object. The garbage collector will only be invoked if you are running in Lisp code, but if some signal handler calls into lisp (which most of them do), then the garbage collector could be invoked. This means that any time your C code has ahold of lisp pointers, you should wrap it with a sigblock/sigsetmask. Or you could just assume that nobody is going to press ^C at a bad time. Unfortunately, the lisp.h header file isn't installed anywhere. You can get the version for whatever system you are running on via anonymous FTP from one of these directories: /afs/cs/project/clisp/build/sun4c_41/beta/ldb/lisp.h /afs/cs/project/clisp/build/sun4_mach/beta/ldb/lisp.h /afs/cs/project/clisp/build/pmax_mach/beta/ldb/lisp.h Note: lisp.h is machine generated whenever we build a new system, so it can change at pretty random intervals. Whenever you pick up a new system, make sure you pick up a new copy of lisp.h with it. Hope this helps. If you need any more information, let us know. -William Lott CMU Common Lisp Group