[gambit-list] os_dyn

Marc Feeley feeley at iro.umontreal.ca
Thu Oct 8 10:32:11 EDT 2009


On 2009-10-08, at 9:13 AM, Michele Zaffalon wrote:

>>> Is this the only way to have a Scheme defined function passed on the
>>> fly to C? Short of using global variables as in here
>>>
>>> https://mercure.iro.umontreal.ca/pipermail/gambit-list/2009-January/002939.html
>>
>> Well, the only solutions I find acceptable.  There might be some  
>> (more or
>> less portable) library to implement C closures that could be used  
>> (libffi?).
>>  You have to understand what the fundamental problem is.  In C,  
>> functions
>> pointers are implemented (usually) as the address of the code which
>> implements the function.  The C compiler generates a "call"  
>> instruction to
>> that address.  Scheme closures carry with them an environment...  
>> that is
>> what makes them more useful than plain functions.  So to convert a  
>> Scheme
>> closure to a C function pointer, in general it is necessary to  
>> allocate a
>> fresh code address that will correspond to the Scheme closure.  The
>> technique shown in the message linked above is based on the idea of
>> allocating at compile time a pool of C functions, and then to  
>> assign them on
>> demand to Scheme closures.  It is 100% portable, but it places a  
>> static
>> limit on the number of Scheme closures that can be converted (the  
>> code could
>> be improved to un-assign the Scheme closure when it is no longer  
>> live using
>> wills for example).  The other solution, based on dynamic code  
>> generation,
>> does not place a limit on the number of converted Scheme closures,  
>> but it is
>> not portable (it is CPU and OS dependent).  There is no portable  
>> solution I
>> know of that solves both issues (portable here means it respects  
>> the C
>> standard and only relies on the C standard).
>>
>> Marc
>
> I don't understand: in
>
> (c-define (helper-func x)
> 	  (int) int "helper_func" ""
> 	  (*f* x))
>
> (define gsl-func
>  (c-lambda (int) int "gsl_func"))
>
> and helper_func is called by the gsl_func routine, *f* can be any
> Scheme closure.
> Then why can't the C interface accept
>
> (define gsl-func2
>  (c-lambda ( (function (int) int) int) int "gsl_func"))
>
> and generate the correct helper-func with *f* replaced by whatever
> function is passed to gsl-func2?

The user is free to do that in his/her code (that is what the code at  
the above link does).  So I assume you mean "why doesn't the C  
interface do this automatically for the user?".

Here are a few problems that come to mind:

1) This approach is not thread-safe.  If two threads concurrently call  
gsl-func2 with different closures, then they will clobber the value of  
*f* that the other thread is using.

2) Even if threads are not used, imagine the case where the C code is  
receiving the function and storing it away for later use in a table  
(for example the function is a callback attached to a particular  
event, say the mouse is moved, or a key is typed on the keyboard,  
etc).  With your approach there is a single *f* which is shared by all  
the callbacks you install.  Which means that they are not  
independent.  In fact, whichever callback is called, the most recently  
installed callback will be called (because that is what *f* will  
contain).

In other words, the fundamental problem here is that all closures must  
be independent, so they cannot share state.  That's why the decision  
to use this approach must be in the hands of the user.  The system  
can't do this automatically.

The two solutions I explained previously solve the sharing problem,  
with different caveats.

Marc




More information about the Gambit-list mailing list