FFI, safe vs unsafe
wolfgang.thaller at gmx.net
Wed Apr 12 23:37:57 EDT 2006
John Meacham wrote:
> However, in order to achieve that we would have to annotate the
> functions with whether they use thread local state.
I am not opposed to that; however, you might not like that here
again, there would be the safe, possibly inefficient default choice,
which means "might access thread local data", and the possibly more
efficient annotation that comes with a proof obligation, which says
"guaranteed not to access thread local data".
The main counterargument is that some libraries, like OpenGL require
many *fast* nonconcurrent, nonreentrant but tls-using calls (and,
nost likely, one reentrant and possibly concurrent call for the GLUT
main event loop). Using OpenGL would probably be infeasible from an
implementation which requires a "notls" annotation to make foreign
> it would pretty much
> be vital for implementing them efficiently on a non OS-threaded
> implemenation of the language.
True, with the implementation plan you've outlined so far.
Have you considered hybrid models where most threads are state
threads (all running in one OS thread) and a few threads (=the bound
threads) are OS threads which are prevented from actually executing
in parallel by a few well-placed locks and condition variables? You
could basically write an wrapper around the state threads and
pthreads libraries, and you'd get the best of both worlds. I feel it
wouldn't be that hard to implement, either.
> Oddly enough, depending on the implementation it might actually be
> easier to just make every 'threadlocal' function fully concurrent. you
> have already paid the cost of dealing with OS threads.
Depending on the implementation, yes. This is the case for the
inefficient implementation we recommended for interpreters like Hugs
in our bound threads paper; there, the implementation might be
constrained by the fact that Hugs implements cooperative threading in
Haskell using continuation passing in the IO monad; the interpreter
itself doesn't even really know about threads. For jhc, I fell that a
hybrid implementation would be better.
> they are a bonus in that you can't run concurrent computing haskell
> threads at the same time. you get "free" concurrent threads in other
> languages that you would not get if the libraries just happened to be
> implemented in haskell. However, if the libraries were implemented in
> haskell, you would still get concurrency on OS blocking events because
> the progress guarentee says so.
Hmm... it sounds like you've been assuming cooperative scheduling,
while I've been assuming preemptive scheduling (at least GHC-style
preemption, which only checks after x bytes of allocation). Maybe, in
a cooperative system, it is a little bit of a bonus, although I'd
still want it for practical reasons. I can make my Haskell
computations call yield, but how do I make a foreign library (whose
author will just say "Let them use threads") cooperate? In a
preemtive system, the ability to run a C computation in the
background remains a normal use case, not a bonus.
>> The question "can I provide a certain guarantee or not" could be
>> answered with "no" by default to flatten the learning curve a bit. My
>> objection against having "no default" is not very strong, but I do
>> object to specifying this "in neutral language". This situation does
>> not call for neutral language; rather, it has to be made clear that
>> one of the options comes with a proof obligation and the other only
>> with a performance penalty.
> you seem to be contradicting yourself, above you say a performance
> penalty is vitally important in the GUI case if a call takes too
> long, [...]
I am not. What I was talking about above was not performance, but
responsiveness; it's somewhat related to fairness in scheduling.
If a foreign call takes 10 microseconds instead of 10 nanoseconds,
that is a performance penalty that will matter in some circumstances,
and not in others (after all, people are writing real programs in
Python...). If a GUI does not respond to events for more than two
seconds, it is badly written. If the computer or the programming
language implementation are just too slow (performance) to achieve a
certain task in that time, the Right Thing To Do is to put up a
progress bar and keep processing screen update events while doing it,
or even do it entirely "in the background".
Of course, responsiveness is not an issue for non-interactive
processes, but for GUIs it is very important.
> Who is to say whether a app that
> muddles along is better or worse than one that is generally snappy but
> has an occasional delay.
I am ;-). Apart from that, I feel that is a false dichotomy, as even
a factor 1000 slowdown in foreign calls is no excuse to make a GUI
"generally muddle along".
> Though, I am a fan of neutral language in general. you can't crash the
> system like you can with unsafePerformIO, FFI calls that take a while
> and arn't already wrapped by the standard libraries are relatively
> no need for strong language.
To the end user, all unusable programs are equivalent :-). Also, one
decision can make a library unusable for interactive programs while
the other can't; the language should be strong enough to make that
clear to library writers who have never heard the words "state
threads" and who don't care much about concurrency in general.
As for your claim about the relative rarity of such calls, I see that
your bias is very different from mine. My world consists mostly of
console-based programs that compute something (compilers, etc.) and
don't need any FFI or concurrency to speak of, and of interactive
graphical applications (GUIs + games) for which the standard
libraries are only a tiny fragment of the FFI world. In your world,
network servers (or applications with a similar structure) seem to
figure more prominently.
More information about the Haskell-prime