New Bound Threads Proposal
Wolfgang Thaller
wolfgang.thaller at gmx.net
Sat Apr 26 07:58:23 EDT 2003
> Shame on me to not have written a proposal yet, but I am still
> too busy with other stuff right now.
I understand that... I'll probably be too busy again in a little more
than a week...
> If you start with the prototype, I urge you to build it completely in
> Haskell;
I was not talking about a "simulator", I was talking about a first
draft of a working implementation for GHC. I would implement it in C,
because it would have to be part of the RTS. After all, it's part of
the scheduler, and the scheduler is already implemented in C.
> using the *minimal* amount of primitive operations required. Those
> operations
> will probably be:
> - fork a native thread
> - attach a haskell thread to a native thread
> - moving unbound threads to other native threads
> - getting the current threads and their mapping to native threads
Question: Do you want them as part of a "low-level" public interface,
i.e. should they be the same accross all Haskell implementations that
implement your proposal?
If so, that contradicts two of the goals I've started from:
(*) The specification shouldn’t explicitly require lightweight “green”
threads
to exist. The specification should be implementable in a simple and
obvious
way in haskell systems that always use a 1:1 correspondence between
Haskell threads and OS threads.
(*) The specification shouldn’t specify which particular OS thread
should be
used to execute Haskell code. It should be possible to implement it
with
e.g. a Haskell interpreter running in one OS thread that just uses
other
OS threads for foreign calls.
(These are the fourth and fifth points of section 2, "Requirements", of
the threads document)
This is why I oppose having these, or similar operations, as part of
any standard public interface.
Now if you mean using these primitives as an interface between the GHC
RTS and GHC-specific libraries... well at least I'm less opposed to it.
I think it's more work to expose all these primitives. These primitives
actually provide more features than we need (we don't need to
explicitly map unbound threads to native threads; a scheduler loop
running in an [unassociated] native thread can just execute any unbound
thread without much ado).
Also, it feels like splitting up the scheduler logic in half between
the RTS and the libraries. We don't we have primitive Haskell action
for "add to run queue", "remove from run queue" etc. so that we can
implement all the scheduling and MVars and so on in Haskell - so why
should we implement just this part of the scheduler in Haskell?
Thirdly, I fear that it would preclude several kinds of optimizations
that could be done within the scheduler (the proposal intentionally
leaves some things unspecified to provide room for optimizations).
> Secondly, try to remove the whole safe/unsafe/threadsafe business and
> make
> "safe" and "threadsafe" combinators too.
No ;-).
I don't think it's at all possible to implement the distinction between
unsafe and the others via a combinator, because unsafe is about things
that just have to be in the C language RTS.
In GHC, "unsafe" calls are compiled to just plain calls; "safe" and
"threadsafe" calls first do some cleanup of RTS structures that makes
sure that other (Haskell) threads or callbacks can run.
After this cleanup is performed (function suspendThread()), no Haskell
code can execute until resumeThread() is called. Therefore, it is
impossible to do this using a combinator.
So we're stuck with one optional specialid (not a keyword, "unsafe" is
still a legal variable name) in foreign import declarations. Also, it's
already widely used.
Now what about the distinction between "safe" and "threadsafe"?
_Maybe_ it's possible to implement "threadsafe" on top of "safe" and a
few primitives (though I still doubt it).
My position is to simply remove "safe" from the language altogether,
because:
*) It is poorly specified. There is no written document that specifies
what exactly should block when, or what is required to block and what
is just "allowed" to block.
*) Most "informal" specifications that require "safe" calls to block
other threads rely on specific details of present Haskell
implementations. Future implementations could, and are allowed to,
implement threading differently. Green threads are a feature of Haskell
implementations, not a feature of the Haskell language.
*) "safe" calls are dangerous. A "safe" call influences totally
unrelated parts of a program in hard-to-predict ways.
*) It seems to be relatively hard to actually achieve the performance
benefit of "safe" calls (which was the original reason for having the
distinction).
If we remove "safe" from the language (and, consequently, rename
"threadsafe" to "safe" and make it the default), we're left with only
the distinction between "unsafe" and "safe" foreign imports (which we
had from the start). If you don't specify anything, you get "safe"
(a.k.a. threadsafe), which is the version that automatically "does the
right thing". Unsafe foreign imports are provided as a performance
optimization only (and it's not possible to achieve that using a
combinator).
There would be no unnecessary keywords or language extensions left.
> Success,
> Daan.
Qapla',
Wolfgang
More information about the FFI
mailing list