From: <don...@is...> - 2005-10-22 06:39:43
|
Sam Steingold writes: > visit http://www.podval.org/~sds/clisp/impnotes/faq.html#faq-doc tomorrow. This facility, also known Foreign Language Interface allows one to call a function implemented in C from inside CLISP and to do many related things, like inspect and modify foreign memory, define callback (i.e., make a lisp function available to the C world), etc. To use this facility, one writes a foreign function description into an ordinary Lisp file, which is then compiled and loaded as usual. This helps a lot. A few relatively minor complaints. First, you don't have to compile the FFI descriptions, at least with shared libraries. Perhaps better to say that you call lisp functions to tell clisp about the foreign functions, types, variables, etc. and that these calls can be compiled like other calls to lisp functions. Second, I think one of the important points to mention is that c doesn't know about lisp memory allocation and garbage collection. This presents various problems such as - you should not pass to c functions pointers to lisp data if the c function could store the pointer and use it after a GC, since the GC may move the data and thus invalidate those pointers - you can, instead, allocate "c" memory that is not GC'd (mention how to do that). Of course, you then have to copy data between lisp and c memory, and you have to manage c memory in the same way as you would in c (BTW, can you store c pointers in lisp memory?) I think above is an important part of the difference between FFI and modules (if I understand correctly, please tell me if not). The only real difference between modules and the core clisp code is that there's a build time switch to control whether or not a module is included. That code therefore gets to use memory managed by lisp (at the expense of following all the rules for that). It also gets to support lisp function calling conventions (optional/keyword/rest). So far as I see now, that seems to cover the difference. Perhaps you can add to the list. I suppose this and 31.2.8 belong together, but it seems to me that the right place is not in the middle of 31. I still think that this should be mentioned (perhaps by reference) in the introduction to both modules and FFI. (Is AFFI functionally the same as FFI? Perhaps there too.) There are two basic ways to do define a foreign function: 1. Use dlopen and dlsym to get to the location of the function code in a dynamic library. To access this facility, pass the :LIBRARY option to FFI:DEF-CALL-OUT and FFI:DEF-C-VAR. Unfortunately, this functionality is not available on some operating systems, and, also, it offers only a part of the foreign functionality: cpp macros and inline functions cannot be accessed this way. I don't see that the other way provides access to macros and inline functions either. 2. Use a somewhat less direct way: when you do not use the :LIBRARY argument, COMPILE-FILE produces a C file. Then you compile (with a C compiler) and link it into CLISP (statically, linking it into lisp.a, or dynamically, loading it into a running CLISP using dlopen and dlsym). This way you can use any functionality your foreign library exports, whether using ordinary functions, inline functions, or cpp macros. Does it make sense to export c macros or inline functions? Maybe I'm missing something. I thought those exist only at compile time. BTW, you've told me something about how shared library functions are called. (Not that I actually understand it yet.) How about non-shared-library functions? Do those have the same overhead? Also, down in the examples, I thought I'd try one and had some trouble (def-call-out div (:arguments (numer int) (denom int)) (:return-type div_t)) *** - FFI::LOOKUP-FOREIGN-FUNCTION: A foreign function "div" does not exist works when I add (:library :default) Yet another thought: RAWSOCK:HTONS is almost 3 times as fast (as ffi :library version) I got a similar result but that included loop overhead which was actually the majority of the time in RAWSOCK:HTONS. If you subtract that then the factor is much higher. Time for a single call gives me much larger times (per call) than a loop. |