RE: FFI, safe vs unsafe

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

On Thu, Mar 30, 2006 at 10:44:36AM +0100, Simon Marlow wrote:
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.
yeah, if you actually have a OS threaded RTS, then everything is a whole different ball of wax. But there is a lot to be said for a state-threaded version like hugs. Even in C-land many people choose state-threads over posix threads or vice versa depending on many criteria and we shouldn't assume that one is necessarily superior. state-threads arn't second class, just a different way to go. Although I was skeptical at the beginning that we could come up with a standard based on forkIO that could encompass both models without compromising performance or implementation flexability, I now think that we can! and that is good, because it means we won't need to make concurrency an addendum or just accept the fact that many haskell-prime implementations will be incomplete! mainly, I think we need to keep a couple goals in mind, which are sometimes in opposition, but not really so much: * not require anything that will rule out or arbitrarily reduce the efficiency of a absolutely-zero-overhead in the non-concurrent case implementation of straightforward state-threads. * not require anything that will inhibit the SMP scalability or scheduling freedom of OS threaded implementations. I think if we stick to these 'caps' at both ends then all the intermediate implementations we have talked about will be accomodated and since state-threads can _almost_ be implemented in pure haskell, we can be pretty sure we arn't constraining future as yet to be thought of implementation models too much. A sticky point might be whether we say anything about duplicated work, however, the haskell report never really says anything about guarenteed sharing anyway so we can probably be silent on the matter. we certainly shouldn't treat state-threads as second class or a "lesser" implementation of the standard though! they can often be faster than OS threads but with their own set of tradeoffs. glossary: OS threaded - ghc -threaded, context switching at arbitrary points, not necessarily under the control of the haskell runtime. state-threading - hugs,jhc context switching at block-points chosen by the implementation and user via yield. yhc is somewhere in between. basically state-threading, but with more context switching under the control of the yhc run-time.
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).
yeah, a much touted feature of haskell concurrency is that it is _fast_ _fast_, we shouldn't compromise that or its potential without very good reason. John -- John Meacham - ⑆repetae.net⑆john⑈
participants (2)
-
John Meacham
-
Simon Marlow