FFI, safe vs unsafe
Simon Marlow
simonmar at microsoft.com
Thu Mar 30 04:44:36 EST 2006
On 29 March 2006 16:53, John Meacham wrote:
> On Wed, Mar 29, 2006 at 04:11:56PM +0100, Simon Marlow wrote:
>> Ok, let's explore how difficult it really is.
>>
>> Take a single-threaded implementation that forks OS threads for
>> concurrent foreign calls. Let's call the OS thread running Haskell
>> code the "runtime thread". An OS thread wanting to call a foreign
>> export must make an RPC to the runtime thread. You could do this by:
>>
>> - have a channel for RPC requests
>>
>> - the callee creates a condition var for the result, and sends
>> the call details down the channel with the condition var.
>>
>> - the runtime thread picks up the request in its event loop and
>> forks a Haskell thread to handle it
>>
>> - when the Haskell thread completes it places the result in the
>> right place and signals the condition variable
>>
>> - the callee picks up the result, frees the resources and
>> continues on its merry way
>>
>> can't be more than a couple of days work, unless I'm missing
>> something? It's not particularly fast, but then call-ins in GHC
>> aren't fast either.
>
> still seems rather complicated for something that as far as I know has
> never come up as needed :) and given that, it is certainly
> unacceptable to pay that cost for every reentrant or blockable call
> on the off chance it might want to do both.
It's not just for callbacks: you need this working if you want to
support call-ins in a multi-threaded environment. That is, implementing
a library in Haskell with a C interface that can be called by multiple
OS threads.
For example, our Visual Studio plugin needed this to be working because
Visual Studio likes to call APIs in the plugin from different threads.
> Trading a single 'call' instruction for a condition variable, a rpc
> call, and some value passing and many memory accesess and potential
> SMP bus locks is more than just not particularly fast :)
>
> why are call-ins in ghc not very fast? with jhc they are just
> straight C function calls.
You're optimising for the single-threaded case, and that's fine. In
GHC, a call-in is similar to what I outlined above except that we can
optimise away the RPC and perform the call directly in the OS thread
that requested it, due to the way bound threads are implemented. Doing
that requires that a lot more of the runtime needs to be thread-safe,
though.
It's true that this is a fairly large overhead to impose on all Haskell
implementations. I'm coming around to the idea that requiring this is
too much, and perhaps multi-threaded call-ins should be an optional
extra (including concurrent/reentrant foreign calls).
Cheers,
Simon
More information about the Haskell-prime
mailing list