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

Michael Klingbeil michael at klingbeil.com
Thu Nov 21 10:26:58 PST 2002


I have been using code that uses ccl:%vect-data-to-macptr and it 
seems to work. No copying required. But as Gary points out this is 
dangerous, particularly once OpenMCL moves to preemptive threads. 
Originally the code was run on MCL Classic where preemption really 
wasn't an issue. However, I did try re-calling the MCL scheduler from 
C code to get some kind of concurrency happening. Most of the time 
this works, but I did experience a couple of crashes (heap 
corruption) which could very well have been due to an address moving 
during GC. All of this is under MCL on MacOS 9, but I guess the 
issues are similar whenever a foreign call in progress is preempted.

But if you just want something quick and dirty, try it!

Michael


>  > 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


_______________________________________________
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