Dear GHC Gurus ;-)

Michael Hobbs <[EMAIL PROTECTED]> and I were just discussing
the use of GHC's threads (ie, the `Concurrent' library)
within GTK+ applications when we came across an
inconsistency between ``The STG runtime system (revised)''
and the actual implementation of the RTS in GHC 4.02.  The
specification says in Section 4.6 (about "safe" and "unsafe"
C calls) that in case of a "safe" call, a new OS thread is
spawned to execute the called C code - I also remember Simon
(PJ) mentioning something similar at last years IFL.
However, on inspection of the actual implementation, we
couldn't find any use of OS threads.  Maybe this is just a
matter of the implementation being behind the specification,
but in would be interesting to know how things are expected
to develop.

This is interesting because GTK+ is not thread-safe (as far
as I know, partially because X is not thread-safe and GTK+
makes no attempt at guarding its X calls against re-entry).[1]
However, as long as GHC's RTS *does not* spawn an OS thread
for safe FFI calls, there is not problem, because GHC's
scheduler does not really interrupt Haskell threads, but
just asks them to yield by setting a flag (and this can
barely interrupt GTK+).

If the RTS, however, starts to use OS threads for safe FFI
calls, GTK+ may end up in a different thread as the Haskell
scheduler, which in turn may run Haskell threads that again
call GTK+, thus causing disaster.  One way to prevent such
disaster (without assigning all GTK+ interaction of an
application to a dedicated thread) would be to have some new
synchronization primitives in the RTS (and the required API
in `Concurrent').  For example, to know when all threads
created by a callback have finished.

The required synchronization could of course be programmed
using `Concurrent's semaphores, but with the disadvantage
that if we want to provide this thread-safety transparently
for user applications in a library, we have to define a
"new" IO monad on top of the standard one (to thread the
reference to the semaphore to all library calls).  As a
consequence, all standard IO operations would have to be
lifted to the new IO monad.[2]

Finally, I am wondering how big the performance impact of
using a separate IO thread per safe FFI call is.  For
example, in the GTK+ binding I often cannot use unsafe
calls, because the calls can trigger callbacks (ie, may
reenter Haskell), but I know that they cannot block.  On the
other hand, the usage of OS threads is nice when calling an
external routine that can block.  The question, however, is
whether we want to pay for an OS thread each time a call can
potentially re-enter the Haskell scheduler.  Preforking
OS threads can make things more efficient, but I am still not
sure whether it wouldn't be a serious overhead.  Maybe we
need three types of calls: unsafe, safe, and supersafe ;-)

Let's summarize the questions:

* Will safe FFI calls eventually be executed by extra OS
  threads? 
* Would you support additional synchronization primitives in
  the RTS (and `Concurrent') to support making the use of
  libraries like GTK+ thread-safe?
* How about three kinds of FFI calls?

Cheers,

Manuel

[1] GTK+ 1.2 has some mechanisms to support writing
    multi-threaded applications, but it requires some care
    by the programmer.
[2] Apart from extending the RTS and defining a new IO
    monad, there are some other rather ugly solutions, like
    storing the reference to the semaphore in C land via the 
    FFI.

Reply via email to