[Third attempt (I'll get it right at some point!), to post
this to the list; I am sorry if it results in any duplication
of the post.] 

Simon Peyton-Jones <[EMAIL PROTECTED]> wrote,

> > 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?
> 
[...]
>
> Our proposed solution is this:
>       Have lots of OS "worker threads", plus an OS lock for the
>       entire heap and scheduler data structures.
> 
>       Each worker thread tries to get the lock, at which point
>       it busily executes all the Concurrent Haskell threads in 
>       the heap
> 
>       Before a potentially-blocking FFI call, the worker tidies
>       things up and releases the lock. Then it makes the call,
>       and re-acquires the lock.  If the I/O call doesn't block,
>       it may get the lock back before any of the other worker
>       threads get it.
> 
>       If the I/O call does block, another worker thread gets the
>       lock, and executes Concurrent Haskell threads.
> 
>       Maybe there ought to be some way for the returning OS thread
>       to ask the current worker to back off, so that it's not
>       shut out indefinitely.

I like to make some conceptual comments first.  I think,
also referring to SimonM's comments, that the interface
should distinguish the two goals

(1) making FFI calls that may re-enter Haskell land and
(2) dealing with the interaction of blocking I/O with
    threads. 

This is not only convenient for writing bindings to
non-thread-safe libraries, but also because, I think, it is
VERY important for the language that Haskell gets a
*standard* FFI.  The GHC/Hugs interface is IMHO a very good
attempt at this, but to be able to propose it for inclusion
into the standard, the FFI (and thus, bindings written ontop
of it) should be independent of the presence of threads in
the RTS.

Changing the semantics of the "safe" call from the currently 
implemented to the specified behaviour would mingle the
above two goals.

> Of course, this solution does indeed require libraries to be 
> thread safe.
> 
> I know of no way to support
>       a) non-thread-safe libraries
>       b) I/O calls that can block without freezing the entire
>          Concurrent Haskell program.

Therefore, I propose to have three kinds of FFI calls:

  unsafe    - as before
  safe      - as currently implemented
  supersafe - (or call it "threadsafe" or "blocksafe")
              the solution you described above

I think, the trouble of having to deal with three kinds of
calls is worthwhile as

(a) "unsafe" and "safe" can be part of a standard FFI;
    "supersafe" is only added by implementations that also
    support multi-threading;
(b) bindings to non-thread-safe libraries can use "unsafe"
    and "safe"; in a multi-threaded RTS, they are, so to
    speak, included into the lock that protects the Haskell
    heap etc; and
(c) if a programmer knows that a call cannot block, but may
    re-enter the Haskell scheduler, "safe" provides a faster 
    way of doing the call.

Please don't underestimate the impact of (c), in the GTK+
binding, for example, a big number of frequently made calls
have to be "safe", because they may trigger callbacks.  But
in fact, most of the time, they actually don't execute a
call back and often require rather little work on the GTK+
side; so, I am a bit concerned about efficiency here.

Xavier's comment,

> You can safely call non-thread safe libraries by simply not releasing
> the global lock during the foreign call.  Of course, all threads will
> be frozen during the call, but for foreign functions that don't do
> I/O, it's a reasonable alternative.

also boils down to having a third form of call, I guess.

Manuel

Reply via email to