[Openmcl-devel] Calling foreign function with float array as argument?
Ronnie Hoogerwerf
ronnieh at head-cfa.harvard.edu
Thu Nov 21 09:23:50 PST 2002
> There are a couple of approaches that would work in current and (near)
> future versions of OpenMCL:
>
> a) Copy the contents of the lisp vector of single floats to a C vector
> of single floats. Pass the C vector to foreign code; copy the C vector's
> contents back into the lisp vector after the foreign call returns.
>
> b) Allocate the lisp vector in the C heap; pass the (fixed) address of
> its first element to foreign code (which can then side-effect it directly.)
> "Manually" dispose of the lisp vector when you're through with it.
>
> If you're interested, I'll try to explain (a) and (b) above in greater
> detail.
Thanks for the reply, I think I have some new ideas to try out now. However,
I would appreciate it if you could go into some more detail on the suggestion
you described above (and maybe give rough example of how to implement this).
Thanks again.
>
>
> On Thu, 21 Nov 2002, Ronnie Hoogerwerf wrote:
>
> >
> > Hi,
> >
> > I relatively new to openmcl but have some experience using mcl and cmucl.
> > I am trying to port a lisp interface to the PGPLOT graphics library to
> > openmcl (the orignal was written for cmucl) and am running into some
> > problems that I cannot seem to solve. I need to pass an array (of type
> > single-float) to a foreign function. This function then changes the values
> > of the array and I would like to retrieve those changed values.
> > An example of the c-code looks something like:
> >
> >
> > /****************************************/
> > #include "cpgplot.h"
> > #include <string.h>
> > extern int pgcurs_();
> >
> > int cpgcurs(float *x, float *y, char *ch_scalar)
> > {
> > int len_ch_scalar = 1;
> > int r_value;
> > r_value = pgcurs_(x, y, ch_scalar, len_ch_scalar);
> > return r_value;
> > }
> > /****************************************/
> >
> > The cmucl code solves the problem of passing pointers to float by
> > obtaining the memory address of the lisp array (using
> > kernel:get-lisp-obj-address) and then passes the address to the function.
> >
>
> That solution would (in general) fail if a GC happened during the execution
> of the foreign function: the garbage collector could move the lisp vector,
> and would have no way to tell C code where it was moved to.
>
> You might be tempted to say that there's no way that a GC could happen
> during the execution of your foreign function call. That's probably
> true currently, but as OpenMCL moves to using preemptively scheduled
> native threads, it becomes impossible to make that assumption: a GC
> could occur (because of activity of another thread) on essentially any
> instruction boundary. There's therefore intentionally no (supported)
> way to pass the address of a lisp object to foreign code.
>
> There are a couple of approaches that would work in current and (near)
> future versions of OpenMCL:
>
> a) Copy the contents of the lisp vector of single floats to a C vector
> of single floats. Pass the C vector to foreign code; copy the C vector's
> contents back into the lisp vector after the foreign call returns.
>
> b) Allocate the lisp vector in the C heap; pass the (fixed) address of
> its first element to foreign code (which can then side-effect it directly.)
> "Manually" dispose of the lisp vector when you're through with it.
>
> Both of these appoaches are more awkward than simply passing the lisp
> object's address to foreign code would be; both of these approaches
> are GC-safe (and will continue to be), whereas pretending that the
> addresses of lisp objects are fixed would only be safe if it were
> true. It isn't. (Some months ago, I exchanged several email messages
> with someone who was trying to use CCL::%ADDRESS-OF in the simple,
> straightforward way in MCL, but found that it sometimes failed. It
> was several messages before we realized that the addresses in question
> and some other arguments in the call were bignums: the addresses of
> the lisp objects he was passing were changing before they even got
> to the foreign code.)
>
>
> > I am at a loss on how I do this in openmcl. So my questions are:
> >
> > 1) How do I call the foreign function?
> > a) (ccl::external-call "_cpgcurs"
> > (:* float) x
> > (:* float) y
> > (:* char) c
> > :int)
> > b) (ccl::external-call "_cpgcurs"
> > :address x
> > :address y
> > :address c
> > :int)
> >
> > 2) How do I obtain the memory address (or macptr) of a lisp object?
>
> The lisp printer uses CCL::%ADDDRESS-OF. It's best to think of the
> 32-bit address it returns as "a probably unique identifier which makes
> it easier to distinguish otherwise anonymous objects" rather than as
> something too closely related to the object's actual address.
>
> > Or is there some other way around this?
> >
>
> If you're interested, I'll try to explain (a) and (b) above in greater
> detail.
>
> > I am using openmcl 0.13 on Mac OS X 10.1.5.
> >
> > I hope I make myself clean and I would appreciate any help.
> >
> > Thanks,
> > Ronnie
> >
> >
> > P.S. I succeeded in calling a foreign function which had just a single
> > float as its argument (not an array) but was unable to modify this
> > to work with an array of floats:
> >
> > (defun func (x)
> > (rlet ((_x :float))
> > (setf (pref _x :float) x)
> > (ccl::external-call "_func"
> > (:* float) _x)
> > (pref _x :float)))
> >
>
> The idea with (a) is sort of an extension of this.
_______________________________________________
Openmcl-devel mailing list
Openmcl-devel at clozure.com
http://clozure.com/cgi-bin/mailman/listinfo/openmcl-devel
More information about the Openmcl-devel
mailing list