[Openmcl-devel] Calling foreign function with float array as argument?

Ronnie Hoogerwerf ronnieh at head-cfa.harvard.edu
Thu Nov 21 17:23:50 UTC 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