FFI, safe vs unsafe

Claus Reinke claus.reinke at talk21.com
Wed Mar 29 09:58:47 EST 2006

>Malcolm correctly notes that when I say "non-blocking" I'm referring to
>the behaviour from Haskell's point of view, not a property of the
>foreign code being invoked.
>In fact, whether the foreign code being invoked blocks or not is largely
>immaterial.  The property we want to capture is just this:
>  During execution of the foreign call, other Haskell threads
>  should make progress as usual.

if that is really what you want to capture, the standard terminology 
would be "asynchronous call" (as opposed to "synchronous call"). 
hence all that separation between synchronous and asynchronous 
concurrent languages (so "concurrent" would not be a useful qualifier).

the only remaining ambiguity would be that concurrent languages
(eg, Erlang) tend to use "asynchronous calls" to mean that the 
_calling thread_ does not need to synchronise, whereas you 
want to express that the _calling RTS_ does not need to 
synchronise while the _calling thread_ does need to. 

which makes me wonder why one would ever want the RTS to 
block if one of its threads makes a call? if the RTS is sequential 
(with or without user-level threads), it can't do anything but 
synchronous foreign calls, can it? and if the RTS does support 
non-sequential execution, I can see few reasons for it to block 
other threads when one thread makes a foreign call.

I think what you're after is something quite different: by default,
we don't know anything about the behaviour of foreign call, so
once we pass control to foreign, it is out of our hands until
foreign decides to return it to us. 

for sequential RTS, that's the way it is, no way around it. for 
non-sequential RTS, that need not be a problem: if the foreign 
call can be given its own asynchronous (OS-level) thread of 
control, it can take however long it needs to before returning, 
and other (user-level) threads can continue to run, 
asynchronously. but that means overhead that may not 
always be necessary.

so what I think you're trying to specify is whether it is safe for
the RTS to assume that the foreign call is just another primitive
RTS execution step (it will return control, and it won't take long
before doing so). the standard terminology for that is, I believe,
"atomic action".

in other words, if the programmer assures the RTS that a foreign
call is "atomic", the RTS is free to treat it as any other RTS step
(it won't block the current OS-level thread of control entirely, 
and it won't hog the thread for long enough to upset scheduling
guarantees). if, on the other hand, a foreign call is not annotated
as "atomic", there is a potential problem: non-sequential RTS
can work around that, with some overhead, while sequential
RTS can at best issue a warning and hope for the best.

so my suggestion would be to make no assumption about
unannotated calls (don't rely on the programmer too much;),
and to have optional keywords "atomic" and "non-reentrant".

[one might assume that an "atomic" call should never be 
 permitted to reenter, so the annotations could be ordered
 instead of accumulated, but such assumptions tend to
 have exceptions]


>It doesn't matter whether the foreign call "blocks" or not (although
>that is a common use for this feature).  I'd rather call it
>'concurrent', to indicate that the foreign call runs concurrently with
>other Haskell threads.

More information about the Haskell-prime mailing list