FFI, safe vs unsafe

John Meacham john at repetae.net
Fri Mar 31 16:44:23 EST 2006

On Fri, Mar 31, 2006 at 03:16:50PM -0500, Wolfgang Thaller wrote:
> So I'm going to ask a few questions about the semantics of non- 
> concurrent reentrant calls, and if people can provide answers that  
> don't scare me, I'll concede that they have a place in the language  
> standard.

first of all, a quick note, for GHC, the answers will be "the same thing
it does now with -threaded". but I will try to answer with what a simple
cooperative system would do.

> 1.) Assume thread A and B are running. Thread A makes a non- 
> concurrent, reentrant call to Foreign Lands. The foreign function  
> calls a foreign-exported Haskell function 'foo'.
> While 'foo' is executing, does thread B resume running?

if 'foo' blocks on a mvar,read,write,etc... then yes.

> 2.) Assume the same situation as in 1, and assume that the answer to  
> 1 is yes. While 'foo' is running, (Haskell) thread B makes a non- 
> concurrent, reentrant foreign call. The foreign function calls back  
> to the foreign-exported Haskell function 'bar'. Because the answer to  
> 1 was yes, 'foo' will resume executing concurrently with 'bar'.
> If 'foo' finishes executing before 'bar' does, what will happen?

I am confused, why would anything in particular need to happen at all?

the threads are completly independent.  The non-concurrent calls could
just be haskell code that happens to not contain any pre-emption points
for all it cares. in particular, in jhc, non-concurrent foreign imports
and exports are just C function calls. no boilerplate at all in either
direction.  calling an imported foreign function is no different than
calling one written in haskell so the fact that threads A and B are
calling foregin functions doesn't really change anything.

> 3.) Same situation as in 1. When 'foo' is called, it forks (using  
> forkIO) a Haskell thread C. How many threads are running now?

3 potentially runable.

> 4.) Should there be any guarantee about (Haskell) threads not making  
> any progress while another (Haskell) thread is executing a non- 
> concurrent call?

I don't understand why we would need that at all.

> Two more questions, not related to semantics:
> 5.) Assume that Haskell Programmer A writes a Haskell library that  
> uses some foreign code with callbacks, like for example, the GLU  
> Tesselator (comes with OpenGL), or, as a toy example, the C Standard  
> Library's qsort function. Should Programmer A specify "concurrent  
> reentrant" on his foreign import?
> Programmer B will say "please don't", as he wants to use a Haskell  
> implementation which doesn't support "concurrent reentrant".  
> Programmer C will say "please do", as he wants his application's GUI  
> to stay responsive while the library code is executing. So what  
> should the poor library programmer A do?

He should say just 'reentrant' since concurrent isn't needed for
correctness because the tessalation routines are basic calculations and
will return.

However, on a system like GHC that actually can run code concurrently
and actually would have issues enforcing a 'non-concurrent' guarentee it
would run concurrently anyway. It would be hard not to on an
implementation that supported true OS threads actually.

everyone wins. in the absolute worst case there are always #ifdefs but I
doubt they will be needed.

> 6.) Why do people consider it too hard to do interthread messaging  
> for handling a "foreign export" from arbitrary OS threads, when they  
> already agree to spend the same effort on interthread messaging for  
> handling a "foreign import concurrent"? Are there any problems that I  
> am not aware of?

it is not that it is hard (well it is sort of), it is just absurdly
inefficient and you would have no choice but to pay that price for
_every_ foregin export. even when not needed which it mostly won't be.
the cost of a foreign export should be a simple 'call' instruction
(potentially) when an implementation supports that.  

the cost of a foreign import concurrent nonreentrant is only paid when
actually using such a function, and quite cheap. on linux at least, a
single futex, a cached pthread and it gets rolled into the main event
loop. so a couple system calls max overhead.


John Meacham - ⑆repetae.net⑆john⑈

More information about the Haskell-prime mailing list