Re: Native Threads in the RTS
I've been watching the discussion about native threads, and getting thoroughly confused. Understandable ;-) . But before investing effort in fiddling with it, I thought it'd be good to see whether anyone finds it helpful. Yes, it does seem to be a good idea. Feel free to modify it. E.g. add inline comments, alternative rules, and whatever. OK, I'll get to work :-) Cheers, Wolfgang ___ Glasgow-haskell-users mailing list [EMAIL PROTECTED] http://www.haskell.org/mailman/listinfo/glasgow-haskell-users
RE: Native Threads in the RTS
| I've postponed writing up a new proposal again... | | But I'm going to sum up some requirements that I would like to see | fulfilled - to make it clearer to others why I'm proposing such strange | things... I've been watching the discussion about native threads, and getting thoroughly confused. In an attempt to get a handle on what is going on, I have (with Simon M) written a sort of operational semantics for Concurrent Haskell with foreign threads, that attempts to abstract away from everything except the issues that gave rise to these thread proposals. You can find the document in haskell-report/ffi/threads.tex. The style files are in haskell-report/styles/*.sty. There's a Makefile in haskell-report/ffi. It's very much a first cut, and it would clearly be good to merge the threads.txt document with this new Latex one, and in the end have a final spec. But before investing effort in fiddling with it, I thought it'd be good to see whether anyone finds it helpful. It's almost certainly inconsistent in minor ways, and may need adjustment to accurately reflect the proposals on the table, but I hope it may help to make the debate more precise. Feel free to modify it. E.g. add inline comments, alternative rules, and whatever. Simon | ___ Glasgow-haskell-users mailing list [EMAIL PROTECTED] http://www.haskell.org/mailman/listinfo/glasgow-haskell-users
Re: Native Threads in the RTS
Dean Herrington wrote: [...] Rather, I find it nonintuitive that calling from Haskell to foreign code and back into Haskell should create a new Haskell thread, when these two Haskell threads really are just different portions of a single "thread of computation" (deliberately vague term). I agree to that. Creating a new thread for calling back into Haskell _only_ makes sense if you look at it from inside the GHC RTS. Before I had a look at the relevant parts of the RTS, I would never have thought of that. I don't know if there's any advantage/disadvantage to changing GHC's internals. The only _observable_ difference is the thread's ThreadIds, and this should at least be clearly documented (or, even better, it should be "explicitly undocumented", so that no one will be suprised if the behaviour is changed in the future). Off the top of my head I can think of two situations in which having separate threads is bothersome. 3. Throwing exceptions to a thread If I manually translate haskell exceptions to foreign exceptions and back, there is no reason why I shouldn't want to raise an exception in a thread I have a threadId for, even if that thread called a foreign function which in turn called back to haskell. I think that the behaviour can always be emulated using MVars however, so I think there's no immediate action required. --- I've tried to rephrase my proposal for native threads, this time treating GHC's behaviour in this situation as an implementation detail. I think the meaning of the proposal becomes clearer because of this. The proposal doesn't comment on ThreadIds, so the non-intuitive (IMHO) behaviour in GHC is independent of the "bound threads" proposal. I think I've understood both my own specification and the current RTS well enough to start trying to implement a prototype soon. The intended meaning of the specification hasn't changed for the third revision in a row. Does anyone have concrete suggestions for the syntax change to foreign export and foreign import "wrapper"? Cheers, Wolfgang = Bound Threads Proposal, version 5 Goals ~ Since foreign libraries sometimes exploit thread local state, it is necessary to provide some control over which thread is used to execute foreign code. In particular, it is important that it should be possible for Haskell code to arrange that a sequence of calls to a given library are performed by the same native thread and that if an external library calls into Haskell, then any outgoing calls from Haskell are performed by the same native thread. This specification is intended to be implementable both by multithreaded Haskell implementations and by single-threaded implementations and so it does not comment on which particular OS thread is used to execute Haskell code. Definitions ~~~ A native thread is a thread as defined by the operating system. A "Haskell thread" encapsulates the execution of a Haskell I/O action. A Haskell thread is created by forkIO, and dies when the I/O action completes. When a Haskell thread calls a foreign imported function, it is not considered to be blocked (in the GHC runtime system, the calling thread is blocked; This is considered an implementation detail for the purposes of this specification, but be aware that myThreadId might return several different values for one "Haskell thread" as defined here). If the foreign function calls back to Haskell, the callback is said to run in the same Haskell thread. Design ~~ Haskell threads may be associated at thread creation time with either zero or one native threads. Each Native thread is associated with at most one Haskell thread. A native thread that is associated with a Haskell thread is called a bound Haskell thread. A Haskell thread that is associated with a native thread is called a bound native thread. A Haskell thread is always executed by a native thread. This specification places absolutely no restrictions on which native thread is used to execute a particular Haskell thread. The Haskell thread need not be associated with the native thread used to execute it, and one Haskell thread may be executed by more than one native thread during its lifetime [but not by several native threads at once]. A bound native thread may not be used for executing any Haskell thread except the one it is bound to. It is implementation dependent whether the main thread, threads created using forkIO and threads created for running finalizers or signal handlers are bound or not. When a foreign imported function is invoked [by Haskell code], the foreign code is executed in the native thread associated with the current Haskell thread, if an association exists. If the current Haskell thread is not associated to a native thread, the implementation may decide which native thread to run the foreign function in. The native thread that is used may not be bound to another Haskell thread. The existing distinc
RE: Native Threads in the RTS
> 2. It seems perfectly reasonable to want to have the Haskell > called-back code throw an exception that is caught by the Haskell code > that called out to foreign code. "Reusing" the Haskell thread is > necessary (though not sufficient) to achieve such behavior. This is a particularly tricky problem, and I prefer to leave it up to the programmer to handle such things. Propagating the exception to the original (Haskell) caller automatically is unlikely to be the right thing to do, because the foreign code will almost certainly want to do some clean up. If the foreign language supports exceptions then it is conceivable that we could turn a Haskell exception into a foreign exception (and vice-versa), but for plain C I think we should leave well alone. Cheers, Simon ___ Glasgow-haskell-users mailing list [EMAIL PROTECTED] http://www.haskell.org/mailman/listinfo/glasgow-haskell-users
Re: Native Threads in the RTS
I've postponed writing up a new proposal again... But I'm going to sum up some requirements that I would like to see fulfilled - to make it clearer to others why I'm proposing such strange things... *) It should be possible for Haskell code to arrange that a sequence of calls to a given library are performed by the same native thread and that if an external library calls into Haskell, then any outgoing calls from Haskell are performed by the same native thread. *) The specification should be implementable in a way that allows a lot of foreign calls to be made with no additional overhead with respect to GHC's current "unsafe" foreign calls. *) The good performance of the existing lightweight "green" threads in GHC should not be sacrificed. Performance should still OK when using the new features with only a few threads (i.e. not more than commonly used from multithreaded C programs). *) 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. *) There should be no unexpected blocking. Especially, threadsafe calls should never cause other threads to block. I'm currently stuck thinking about one particular problem that I discovered in my current version of the spec. What happens when an unbound Haskell thread calls a threadsafe foreign function which in turn calls a bound foreign exported function? Well, I think my current proposal says relatively clearly what's supposed to happen, but I discovered it's not as easy to fit that in the current implementation of GHC as I thought... in fact it might be quite difficult. I'll have to do more thinking before I can be sure, though. That's it for today, Regards, Wolfgang ___ Glasgow-haskell-users mailing list [EMAIL PROTECTED] http://www.haskell.org/mailman/listinfo/glasgow-haskell-users
Re: Native Threads in the RTS
Simon Marlow wrote: > > | 2. Calling from foreign code into Haskell to a bound foreign import > > will > > | require some special handling to ensure that a subsequent > > call out to > > | foreign code will use the same native thread. Why couldn't this > > special > > | handling select the same Haskell thread instead of creating > > a new one? > > > > This is just an efficiency issue, right? If creating a > > Haskell thread > > from scratch is very cheap, then it's easier to do that each > > time rather > > than to try to find the carcass of a completed Haskell > > thread. If you > > do the latter, you need to get into carcass management. > > > > But maybe there is more to it than efficiency in your mind? > > To recap, the suggestion was that a Haskell thread which makes a foreign > call, which is turn calls back into Haskell, should use the same Haskell > thread for the callback. So the Haskell thread is not a carcass, it is > still running, but blocked waiting for the result of the foreign call. Yes, exactly. > I'm not sure I've quite got my head around all the implications of doing > this, but it sounds possible. However, I'm not completely convinced > it's desirable: the gain seems to be in efficiency only, and a fairly > small one (creating threads is quite cheap). I imagine you could > demonstrate a performance gain by doing this for an application which > does a lot of callbacks, though. My concern is not for efficiency. (In fact, I assumed the efficiency to be better with the current scheme because it was preferred to the (to me) more natural scheme. In any case, it appears any difference in efficiency--either way--is likely not to be large.) Rather, I find it nonintuitive that calling from Haskell to foreign code and back into Haskell should create a new Haskell thread, when these two Haskell threads really are just different portions of a single "thread of computation" (deliberately vague term). Off the top of my head I can think of two situations in which having separate threads is bothersome. 1. Consider a computation that requires Haskell-side per-thread state and associates it with a thread via the thread's ThreadId. Then some handle to this state currently needs to be passed out to foreign code and then back into Haskell. (This passage could be achieved explicitly as arguments in the call-out and callback, or implicitly in the closure representing the callback.) It is unfortunate that mere inclusion of a foreign call in such a chain of calls necessitates such additional complexity in per-thread state maintenance. 2. It seems perfectly reasonable to want to have the Haskell called-back code throw an exception that is caught by the Haskell code that called out to foreign code. "Reusing" the Haskell thread is necessary (though not sufficient) to achieve such behavior. > The current situation has the advantage of simplicity: > > * for each 'foreign export' we create a single Haskell thread which > lives until completion of the IO action. We can consider a > standalone > program as a call to 'foreign export main :: IO a' from a simple C > wrapper (in fact, that's almost exactly how it works). Dean ___ Glasgow-haskell-users mailing list [EMAIL PROTECTED] http://www.haskell.org/mailman/listinfo/glasgow-haskell-users
RE: Native Threads in the RTS
> | 2. Calling from foreign code into Haskell to a bound foreign import > will > | require some special handling to ensure that a subsequent > call out to > | foreign code will use the same native thread. Why couldn't this > special > | handling select the same Haskell thread instead of creating > a new one? > > This is just an efficiency issue, right? If creating a > Haskell thread > from scratch is very cheap, then it's easier to do that each > time rather > than to try to find the carcass of a completed Haskell > thread. If you > do the latter, you need to get into carcass management. > > But maybe there is more to it than efficiency in your mind? To recap, the suggestion was that a Haskell thread which makes a foreign call, which is turn calls back into Haskell, should use the same Haskell thread for the callback. So the Haskell thread is not a carcass, it is still running, but blocked waiting for the result of the foreign call. I'm not sure I've quite got my head around all the implications of doing this, but it sounds possible. However, I'm not completely convinced it's desirable: the gain seems to be in efficiency only, and a fairly small one (creating threads is quite cheap). I imagine you could demonstrate a performance gain by doing this for an application which does a lot of callbacks, though. The current situation has the advantage of simplicity: * for each 'foreign export' we create a single Haskell thread which lives until completion of the IO action. We can consider a standalone program as a call to 'foreign export main :: IO a' from a simple C wrapper (in fact, that's almost exactly how it works). Cheers, Simon ___ Glasgow-haskell-users mailing list [EMAIL PROTECTED] http://www.haskell.org/mailman/listinfo/glasgow-haskell-users
RE: Native Threads in the RTS
| 2. Calling from foreign code into Haskell to a bound foreign import will | require some special handling to ensure that a subsequent call out to | foreign code will use the same native thread. Why couldn't this special | handling select the same Haskell thread instead of creating a new one? This is just an efficiency issue, right? If creating a Haskell thread from scratch is very cheap, then it's easier to do that each time rather than to try to find the carcass of a completed Haskell thread. If you do the latter, you need to get into carcass management. But maybe there is more to it than efficiency in your mind? Simon ___ Glasgow-haskell-users mailing list [EMAIL PROTECTED] http://www.haskell.org/mailman/listinfo/glasgow-haskell-users
Re: Native Threads in the RTS
On 29 Nov 2002, Alastair Reid wrote: > Consider Haskell functions a,b,c,d and C functions A,B,C,D and a call > pattern > > a -> A -> b -> B -> c -> C -> d -> D > > That is, a calls A, calls b, calls B, calls ... > > Suppose we want A,B,C,D executed by the same foreign thread. > > Each of a,b,c,d are executed by different Haskell threads (because a > new Haskell thread is spawned for each call into Haskell) so we have > multiple Haskell threads associated with a single foreign thread. It doesn't feel right to me that a,b,c,d are executed by different Haskell threads. Why shouldn't they all be the *same* Haskell thread? 1. Reasonable exception handling across the Haskell/foreign boundary is not currently supported, but if we imagine moving in that direction, it would seem we'd want a single thread for the given example. 2. Calling from foreign code into Haskell to a bound foreign import will require some special handling to ensure that a subsequent call out to foreign code will use the same native thread. Why couldn't this special handling select the same Haskell thread instead of creating a new one? Dean ___ Glasgow-haskell-users mailing list [EMAIL PROTECTED] http://www.haskell.org/mailman/listinfo/glasgow-haskell-users
Re: Native Threads in the RTS
So, we can say that foreign functions of the form: foreign import bound unsafe bar :: ... are illegal or we can allow them and provide warnings or we can allow them and trust the programmer to know that bar is much more expensive than they think. (I favour the first two.) NOOO! Don't do that! Please don't! I see two potential problems with this (but would like to hear which, if either, dominates your thoughts): 1) If foreign threads cannot be used to execute Haskell code, foreign calls require (OS-level) context switches which are expensive. 2) Adding an implicit lock to foreign calls might surprise programmers. I'm slightly concerned about 2), but 1) Is an absolute show-stopper for me. It should stay possible to implement an unsafe call as just a call - no special RTS management, no context switches, no nothing, just a few machine code instructions to move the parameters to the stack and/or registers. And I definitely do want to keep that efficiency for "bound" Haskell threads. The reason why I startet this discussion is that I want to use OpenGL in my Haskell Programs (which works fine with GHC's current non-threaded RTS). OpenGL requires a lot of calls to functions that don't take much time to execute and that don't call back to haskell land. Using "safe" or even "threadsafe" for these calls would kill performance utterly and completely. *) Exactly one Haskell thread associated with the native thread is executing. All other associated Haskell threads are blocked. No foreign code is being executed by the native thread. This isn't quite right - or, at least, needs clarified. Consider Haskell functions a,b,c,d and C functions A,B,C,D and a call pattern a -> A -> b -> B -> c -> C -> d -> D That is, a calls A, calls b, calls B, calls ... Suppose we want A,B,C,D executed by the same foreign thread. [...] I think the quoted text assumes that a,b,c,d are blocked during the call to D. Yes. For the purpose of the above paragraph (and the neighboring paragraphs in the spec), a Haskell thread is considered "blocked" during a call to a foreign imported function. I admit that this terminology is inspired by implementation details of GHC, but it makes [some] sense: After all, if there is no Haskell code to execute [it's foreign code only now], the Haskell thread can not be executed. A Haskell thread can be either blocked or executing Haskell code. This needs careful interpretation if we want to be able to bind finalizers to foreign threads. In particular, if a finalizer is bound to a foreign thread, we don't increment 'bindees(f)' until the finalizer starts and we don't start the finalizer unless either: I'm not currently planning to allow finalizers to be bound to native(foreign) threads, as I have so far failed to see a solution that I'm happy with. [...] From an implementation point of view, this requires: 1) That foreign threads are _not_ used to execute Haskell code. One of my design goals is to allow the native threads to be used to execute Haskell code. Implementations are not required to do so, but it should be possible. For that reason I also dislike the term "foreign thread". It sounds great until I want to say "the implementation may use the foreign thread to execute Haskell code". And just as I went back to the computer after a long pause in order to finish this message, a new proposal arrived. I'll take more time to study it more completely. I just want to reiterate one thing: The notion of bound foreign imports could be eliminated by saying that all foreign calls are performed by the bound thread if one exists and eliminate the concept of 'bound foreign imports'. The only reason to allow any flexibility is to allow for faster implementations which perform less context switching - this is especially important for 'unsafe' foreign calls. I definitely need zero-overhead bound unsafe calls. Everything else would be basically unusable for me. I'll be back later. Cheers, Wolfgang ___ Glasgow-haskell-users mailing list [EMAIL PROTECTED] http://www.haskell.org/mailman/listinfo/glasgow-haskell-users
RE: Native Threads in the RTS
> > This is all getting highly confusing, as it seems we're working with > > different ideas of what's on the table. Alastair: you seem to be > > working on your own proposal - could you write it down either as a > > complete proposal or diffs to Wolfgangs? > > I did. You sent comments on it and I sent back a cleaned up version. > Here it is again. My apologies - I didn't notice you'd already proposed 'foreign import bound' so I thought you were working with a definition that we hadn't seen. Never mind. Cheers, Simon ___ Glasgow-haskell-users mailing list [EMAIL PROTECTED] http://www.haskell.org/mailman/listinfo/glasgow-haskell-users
Re: Native Threads in the RTS
> This is all getting highly confusing, as it seems we're working with > different ideas of what's on the table. Alastair: you seem to be > working on your own proposal - could you write it down either as a > complete proposal or diffs to Wolfgangs? I did. You sent comments on it and I sent back a cleaned up version. Here it is again. -- Alastair Goals ~ Since foreign libraries sometimes exploit thread local state, it is necessary to provide some control over which thread is used to execute foreign code. In particular, it is important that it should be possible for Haskell code to arrange that a sequence of calls to a given library are performed by the same foreign (or 'native') thread and that if an external library calls into Haskell, then any outgoing calls from Haskell are performed by the same foreign thread. This specification is intended to be implementable both by multi-threaded Haskell implementations and by single-threaded implementations and so it does not comment on which particular OS thread is used to execute Haskell code. Design ~~ Haskell threads may be bound with either zero or one foreign threads. Binding occurs at thread creation time. There are four ways to create Haskell threads so there are four cases to consider: 1) forkForeignThread :: IO () -> IO ThreadId The fresh Haskell thread is bound to a fresh foreign thread. 2) forkIO :: IO () -> IO ThreadId The fresh Haskell thread is not bound to a foreign thread. 3) Calls to a bound foreign export allocate a fresh Haskell thread which is then bound to the calling thread thread. Bound foreign exports have the form foreign export bound foo :: and otherwise behave like normal foreign exports. 4) ToDo: For completeness, there ought to be a way to 'bind' finalizers to foreign threads but no concrete proposal currently exists. Calls to bound foreign imports by Haskell threads which are bound to a foreign thread are performed by that foreign thread. Bound foreign imports have the form foreign import bound foo :: and otherwise behave like normal foreign imports. Calls to any free (i.e., not bound) foreign imports may be made in the bound thread (if it exists) or by some other foreign thread at the implementation's discretion. Issues ~~ The notion of bound foreign imports could be eliminated by saying that all foreign calls are performed by the bound thread if one exists and eliminate the concept of 'bound foreign imports'. The only reason to allow any flexibility is to allow for faster implementations which perform less context switching - this is especially important for 'unsafe' foreign calls. An alternative to forkForeignThread is to allow direct control over thread binding: bindThread :: ForeignThread -> IO () The current Haskell thread is bound to a fresh foreign thread. (Any previous binding is forgotten.) This leads to a much simpler design since it eliminates the need for forkForeignThread and can be used for finalizers too. The cost is that every bound foreign call requires locking and a context switch since multiple Haskell threads may be bound to the same foreign thread and could try to make a foreign call 'at the same time'. Binding finalizers to foreign threads also seems to require locking and a context switch for the same reason. ___ Glasgow-haskell-users mailing list [EMAIL PROTECTED] http://www.haskell.org/mailman/listinfo/glasgow-haskell-users
RE: Native Threads in the RTS
> Simon Marlow: > > > Another problem, from an implementation point of view, is that we > > would have to surround "unsafe" foreign calls with a lot of > > context-switching gumph, in case the calling Haskell thread is bound > > to a native thread. I really think we don't want to do this. > > Note that you only have to do this to foreign calls of the form: > > foreign import bound foo :: ... > > since any other calls are free to use whatever thread they feel like. Umm, this is new... the proposal doesn't have "foreign import bound", although it does have a parenthetical comment that indicates that it might be considered: There are now two kinds of foreign exported [and foreign import wrapped] functions: bound and free. and later on: When a foreign imported function is invoked [by Haskell code], the foreign code is executed in the native thread associated with the current Haskell thread, ... So currently the idea is that every foreign import is executed by the native thread bound to the current Haskell thread, if any. This is all getting highly confusing, as it seems we're working with different ideas of what's on the table. Alastair: you seem to be working on your own proposal - could you write it down either as a complete proposal or diffs to Wolfgangs? Cheers, Simon ___ Glasgow-haskell-users mailing list [EMAIL PROTECTED] http://www.haskell.org/mailman/listinfo/glasgow-haskell-users
Re: Native Threads in the RTS
Simon Marlow: > Another problem, from an implementation point of view, is that we > would have to surround "unsafe" foreign calls with a lot of > context-switching gumph, in case the calling Haskell thread is bound > to a native thread. I really think we don't want to do this. Note that you only have to do this to foreign calls of the form: foreign import bound foo :: ... since any other calls are free to use whatever thread they feel like. So, we can say that foreign functions of the form: foreign import bound unsafe bar :: ... are illegal or we can allow them and provide warnings or we can allow them and trust the programmer to know that bar is much more expensive than they think. (I favour the first two.) -- Alastair ___ Glasgow-haskell-users mailing list [EMAIL PROTECTED] http://www.haskell.org/mailman/listinfo/glasgow-haskell-users
RE: Native Threads in the RTS
> Or, we can adopt a much weaker semantics than Wolfgang > intended and have: > > $0 <= bindees(f) - uses(f)$ > > This would allow several currently running, active Haskell threads to > all be bound to the same foreign thread. When any of these threads > makes a foreign call, the other threads could all keep running and > they would only block if they too tried to make foreign calls. From > an implementation point of view, this requires: > > 1) That foreign threads are _not_ used to execute Haskell code. > > 2) That we maintain a lock on foreign threads so that only one >Haskell thread tries to use it at a time. > > I see two potential problems with this (but would like to hear which, > if either, dominates your thoughts): > > 1) If foreign threads cannot be used to execute Haskell code, foreign >calls require (OS-level) context switches which are expensive. > > 2) Adding an implicit lock to foreign calls might surprise > programmers. Another problem, from an implementation point of view, is that we would have to surround "unsafe" foreign calls with a lot of context-switching gumph, in case the calling Haskell thread is bound to a native thread. I really think we don't want to do this. The "thread groups" idea is similar, but only allows one of the Haskell threads in a group to be executing at any one time. This means you can run the Haskell thread using its native thread, and you don't have to context switch on every C call. However, I believe it would be tricky to implement this correctly in the scheduler (not impossible, just tricky and hard to test). Cheers, Simon ___ Glasgow-haskell-users mailing list [EMAIL PROTECTED] http://www.haskell.org/mailman/listinfo/glasgow-haskell-users
Re: Native Threads in the RTS
[Note: I'm consistently using 'foreign thread' instead of 'native thread'. The Haskell-spec necessarily treats Haskell as the centre of the universe. So what a Linux kernel hacker might think of as a 'native thread' is really quite foreign to Haskell. Feel free to ignore this little experiment with the language.] > *) Exactly one Haskell thread associated with the native thread is > executing. All other associated Haskell threads are blocked. No > foreign code is being executed by the native thread. This isn't quite right - or, at least, needs clarified. Consider Haskell functions a,b,c,d and C functions A,B,C,D and a call pattern a -> A -> b -> B -> c -> C -> d -> D That is, a calls A, calls b, calls B, calls ... Suppose we want A,B,C,D executed by the same foreign thread. Each of a,b,c,d are executed by different Haskell threads (because a new Haskell thread is spawned for each call into Haskell) so we have multiple Haskell threads associated with a single foreign thread. Now, when D is called, which of these threads is 'executing' and which are 'blocked'? I think the quoted text assumes that a,b,c,d are blocked during the call to D. The GHC implementation might well perform a context switch on making the calls into C so we could, perhaps, say that a Haskell thread is 'blocked' while making an ffi call. But, for normal function calls (i.e., all in Haskell or all in C, no ffi stuff), we don't say that the caller is 'blocked' until the callee returns. I think it's better to reserve the word is 'blocked' for its normal usage and avoid possibly over-specifying what implementations must do to implement the spec. Possible rewording: Definitions: Let $f$ be a foreign thread. $uses(f)$ is the number of foreign calls by Haskell threads bound to $f$. $bindees(f)$ is the number of Haskell threads bound to $f$. Invariant: $0 <= bindees(f) - uses(f) <= 1$ Proof: (Should be possible by) structural induction over relevant IO operations (forkIO, forkNativeIO, etc.) This needs careful interpretation if we want to be able to bind finalizers to foreign threads. In particular, if a finalizer is bound to a foreign thread, we don't increment 'bindees(f)' until the finalizer starts and we don't start the finalizer unless either: bindees(f) - uses(f) == 0 or, maybe even, bindees(f) == 0 Or, we can adopt a much weaker semantics than Wolfgang intended and have: $0 <= bindees(f) - uses(f)$ This would allow several currently running, active Haskell threads to all be bound to the same foreign thread. When any of these threads makes a foreign call, the other threads could all keep running and they would only block if they too tried to make foreign calls. From an implementation point of view, this requires: 1) That foreign threads are _not_ used to execute Haskell code. 2) That we maintain a lock on foreign threads so that only one Haskell thread tries to use it at a time. I see two potential problems with this (but would like to hear which, if either, dominates your thoughts): 1) If foreign threads cannot be used to execute Haskell code, foreign calls require (OS-level) context switches which are expensive. 2) Adding an implicit lock to foreign calls might surprise programmers. -- Alastair ___ Glasgow-haskell-users mailing list [EMAIL PROTECTED] http://www.haskell.org/mailman/listinfo/glasgow-haskell-users
Re: Native Threads in the RTS
I'll write up a new version of the proposal tomorrow. For now, here are some answers and [at the end] a question about the current FFI specification. Simon Peyton Jones wrote: You don't say (but you do mean) A bound Haskell thread can be executed only by its associated native thread No I don't mean that, and I've been avoiding to say that. This is how the GHC implementation will probably handle it, but I do not want to put that in the general specification. Alastair remarked a while ago: For that matter, I'd like it to be possible to implement this spec in Hugs. Hugs is internally single-threaded but this spec is concerned with what happens when Haskell calls out to C and we could arrange to switch into the appropriate native thread when Hugs calls out to C. After all, the only thing which needs to be guaranteed is that foreign functions called by the Haskell thread are executed in the associated native thread. You don't say (and I'm not sure if you mean) If a bound native thread blocks, all of its associated Haskell threads are blocked too If a bound Haskell thread blocks, its associate native thread and all its associated Haskell threads also block. Does this sound clearer: *) Exactly one Haskell thread associated with the native thread is executing. All other associated Haskell threads are blocked. No foreign code is being executed by the native thread. *) The native thread is executing foreign code. No Haskell code is executing in any of the associated Haskell threads. *) The native thread and all Haskell threads associated with it are blocked. | The thread that main runs in, threads created using forkIO and threads | created for running finalizers or signal handlers are not necessarily | associated with a native thread. However, an implementation might | choose to do so. But the impl may *not* choose a bound native thread. These must be kept inviolate. [...] Again, it must not be a bound native thread. Good point, I had overlooked that. If a bound Haskell thread calls a foreign import that is not labelled 'threadsafe' which calls a bound foreign export does that work? What if the foreign export was not bound? Similarly, if the foreign import was labelled 'threadsafe', would it work? It's not obvious to me. Some kind of semantics would be good. Good question. I reread Section 3.3 of the FFI document (RC7), and now I think I cannot clarify my specification in this respect without first asking others to clarify the current specs - can someone explain the distinction between unsafe, safe and threadsafe in the current FFI to me? I think I know what it does in GHC, but what's the general definition? I've read the description in the FFI document, but it's not clear to me. Is there any reason why "safe" is the default and not "threadsafe"? After all, "safe" is less safe (it might cause the whole program to block). To me, "safe" seems to be an odd middle ground between speed and safety. What is "safe" guaranteed/allowed to do? Is it _guaranteed_ to block other Haskell threads under certain conditions? Or is that only an artifact of current implementations? Why are implementations allowed to _silently_ fall back to "safe" when "threadsafe" is not supported? Isn't that dangerous? If I'm not mistaken, "threadsafe" calls from bound Haskell threads would have exactly the same overhead as "safe" calls. Should we make sure that "safe" calls somehow block other threads? If so, why? Thats all for now Wolfgang ___ Glasgow-haskell-users mailing list [EMAIL PROTECTED] http://www.haskell.org/mailman/listinfo/glasgow-haskell-users
RE: Native Threads in the RTS
Simon P.J. writes: > Can you give an example of when a native thread is associated > with more than one Haskell thread? I gave an example in my previous message. It's when a bound Haskell thread makes a foreign call which re-enters Haskell via a bound foreign export. > You don't say (and I'm not sure if you mean) > > If a bound native thread blocks, all of its associated Haskell > threads are blocked too "When Bagpuss goes to sleep, all his friends go to sleep too." :-) (apologies to those who never watched British childrens TV in the 70s). Actually, for any given native thread, only one of its bound Haskell threads can be runnable, the others must all be blocked waiting on the result of a foreign call. So you don't really have to worry about a native thread being bound to multiple Haskell threads; this would be quite tricky to implement in the scheduler anyway. Cheers, Simon ___ Glasgow-haskell-users mailing list [EMAIL PROTECTED] http://www.haskell.org/mailman/listinfo/glasgow-haskell-users
RE: Native Threads in the RTS
Improving. Want to put it in CVS? Simon M can suggest where. Simon | Definitions | ~~~ | A native thread (aka OS thread) is a thread as defined by the operating | system. | A Haskell thread is [*** FIXME - How shall I put this? ***] the thing | you see from Haskell land. A "Haskell thread" encapsulates the execution of a Haskell I/O action. A Haskell thread is created by forkIO, and dies when the I/O action completes. A Haskell thread is always executed by a native thread. The Haskell RTS creates one or more "worker native threads" to execute Haskell threads. | Haskell threads may be associated at thread creation time with either | zero or one native threads. Each Native thread is associated with zero | or more native threads. zero or more *Haskell* threads. Can you give an example of when a native thread is associated with more than one Haskell thread? To avoid "A Haskell thread associated with a native thread" I'd prefer to define the term "a bound Haskell thread". I would also like to describe a "bound native thread" as one that has associated Haskell thread(s). | If a native thread is associated with one or more Haskell threads, | exactly one of the following must be true: | *) Exactly one Haskell thread associated with the native thread is | executing. | *) The native thread is executing foreign code. | *) The native thread and all Haskell threads associated with it are | blocked. You don't say (but you do mean) A bound Haskell thread can be executed only by its associated native thread You don't say (and I'm not sure if you mean) If a bound native thread blocks, all of its associated Haskell threads are blocked too If a bound Haskell thread blocks, its associate native thread and all its associated Haskell threads also block. | The thread that main runs in, threads created using forkIO and threads | created for running finalizers or signal handlers are not necessarily | associated with a native thread. However, an implementation might | choose to do so. But the impl may *not* choose a bound native thread. These must be kept inviolate. | When a "free" foreign exported function is invoked, the implementation | may freely choose what kind of Haskell thread the function is executed | in. It is not specified whether this thread is associated with a | particular OS thread or not. Again, it must not be a bound native thread. | When a foreign imported function is invoked [by Haskell code], the | foreign code is executed in the native thread associated with the | current Haskell thread, if an association exists. If the current | Haskell thread is not associated to a native thread, the implementation | may freely decide which thread to run the foreign function in. | The existing distinction between unsafe, safe and threadsafe calls | remains unchanged. If a bound Haskell thread calls a foreign import that is not labelled 'threadsafe' which calls a bound foreign export does that work? What if the foreign export was not bound? Similarly, if the foreign import was labelled 'threadsafe', would it work? It's not obvious to me. Some kind of semantics would be good. ___ Glasgow-haskell-users mailing list [EMAIL PROTECTED] http://www.haskell.org/mailman/listinfo/glasgow-haskell-users
Re: Native Threads in the RTS
Simon Marlow wrote: I don't see the problem with forking a new Haskell thread for each foreign export, and associating it with the current native thread if the foreign export is marked "bound". It does mean we can get multiple Haskell threads bound to the same native thread, but only one can be runnable at any one time (this is an important invariant from the point of view of the implementation, I believe). Of course, you're right. Simon Peyton-Jones wrote: I offer myself as such a guinea pig. I'm afraid I don't understand it yet. It's hard to describe precisely. Comments below. Yes, I do need a guinea pig ;-) . I really have trouble expressing my ideas accurately, and I keep changing them. Better start with some definitions, for 'Haskell thread' and'native thread' I think I know what you mean, but better to be sure. Well, yes. I didn't manage to come up with a decent definition for it yet. I intend "native thread" to be the thing you get using pthread_create on unix, and "Haskell thread" to be the same thing as it currently is in the GHC RTS. Can anyone think of a way of defining that in a way that is accurate, general and understandable? | If there is one, this Haskell thread is used to execute the callback. OK, so this is where I get completely confused. A Haskell thread is not (currently) an execution platform. Oops... The best way to confuse other people is to be confused yourself ;-) --- I had a slight misconception about the RTS there --- I think I've corrected that. === Threads Proposal, version 4 Goals ~ Since foreign libraries sometimes exploit thread local state, it is necessary to provide some control over which thread is used to execute foreign code. In particular, it is important that it should be possible for Haskell code to arrange that a sequence of calls to a given library are performed by the same native thread and that if an external library calls into Haskell, then any outgoing calls from Haskell are performed by the same native thread. This specification is intended to be implementable both by multithreaded Haskell implementations and by single-threaded implementations and so it does not comment on which particular OS thread is used to execute Haskell code. Definitions ~~~ A native thread (aka OS thread) is a thread as defined by the operating system. A Haskell thread is [*** FIXME - How shall I put this? ***] the thing you see from Haskell land. Design ~~ Haskell threads may be associated at thread creation time with either zero or one native threads. Each Native thread is associated with zero or more native threads. If a native thread is associated with one or more Haskell threads, exactly one of the following must be true: *) Exactly one Haskell thread associated with the native thread is executing. *) The native thread is executing foreign code. *) The native thread and all Haskell threads associated with it are blocked. The thread that main runs in, threads created using forkIO and threads created for running finalizers or signal handlers are not necessarily associated with a native thread. However, an implementation might choose to do so. There are now two kinds of foreign exported [and foreign import wrapped] functions: bound and free. The FFI syntax should be extended appropriately [which of the two should be the default, if any?]. When a "bound" foreign exported function is invoked [by foreign code], a new Haskell thread is created and associated with the native thread. The new associated Haskell thread is then used to execute the callback. When a "free" foreign exported function is invoked, the implementation may freely choose what kind of Haskell thread the function is executed in. It is not specified whether this thread is associated with a particular OS thread or not. When a foreign imported function is invoked [by Haskell code], the foreign code is executed in the native thread associated with the current Haskell thread, if an association exists. If the current Haskell thread is not associated to a native thread, the implementation may freely decide which thread to run the foreign function in. The existing distinction between unsafe, safe and threadsafe calls remains unchanged. A new library routine, forkNativeThread :: IO () -> IO ThreadID, should spawn a new Haskell Thread (like forkIO) and associate it with a new native thread (forkIO is not guaranteed to do this). It may be implemented using the FFI and an OS-specific thread creation routine. It would just pass a "bound" callback as an entry point for a new OS thread. Issues ~~ Finalizers and signal handlers cannot be associated with a particular native thread. If they have to trigger an action in a particular native thread, a message has to be sent manually (via MVars and friends) to the Haskell thread associated with the native thread in question. This introduces a change in the syn
Re: Native Threads in the RTS
> Are you sure you intend to change the type of forkIO? Currently it's > forkIO :: IO () -> IO ThreadId Sorry, no, I did not. -- Alastair ___ Glasgow-haskell-users mailing list [EMAIL PROTECTED] http://www.haskell.org/mailman/listinfo/glasgow-haskell-users
RE: Native Threads in the RTS
> When a "bound" foreign exported function is invoked [by > foreign code], > the implementation checks whether a Haskell thread is associated with > the current OS thread. > If there is one, this Haskell thread is used to execute the callback. > If there is none, a new Haskell thread is created and associated with > the native thread. This is the only situation where a Haskell > thread is > associated with a native thread. The new associated Haskell thread is > then used to execute the callback. When the callback finishes, the > Haskell thread is terminated, the association is dissolved, > but the OS thread continues to run. This is the bit I have trouble with too. If the OS thread trying to call a foreign export has an associated Haskell thread, then it must be because the Haskell thread called out to C in the first place. This Haskell thread will be waiting for the call to return, and has all the state associated with its current execution context, so we can't just use that thread to run the foreign export. I don't see the problem with forking a new Haskell thread for each foreign export, and associating it with the current native thread if the foreign export is marked "bound". It does mean we can get multiple Haskell threads bound to the same native thread, but only one can be runnable at any one time (this is an important invariant from the point of view of the implementation, I believe). Cheers, Simon ___ Glasgow-haskell-users mailing list [EMAIL PROTECTED] http://www.haskell.org/mailman/listinfo/glasgow-haskell-users
RE: Native Threads in the RTS
| Nice design, Alastair. I've stolen lots of ideas and some text for the | complete rewrite of the proposal. I think it is a great idea to rewrite the proposal. A tiny minority will follow the details of the discussion, and it's essential to record the outcome in a way comprehensible by someone who reads only the proposal. I offer myself as such a guinea pig. I'm afraid I don't understand it yet. It's hard to describe precisely. Comments below. I wonder if some simple formal semantics would be useful. Simon | Haskell threads may be associated at thread creation time with either | zero or one native threads. Each Native thread is associated with zero | or one Haskell threads (no native thread may be associated with two | Haskell threads at a time). Better start with some definitions, for 'Haskell thread' and 'native thread' I think I know what you mean, but better to be sure. | An associated pair of a Haskell thread and a native thread can only | execute either foreign code or haskell code at any one time. Unclear. Can we have a name for a Haskell thread that is 'associated with' a native thread? (Or is that misleading?) Is that what you mean by a 'bound Haskell thread'? If so then I think the above sentence means A bound Haskell thread can be executed only by its associated native thread. | There are now two kinds of foreign exported [and foreign import | wrapped] functions: bound and free [I'm not happy with these names, for | the same reasons as given by Seth before]. Do you mean that the syntax for 'foreign export' etc is modified to let you say bound/free? | When a "bound" foreign exported function is invoked [by foreign code], | the implementation checks whether a Haskell thread is associated with | the current OS thread. | If there is one, this Haskell thread is used to execute the callback. OK, so this is where I get completely confused. A Haskell thread is not (currently) an execution platform. It is spawned to execute a single IO action, and then dies, completely and forever. Perhaps you are saying that a bound Haskell thread does not vanish when it completes its IO action instead it waits around in case its associated OS thread wants it to do something If that is what you mean, better say so, because it's quite new. Suppose the Haskell thread calls *out* to foreign code. Then the Haskell thread is not available for to compute anything because it's suspended in the middle of a call. What happens if a bound Haskell thread blocks? Does its associated OS thread block too? Please say so. | If there is none, a new Haskell thread is created and associated with | the native thread. | This is the only situation where a Haskell thread is | associated with a native thread. Do you mean "This is the only way in which an association between a native thread and a Haskell thread can be created"? | The new associated Haskell thread is | then used to execute the callback. When the callback finishes, the | Haskell thread is terminated, the association is dissolved, but the OS | thread continues to run. So, returning to "the implementation checks whether a Haskell thread is associated with the current OS thread", how could this ever happen? The Haskell thread dies when the foreign call terminates. | When a foreign imported function is invoked [by Haskell code], the | foreign code is executed in the native thread associated with the | current Haskell thread, if an association exists. If the current | Haskell thread is not associated to a native thread, the implementation | may freely decide which thread to run the foreign function in. | This must be done for all foreign imports, including "unsafe". What is "this"? | An unsafe call must not call back to Haskell or otherwise cause a | garbage collection. Other Haskell threads may be blocked while the | unsafe call executes. | A safe call allows callbacks to Haskell. Other Haskell threads may be | blocked while the unsafe call executes. | A threadsafe call additionally guarantees other Haskell threads not to | block. ...not to block, even if the foreign call blocks in foreign code. | forkNativeThread :: IO () -> IO ThreadID may be implemented using the | FFI and an OS-specific thread creation routine. Better say what you expect forkNativeThread to do, and what its implementation looks like. ___ Glasgow-haskell-users mailing list [EMAIL PROTECTED] http://www.haskell.org/mailman/listinfo/glasgow-haskell-users
Re: Native Threads in the RTS
Typo: > Being fresh to Haskell, I suggest that the naming continues to be > "native" and "free". I did mean "native" and "green" Have a nice day, once again. Johan Steunenberg ___ Glasgow-haskell-users mailing list [EMAIL PROTECTED] http://www.haskell.org/mailman/listinfo/glasgow-haskell-users
Re: Native Threads in the RTS
Nice design, Alastair. I've stolen lots of ideas and some text for the complete rewrite of the proposal. The concept of "associating" haskell threads to native threads proved to be a good way of explaining my original idea in a different way --- and then I found out that forkNativeThread needn't be a primitive, but can be implemented on top of the FFI. After that I found out what the bound/free exports buisiness was all about and why we might need it. As for the questions regarding my previous proposal, I think they are answered in the new one. If they aren't, let me know. [It's no use explaining what I meant to say if I already want to say something different ;-) ] Cheers, Wolfgang === Threads Proposal, version 3 Goals ~ Since foreign libraries sometimes exploit thread local state, it is necessary to provide some control over which thread is used to execute foreign code. In particular, it is important that it should be possible for Haskell code to arrange that a sequence of calls to a given library are performed by the same native thread and that if an external library calls into Haskell, then any outgoing calls from Haskell are performed by the same native thread. This specification is intended to be implementable both by multithreaded Haskell implementations and by single-threaded implementations and so it does not comment on which particular OS thread is used to execute Haskell code. Design ~~ Haskell threads may be associated at thread creation time with either zero or one native threads. Each Native thread is associated with zero or one Haskell threads (no native thread may be associated with two Haskell threads at a time). An associated pair of a Haskell thread and a native thread can only execute either foreign code or haskell code at any one time. The thread that main runs in, threads created using forkIO and threads created for running finalizers or signal handlers are not associated with a native thread [Actually, we might make this an implementation detail: These Haskell threads are not guaranteed to be associated with a native thread. If it makes sense for some implementation, all threads might be associated with native threads]. There are now two kinds of foreign exported [and foreign import wrapped] functions: bound and free [I'm not happy with these names, for the same reasons as given by Seth before]. When a "bound" foreign exported function is invoked [by foreign code], the implementation checks whether a Haskell thread is associated with the current OS thread. If there is one, this Haskell thread is used to execute the callback. If there is none, a new Haskell thread is created and associated with the native thread. This is the only situation where a Haskell thread is associated with a native thread. The new associated Haskell thread is then used to execute the callback. When the callback finishes, the Haskell thread is terminated, the association is dissolved, but the OS thread continues to run. When a "free" foreign exported function is invoked, the implementation may freely choose what Haskell thread the function is executed in. It is not specified whether this thread is associated with a particular OS thread or not. When a foreign imported function is invoked [by Haskell code], the foreign code is executed in the native thread associated with the current Haskell thread, if an association exists. If the current Haskell thread is not associated to a native thread, the implementation may freely decide which thread to run the foreign function in. This must be done for all foreign imports, including "unsafe". An unsafe call must not call back to Haskell or otherwise cause a garbage collection. Other Haskell threads may be blocked while the unsafe call executes. A safe call allows callbacks to Haskell. Other Haskell threads may be blocked while the unsafe call executes. A threadsafe call additionally guarantees other Haskell threads not to block. forkNativeThread :: IO () -> IO ThreadID may be implemented using the FFI and an OS-specific thread creation routine. Issues ~~ Finalizers and signal handlers cannot be associated with a particular native thread. If they have to trigger an action in a particular native thread, a message has to be sent manually (via MVars and friends) to the Haskell thread associated with the native thread in question. This might be tedious, but if we want to avoid the nastiness of multiple Haskell threads associated with one OS thread (lots of unpredictable blocking), it looks like our only choice. ___ Glasgow-haskell-users mailing list [EMAIL PROTECTED] http://www.haskell.org/mailman/listinfo/glasgow-haskell-users
Re: Native Threads in the RTS
At 2002-11-26 09:37, Alastair Reid wrote: > 1) forkNativeThread :: IO () -> IO () > The fresh Haskell thread is bound to a fresh native thread. > > 2) forkIO :: IO () -> IO () > The fresh Haskell thread is not bound to a native thread. Are you sure you intend to change the type of forkIO? Currently it's forkIO :: IO () -> IO ThreadId -- Ashley Yakeley, Seattle WA ___ Glasgow-haskell-users mailing list [EMAIL PROTECTED] http://www.haskell.org/mailman/listinfo/glasgow-haskell-users
Re: Native Threads in the RTS
On 26 Nov 2002, Alastair Reid wrote: > > Umm, Alastair, I think you've got things a bit mixed up here. Did > > you mean two ways to create a native thread? > > No. > > > There are currently three ways to create a Haskell thread (forkIO, > > foreign export, finalizers) and Wolfgang has proposed a fourth > > (forkNativeThread). Invocation of a signal handler also creates a Haskell thread, doesn't it? > I was (implicitly) viewing forkIO and forkNativeThread as two variants > of the same operation. Both fork a Haskell thread, one of them also > creates a native thread. (It may also choose to use the native thread > as the Haskell thread but that's not externally observable.) > > I was putting off finalizers until the end. > > >> 1) forkNativeThread :: IO () -> IO () > >> > >> The fresh Haskell thread is associated with a fresh native thread. > >> > >> (ToDo: do we really need to use a fresh native thread or would a > >> pool of threads be ok? The issue could be avoided by separating > >> creation of the native thread from the 'associate' operation.) > >> > >> 2) Calls to a threadsafe foreign export allocate a fresh Haskell > >> thread which is then associated with the Haskell thread. > > > I don't know what you mean by a "threadsafe foreign export". Did > > you mean "threadsafe foreign import" perhaps? And I'm not sure how > > a fresh Haskell thread is associated with a Haskell thread ;-) > > Using the bound/free terminology suggested by Seth, what I meant was > "bound foreign import". Actually, I proposed the terms, and Seth criticized the proposal. Perhaps "bound" and "unbound" might be a bit better and partially avoid the possible confusion with lambda calculus variables. > >> [ToDo: can Haskell threads with no associated thread make foreign > >> calls using a thread associated with some other thread? > > > er... overloading the word "thread" was maybe not such a good idea. > > I think you're asking whether a green thread can grab a native > > thread to make a foreign call. The current answer is no... but can > > you think of a reason we might want this feature? > > My question was of the form: 'is a correct implementation allowed to > use a native thread even if the programmer didn't ask for it?' not > 'can we make this happen?' > > Sorry for all the confusion, here's the key part of the proposal again > - hopefully without the ambiguity. > > > Haskell threads may be bound with either zero or one native threads. > Binding occurs at thread creation time. There are four ways to > create Haskell threads so there are four cases to consider: How about: A Haskell thread may be bound to a native thread. Such binding occurs when the Haskell thread is created and persists for the lifetime of the Haskell thread. A Haskell thread that is not bound to a native thread is called "unbound". There are four ways ... > 1) forkNativeThread :: IO () -> IO () > The fresh Haskell thread is bound to a fresh native thread. > > 2) forkIO :: IO () -> IO () > The fresh Haskell thread is not bound to a native thread. > > 3) Calls to a bound foreign export allocate a fresh Haskell > thread which is then bound to the calling thread thread. "... which is bound to the calling native thread" ? > Bound foreign exports have the form > >foreign export bound foo :: > > and otherwise behave like normal foreign exports. > > 4) ToDo: For completeness, there ought to be a way to 'bind' > finalizers to native threads but no concrete proposal currently > exists. > > [ToDo: The following could be simplified by saying that all foreign > calls are performed by the bound thread if one exists and eliminate > the concept of 'bound foreign imports'. The only reason to allow > any flexibility is to allow for faster implementations.] > Calls to bound foreign imports by threads which are bound to a > native thread are performed by that native thread. > > Bound foreign imports have the form > >foreign import bound foo :: > > and otherwise behave like normal foreign imports. > > Calls to any free (i.e., not bound) foreign imports may be made in > the bound thread (if it exists) or by some other native thread at > the implementation's discretion. > > > -- > Alastair ___ Glasgow-haskell-users mailing list [EMAIL PROTECTED] http://www.haskell.org/mailman/listinfo/glasgow-haskell-users
Re: Native Threads in the RTS
> Umm, Alastair, I think you've got things a bit mixed up here. Did > you mean two ways to create a native thread? No. > There are currently three ways to create a Haskell thread (forkIO, > foreign export, finalizers) and Wolfgang has proposed a fourth > (forkNativeThread). I was (implicitly) viewing forkIO and forkNativeThread as two variants of the same operation. Both fork a Haskell thread, one of them also creates a native thread. (It may also choose to use the native thread as the Haskell thread but that's not externally observable.) I was putting off finalizers until the end. >> 1) forkNativeThread :: IO () -> IO () >> >> The fresh Haskell thread is associated with a fresh native thread. >> >> (ToDo: do we really need to use a fresh native thread or would a >> pool of threads be ok? The issue could be avoided by separating >> creation of the native thread from the 'associate' operation.) >> >> 2) Calls to a threadsafe foreign export allocate a fresh Haskell >> thread which is then associated with the Haskell thread. > I don't know what you mean by a "threadsafe foreign export". Did > you mean "threadsafe foreign import" perhaps? And I'm not sure how > a fresh Haskell thread is associated with a Haskell thread ;-) Using the bound/free terminology suggested by Seth, what I meant was "bound foreign import". >> [ToDo: can Haskell threads with no associated thread make foreign >> calls using a thread associated with some other thread? > er... overloading the word "thread" was maybe not such a good idea. > I think you're asking whether a green thread can grab a native > thread to make a foreign call. The current answer is no... but can > you think of a reason we might want this feature? My question was of the form: 'is a correct implementation allowed to use a native thread even if the programmer didn't ask for it?' not 'can we make this happen?' Sorry for all the confusion, here's the key part of the proposal again - hopefully without the ambiguity. Haskell threads may be bound with either zero or one native threads. Binding occurs at thread creation time. There are four ways to create Haskell threads so there are four cases to consider: 1) forkNativeThread :: IO () -> IO () The fresh Haskell thread is bound to a fresh native thread. 2) forkIO :: IO () -> IO () The fresh Haskell thread is not bound to a native thread. 3) Calls to a bound foreign export allocate a fresh Haskell thread which is then bound to the calling thread thread. Bound foreign exports have the form foreign export bound foo :: and otherwise behave like normal foreign exports. 4) ToDo: For completeness, there ought to be a way to 'bind' finalizers to native threads but no concrete proposal currently exists. [ToDo: The following could be simplified by saying that all foreign calls are performed by the bound thread if one exists and eliminate the concept of 'bound foreign imports'. The only reason to allow any flexibility is to allow for faster implementations.] Calls to bound foreign imports by threads which are bound to a native thread are performed by that native thread. Bound foreign imports have the form foreign import bound foo :: and otherwise behave like normal foreign imports. Calls to any free (i.e., not bound) foreign imports may be made in the bound thread (if it exists) or by some other native thread at the implementation's discretion. -- Alastair ___ Glasgow-haskell-users mailing list [EMAIL PROTECTED] http://www.haskell.org/mailman/listinfo/glasgow-haskell-users
RE: Native Threads in the RTS
> * > Native Threads Proposal, version 2 > > Some "foreign" libraries (for example OpenGL) rely on a mechanism > called thread-local storage. The meaning of an OpenGL call therefore > usually depends on which OS thread it is called from. > Therefore, some > kind of direct mapping from Haskell threads to OS threads is > necessary > in order to use the affected foreign libraries. > Executing every haskell thread in its own OS thread is not > feasible for > performance reasons. However, perfomance of native OS threads is not > too bad as long as there aren't too many, so I propose that some > threads get their own OS threads, and some don't: > > Every Haskell Thread can be either a "green" thread or a "native" > thread. > For each "native" thread, there is exactly one OS thread > created by the > RTS. Is there an invariant that there is only one Haskell thread for each native thread? > For a green thread, it is unspecified which OS thread it is > executed in. > The main program and all haskell threads forked using forkIO > are green > threads. Threads forked using forkNativeThread :: IO () -> IO () are > native threads. (Note: The type of the current haskell thread does > _not_ matter when forking new threads) > > Execution of a green thread might move from one OS thread to > another at > any time. A "green" thread is never executed in an OS thread that is > reserved for a "native" thread. > A "native" haskell thread and all foreign imported functions that it > calls are executed in its associated OS thread. A foreign exported > callback that is called from C code executing in that OS thread is > executed in the native haskell thread. > A foreign exported callback that is called from C code > executing in an > OS thread that is not associated with a "native" haskell thread is > executed in a new green haskell thread. > > Only one OS thread can execute Haskell code at any given time. > > If a "native" haskell thread enters a foreign imported > function that is > marked as "safe" or "threadsafe", all other Haskell threads keep > running. If the imported function is marked as "unsafe", no other > threads are executed until the call finishes. I'd change this paragraph as follows: If a "native" haskell thread enters a foreign imported function that is marked as "threadsafe", all other Haskell threads keep running. If the imported function is marked as "safe" or "unsafe", no other threads are executed until the call finishes. in other words, foreign imports for native threads behave just like they do for green threads. As Simon P.J. pointed out, we don't do any OS-thread synchronisation on a "safe" foreign import. > Other things I'm not sure about: > What should we do get if a foreign function spawns a new OS > thread and > executes a haskell callback in that OS thread? Should a new native > haskell thread that executes in the OS thread be created? Should the > new OS thread be blocked and the callback executed in a green > thread? > What does the current threaded RTS do? (I assume the > non-threaded RTS will just crash?) The Haskell callback will execute in a green thread, according to the proposal above, and I think that's the right thing to do. It's possible to get into a situation in which several Haskell threads in the system are associated with the same OS thread: - Haskell native thread calls a foreign import, which - invokes a Haskell callback, which - calls a foreign import, which - invokes another Haskell callback at this point the two Haskell threads created by the callbacks are both attached to the same native thread. One of them is blocked waiting for its foreign import to return, however. I'm not sure if this is important. Cheers, Simon ___ Glasgow-haskell-users mailing list [EMAIL PROTECTED] http://www.haskell.org/mailman/listinfo/glasgow-haskell-users
Re: Native Threads in the RTS
On Tue, 2002-11-26 at 08:32, Dean Herington wrote: > On 26 Nov 2002, Alastair Reid wrote: > > > ps Better names than 'native' and 'green' surely exist. Something > > which conveys the idea that the thread will be remembered for later > > use seems appropriate but no good words spring to mind. > > Perhaps "bound" and "free"? Won't that be confused with bound and free as used in lambda calculus? Or am I missing the point and you mean that they are analogous to bound and free in lambda calculus? (If the latter, I need to reread my lambda calculus books. :)) > > > ___ > Glasgow-haskell-users mailing list > [EMAIL PROTECTED] > http://www.haskell.org/mailman/listinfo/glasgow-haskell-users -- Seth Kurtzberg M. I. S. Corp 480-661-1849 Pager 888-605-9296, or [EMAIL PROTECTED] ___ Glasgow-haskell-users mailing list [EMAIL PROTECTED] http://www.haskell.org/mailman/listinfo/glasgow-haskell-users
RE: Native Threads in the RTS
Alastair Reid wrote: > Design > ~~ > > Haskell threads may be associated at thread creation time with either > zero or one native threads. There are only two ways to create Haskell > threads so there are two cases to consider: Umm, Alastair, I think you've got things a bit mixed up here. Did you mean two ways to create a native thread? There are currently three ways to create a Haskell thread (forkIO, foreign export, finalizers) and Wolfgang has proposed a fourth (forkNativeThread). Or perhaps you're proposing we do away with forkIO and only have forkNativeThread? That was discounted a while back because we want to continue to have light-weight threads independent of OS threads. > 1) forkNativeThread :: IO () -> IO () > >The fresh Haskell thread is associated with a fresh native thread. > >(ToDo: do we really need to use a fresh native thread or would a >pool of threads be ok? The issue could be avoided by separating >creation of the native thread from the 'associate' operation.) > > 2) Calls to a threadsafe foreign export allocate a fresh Haskell >thread which is then associated with the Haskell thread. I don't know what you mean by a "threadsafe foreign export". Did you mean "threadsafe foreign import" perhaps? And I'm not sure how a fresh Haskell thread is associated with a Haskell thread ;-) > Calls to threadsafe foreign imports by threads which have an > associated native thread are performed by that native thread. > > Calls to any other foreign imports (i.e., 'safe' or 'unsafe' calls) > may be made in other threads or, if it exists, in the associated > native thread at the implementation's discretion. > > [ToDo: can Haskell threads with no associated thread make foreign > calls using a thread associated with some other thread? er... overloading the word "thread" was maybe not such a good idea. I think you're asking whether a green thread can grab a native thread to make a foreign call. The current answer is no... but can you think of a reason we might want this feature? Cheers, Simon ___ Glasgow-haskell-users mailing list [EMAIL PROTECTED] http://www.haskell.org/mailman/listinfo/glasgow-haskell-users
Re: Native Threads in the RTS
On 26 Nov 2002, Alastair Reid wrote: > ps Better names than 'native' and 'green' surely exist. Something > which conveys the idea that the thread will be remembered for later > use seems appropriate but no good words spring to mind. Perhaps "bound" and "free"? ___ Glasgow-haskell-users mailing list [EMAIL PROTECTED] http://www.haskell.org/mailman/listinfo/glasgow-haskell-users
Re: Native Threads in the RTS
After sending this mail this morning, I realized that threadsafety is largely orthogonal to the choice of which thread to run in. For example, I might want to make an 'unsafe' call in a particular native thread. So my proposed spec should add a second, orthogonal choice of ffi call types ('native'|'green') which may be specified _in addition to_ the current 'threadsafe'|'safe'|'unsafe'. -- Alastair ps Better names than 'native' and 'green' surely exist. Something which conveys the idea that the thread will be remembered for later use seems appropriate but no good words spring to mind. ___ Glasgow-haskell-users mailing list [EMAIL PROTECTED] http://www.haskell.org/mailman/listinfo/glasgow-haskell-users
Re: Native Threads in the RTS
After writing a fairly long, detailed reply (attached at end), I decided it would be simpler to write my take on what the design should be. Goals ~ Since foreign libraries sometimes exploit thread local state, it is necessary to provide some control over which thread is used to execute foreign code. In particular, it is important that it should be possible for Haskell code to arrange that a sequence of calls to a given library are performed by the same native thread and that if an external library calls into Haskell, then any outgoing calls from Haskell are performed by the same native thread. This specification is intended to be implementable both by multithreaded Haskell implementations and by single-threaded implementations and so it does not comment on which particular OS thread is used to execute Haskell code. Design ~~ Haskell threads may be associated at thread creation time with either zero or one native threads. There are only two ways to create Haskell threads so there are two cases to consider: 1) forkNativeThread :: IO () -> IO () The fresh Haskell thread is associated with a fresh native thread. (ToDo: do we really need to use a fresh native thread or would a pool of threads be ok? The issue could be avoided by separating creation of the native thread from the 'associate' operation.) 2) Calls to a threadsafe foreign export allocate a fresh Haskell thread which is then associated with the Haskell thread. Calls to threadsafe foreign imports by threads which have an associated native thread are performed by that native thread. Calls to any other foreign imports (i.e., 'safe' or 'unsafe' calls) may be made in other threads or, if it exists, in the associated native thread at the implementation's discretion. [ToDo: can Haskell threads with no associated thread make foreign calls using a thread associated with some other thread? Issues ~~ If multiple Haskell threads are associated with a single native thread, only one can make a foreign call at a time but what if the thread calls back into Haskell? Obviously, this callback is allowed to call out to C too. There is a third way to spawn a thread in GHC: running a finalizer attached to a weak pointer. There really ought to be a way to associate a native thread with finalizers. I guess the same applies to ForeignPtr finalizers which are (implicitly) foreign function calls. -- Alastair Reid [EMAIL PROTECTED] Reid Consulting (UK) Limited http://www.reid-consulting-uk.ltd.uk/alastair/ > A foreign exported callback that is called from C > code executing in an OS thread that is not associated with a > "native" haskell thread is executed in a new green haskell thread. Wouldn't it be better to always execute it in the native thread - and give that trhead equal status with native threads forked by Haskell code. As I understand the design at present, the only way to cause Haskell code to get executed in a particular native thread is to have Haskell fork the thread. This is fine for Haskell applications calling C libraries but doesn't seem too useful for C applications calling Haskell libraries. If the reason for wanting it to be executed in a green thread is efficiency, it seems we could say that 'threadsafe' calls will use the current calling thread and 'safe' and 'unsafe' calls may use a cheaper thread. > If a "native" haskell thread enters a foreign imported function that > is marked as "safe" or "threadsafe", all other Haskell threads keep > running. If the imported function is marked as "unsafe", no other > threads are executed until the call finishes. It seems like this is the wrong way around. 'unsafe' is meant to be the one that maximizes performance so surely that's the one where other threads are allowed to keep running if they want (and the implementation supports it). Also, the current ffi spec is written such that a compiler can choose to treat all 'unsafe' calls as 'safe' calls if it wishes. Your language seems to imply that programmers can rely on unsafe calls _not_ behaving like safe calls. What's the purpose of the restriction? Is it to make things cheaper or is it to provide programmers with guarantees about preemption and reentrancy? > If a "green" haskell thread enters a foreign imported function > marked as "threadsafe", a new OS thread is spawned that keeps > executing other green haskell threads while the foreign function > executes. Do you intend that a fresh thread should be spawned each time or is it ok to maintain a pool of previously used threads? > Native haskell threads continue to run in their own OS > threads. If a "green" haskell thread enters a foreign imported > function marked as "safe", all other green threads are blocked. Why are they blocked? Is it to provide some kind of guarantee about preemption and reentrancy or is it to make the implementation simpler? > Some people may want to run finalizers in specific OS threads (are >
Re: Native Threads in the RTS
Nicolas Oury <[EMAIL PROTECTED]> writes: > * I think that, if it is not too much complicated, it could be great > to put many threads in the OpenGL OS thread. The goal of concurrent > Haskell was to allow concurrency for expressivity. It would be a > pity to lose this in part of programs for technical reason. Having > this possibility would also be a pro this language : Haskell would > be the only language to have safe multithreaded OpenGL programming. Note that you can achieve the goal of having multithreaded OpenGL programming using Wolfgang's proposal. All you need to do is fork a worker thread which will make all the OpenGL calls. Any green thread wanting to make a call just sends a request to the worker and waits for a response. The code would look something like this: type Response = () type Job = IO Response type Ch = (MVar Job, MVar Response) -- the worker thread runs this worker :: Ch -> IO () worker ch@(jobs, responses) = do j <- readMVar jobs a <- j writeMVar responses a worker ch -- green threads call this to get work done doit :: Ch -> Job -> IO Response doit (jobs, responses) j = do writeMVar jobs j readMVar response Things get a little tedious if you want multiple return types. -- Alastair Reid [EMAIL PROTECTED] Reid Consulting (UK) Limited http://www.reid-consulting-uk.ltd.uk/alastair/ ___ Glasgow-haskell-users mailing list [EMAIL PROTECTED] http://www.haskell.org/mailman/listinfo/glasgow-haskell-users
Re: Native Threads in the RTS
Nicolas Oury a écrit: * I think that, if it is not too much complicated, it could be great to put many threads in the OpenGL OS thread. The goal of concurrent Haskell was to allow concurrency for expressivity. It would be a pity to lose this in part of programs for technical reason. Having this possibility would also be a pro this language : Haskell would be the only language to have safe multithreaded OpenGL programming. You can safely render into two different OpenGL contexts from two different OS threads. I don't think that rendering into the same context from two green threads would work - the OpenGL interface is far too thread-based for this to be useful. *Another problem can raise : if one render in two different OpenGL windows, he may want to use different threads for these rendering. However, this is impossible for the moment because it would implies that user threads know when a switch has occurred to a thread rendering in another context and swap OpenGL context. This implies a notion of either : allowing to execute arbitrary code on switch ; > [...] If we want to render into two different OpenGL windows in parallel, we can use two OS threads. OpenGL keeps a reference to its current OpenGL context on a per-OS-thread basis (some old OpenGL implementations might not support this, but I think we can ignore them). [...] some user defined code should be executed (in that case the code perform a context switch) [...] Haskell Code won't work here [after all, we're between two haskell threads...]. C code would be no problem. I actually proposed something like this as a stopgap measure for making OpenGL work with the threaded RTS in summer, but I was convinced by others on this list that this is a "hackish" solution that relies on internals of the RTS far too much. It seems that family and OS threads are independent : it could either be multiple OS threads for a family or multiple families for an OS threads. I think a thread could be member of multiple families (even if I can't see pertinent example so far). I also think that multiple threads can be the same member of a family (multiple threads drawing in the same window). What would it mean if a thread was a member of more than one thread families? Would it mean that it might execute in several different OS threads? Also, how would these thread groups interact with the existing threaded RTS? Would the existing features still be available without additional effort? Would they be implemented on top of these thread families? I'm not quite convinced that the thread families approach would be worth the additional complexity. What would it be used for? * To protect OpenGL operations, it would perhaps be useful to introduce a mechanism forbidding to switch between members of a family between a critical section. (I don't know what do a context switch between a glBegin and glEnd). We already have MVars, they can be used for things like that. Can anybody else think of reasons why we should need a more complicated design where threads are put into different "families" or "groups", where each thread group executes in exactly one OS thread? This has been proposed at least twice now, but I fail to see the advantages (it looks more flexible, but what's it _for_?). Some disadvantages of a thread groups approach are: *) More complexity. *) Foreign calls will block other threads in the same group. *) It would be even less meaningful for a haskell implementation that always uses OS threads --- the native/green threads proposal could be implemented as a no-op (forkNativeThread = forkIO) without breaking programs that use it. Somebody else please fill in the advantages. Cheers, Wolfgang ___ Glasgow-haskell-users mailing list [EMAIL PROTECTED] http://www.haskell.org/mailman/listinfo/glasgow-haskell-users
Re: Native Threads in the RTS
Hello, I read your proposal. It's great but I have a few remarks : * I think that, if it is not too much complicated, it could be great to put many threads in the OpenGL OS thread. The goal of concurrent Haskell was to allow concurrency for expressivity. It would be a pity to lose this in part of programs for technical reason. Having this possibility would also be a pro this language : Haskell would be the only language to have safe multithreaded OpenGL programming. *Another problem can raise : if one render in two different OpenGL windows, he may want to use different threads for these rendering. However, this is impossible for the moment because it would implies that user threads know when a switch has occurred to a thread rendering in another context and swap OpenGL context. This implies a notion of either : allowing to execute arbitrary code on switch ; either introducing a notion of "family" of threads. When a switch occurs to a member of a family different of the last member of the family executed , some user defined code should be executed (in that case the code perform a context switch). family and members of family would be defined by user. It seems that family and OS threads are independent : it could either be multiple OS threads for a family or multiple families for an OS threads. I think a thread could be member of multiple families (even if I can't see pertinent example so far). I also think that multiple threads can be the same member of a family (multiple threads drawing in the same window). * A simple way of introducing these new notions (family, members, OS threads) would be to define them as first class value. This would ease the problem of callback : an OpenGL callback would simply be a call to an operator telling the OpenGL thread to execute really the callback. "threadsafe" could be a short hand for wrapping a callback in a call to the thread currently executing (at time of the call to threadsafe function) and give it to extern function. * To protect OpenGL operations, it would perhaps be useful to introduce a mechanism forbidding to switch between members of a family between a critical section. (I don't know what do a context switch between a glBegin and glEnd). I don't know if my proposal is pertinent but it addresses some problems that would arise. It's quite complicated but i think that there is no overcost for people who don't need using it. Best regards, Nicolas Oury ___ Glasgow-haskell-users mailing list [EMAIL PROTECTED] http://www.haskell.org/mailman/listinfo/glasgow-haskell-users
Re: Native Threads in the RTS
Great, thanks. I hope you'll keep it up to date so that by the time the discussion converges it can serve as a specification and rationale. We can put it in CVS too... Simon will think of where! Until then, I'll play the role of a "human CVS server". Ultimately it'd be worth integrating with http://www.cse.unsw.edu.au/~chak/haskell/ghc/comm/rts-libs/multi- thread. html Of course. Some parts should be part of the user documentation, while others should probably be considered implentation details. | A foreign exported | callback that is called from C code executing in that OS thread is | executed in the native haskell thread. This is the bit I don't understand. Is the only scenario you have in mind here native Haskell thread calls C which calls Haskell and you want all that in the same native thread? Yes, exactly. What about this? native Haskell thread calls C which installs a pointer to a foreign-exported Haskell function in some C data structure Later... some other Haskell thread calls C which waits for an event which calls the callback So the callback was installed by a native thread, but won't be executed by it. Is that ok? Definitely. It's the same way it works in C. What thread some code executes in depends on what thread the code is called from. Anyway I think it would be worth explaining what is guaranteed a bit more clearly. I'm not sure how... to me it looks like I already specified this exactly ;-). Anyway, I've added some examples to the proposal to clarify what I mean. | If a "green" haskell thread enters a foreign imported function marked | as "safe", all other green threads are blocked. Native haskell threads | continue to run in their own OS threads. No, I don't think so. The reason that 'safe' is cheaper than 'threadsafe' is that the current worker OS thread does not need to release the Big Lock it holds on the Haskell heap, thereby allowing other green threads to run. Instead, it holds the lock, executes the call, and returns. At least I think this is the idea, but it's all jolly slippery. I thought that was "unsafe"? The "safe" version still does quite a lot (after all, a callbacks are allowed, so is GC). In addition, "threadsafe" may start a new OS thread in order to keep executing green threads. On the other hand, we might simply leave it unspecified: If people want to know what happens to other threads, they should use "threadsafe" or "unsafe". The exact behaviour of "safe" seems to be an implementation detail. | Other things I'm not sure about: Presumably if a native thread spawns a thread using forkIO, it gets just a green thread? If it used forkNativeThread it gets a distinct native thread. Better say this. "The main program and all haskell threads forked using forkIO are green threads. Threads forked using forkNativeThread :: IO () -> IO () are native threads." I thought that was clear enough... I've added a note. Cheers, Wolfgang * Native Threads Proposal, version 2 Some "foreign" libraries (for example OpenGL) rely on a mechanism called thread-local storage. The meaning of an OpenGL call therefore usually depends on which OS thread it is called from. Therefore, some kind of direct mapping from Haskell threads to OS threads is necessary in order to use the affected foreign libraries. Executing every haskell thread in its own OS thread is not feasible for performance reasons. However, perfomance of native OS threads is not too bad as long as there aren't too many, so I propose that some threads get their own OS threads, and some don't: Every Haskell Thread can be either a "green" thread or a "native" thread. For each "native" thread, there is exactly one OS thread created by the RTS. For a green thread, it is unspecified which OS thread it is executed in. The main program and all haskell threads forked using forkIO are green threads. Threads forked using forkNativeThread :: IO () -> IO () are native threads. (Note: The type of the current haskell thread does _not_ matter when forking new threads) Execution of a green thread might move from one OS thread to another at any time. A "green" thread is never executed in an OS thread that is reserved for a "native" thread. A "native" haskell thread and all foreign imported functions that it calls are executed in its associated OS thread. A foreign exported callback that is called from C code executing in that OS thread is executed in the native haskell thread. A foreign exported callback that is called from C code executing in an OS thread that is not associated with a "native" haskell thread is executed in a new green haskell thread. Only one OS thread can execute Haskell code at any given time. If a "native" haskell thread enters a foreign imported function that is marked as "safe" or "threadsafe", all other Haskell threads keep running. If the imported function is marked as "unsafe", no other
RE: Native Threads in the RTS
| I've now written up a slightly more formal proposal for native threads. | (OK, it's only a tiny bit more formal...) | I doubt I have explained everything clearly, please tell me which | points are unclear. And of course please tell me what you like/don't | like about it. Great, thanks. I hope you'll keep it up to date so that by the time the discussion converges it can serve as a specification and rationale. We can put it in CVS too... Simon will think of where! Ultimately it'd be worth integrating with http://www.cse.unsw.edu.au/~chak/haskell/ghc/comm/rts-libs/multi-thread. html Simon | A "native" haskell thread and all foreign imported functions that it | calls are executed in its associated OS thread. This part is ok | A foreign exported | callback that is called from C code executing in that OS thread is | executed in the native haskell thread. This is the bit I don't understand. Is the only scenario you have in mind here native Haskell thread calls C which calls Haskell and you want all that in the same native thread? What about this? native Haskell thread calls C which installs a pointer to a foreign-exported Haskell function in some C data structure Later... some other Haskell thread calls C which waits for an event which calls the callback So the callback was installed by a native thread, but won't be executed by it. Is that ok? Anyway I think it would be worth explaining what is guaranteed a bit more clearly. | If a "green" haskell thread enters a foreign imported function marked | as "safe", all other green threads are blocked. Native haskell threads | continue to run in their own OS threads. No, I don't think so. The reason that 'safe' is cheaper than 'threadsafe' is that the current worker OS thread does not need to release the Big Lock it holds on the Haskell heap, thereby allowing other green threads to run. Instead, it holds the lock, executes the call, and returns. At least I think this is the idea, but it's all jolly slippery. | Other things I'm not sure about: Presumably if a native thread spawns a thread using forkIO, it gets just a green thread? If it used forkNativeThread it gets a distinct native thread. Better say this. ___ Glasgow-haskell-users mailing list [EMAIL PROTECTED] http://www.haskell.org/mailman/listinfo/glasgow-haskell-users
Re: Native Threads in the RTS
I've now written up a slightly more formal proposal for native threads. (OK, it's only a tiny bit more formal...) I doubt I have explained everything clearly, please tell me which points are unclear. And of course please tell me what you like/don't like about it. I have some rough ideas on how to implement the proposal. I would be ready to invest some time, but I don't have enough free time to make any promises here. The discussion has to be finished first, anyway. Cheers, Wolfgang *** Native Threads Proposal, version 1 Some "foreign" libraries (for example OpenGL) rely on a mechanism called thread-local storage. The meaning of an OpenGL call therefore usually depends on which OS thread it is called from. Therefore, some kind of direct mapping from Haskell threads to OS threads is necessary in order to use the affected foreign libraries. Executing every haskell thread in its own OS thread is not feasible for performance reasons. However, perfomance of native OS threads is not too bad as long as there aren't too many, so I propose that some threads get their own OS threads, and some don't: Every Haskell Thread can be either a "green" thread or a "native" thread. For each "native" thread, there is exactly one OS thread created by the RTS. For a green thread, it is unspecified which OS thread it is executed in. The main program and all haskell threads forked using forkIO are green threads. Threads forked using forkNativeThread :: IO () -> IO () are native threads. Execution of a green thread might move from one OS thread to another at any time. A "green" thread is never executed in an OS thread that is reserved for a "native" thread. A "native" haskell thread and all foreign imported functions that it calls are executed in its associated OS thread. A foreign exported callback that is called from C code executing in that OS thread is executed in the native haskell thread. A foreign exported callback that is called from C code executing in an OS thread that is not associated with a "native" haskell thread is executed in a new green haskell thread. Only one OS thread can execute Haskell code at any given time. If a "native" haskell thread enters a foreign imported function that is marked as "safe" or "threadsafe", all other Haskell threads keep running. If the imported function is marked as "unsafe", no other threads are executed until the call finishes. If a "green" haskell thread enters a foreign imported function marked as "threadsafe", a new OS thread is spawned that keeps executing other green haskell threads while the foreign function executes. Native haskell threads continue to run in their own OS threads. If a "green" haskell thread enters a foreign imported function marked as "safe", all other green threads are blocked. Native haskell threads continue to run in their own OS threads. If the imported function is marked as "unsafe", no other threads are executed until the call finishes. Finalizers are always run in green threads. Issues deliberately not addressed in this proposal: Some people may want to run several Haskell threads in a dedicated OS thread (this is what has been called "thread groups" before). Some people may want to run finalizers in specific OS threads (are finalizers predictable enough for this to be useful?). Everyone would want SMP if it came for free (but SMP seems to be too hard to do at the moment...) Other things I'm not sure about: What should we do get if a foreign function spawns a new OS thread and executes a haskell callback in that OS thread? Should a new native haskell thread that executes in the OS thread be created? Should the new OS thread be blocked and the callback executed in a green thread? What does the current threaded RTS do? (I assume the non-threaded RTS will just crash?) ___ Glasgow-haskell-users mailing list [EMAIL PROTECTED] http://www.haskell.org/mailman/listinfo/glasgow-haskell-users
Re: Native Threads in the RTS
Hello, Le mardi 19 novembre 2002, à 01:28 , Wolfgang Thaller a écrit : Nicolas Oury wrote: I don't know if what I say is pertinent, but there was another problem that was discussed in the thread about threaded RTS. One may want to use a finalizer in a particular thread. For example, a finalizer that put make a rotating cube on screen must be ran in the same thread as the Opengl/GLUT things... Good point. That feature won't be covered by my first proposal (As I said, I'll write up a proper document about that ASAP, that is, as soon as I find an entire hour of free time). It sounds useful at first, but I'm not that sure about it: after all, we can't rely on when the finalizer will be executed: the thread might no longer be around, and the GLUT window might be long closed. We should definitely think about it a little more, though. These problems always appears with finalizer. An example (maybe a bit strange but) : one can want to close a window when the program can't reach it anymore. It may sound more realistic if it is closing an unreachable database with a databasse library made for one thread only... I don't know if it is planned but I think it could be great to be able to have, in the new OS thread for OpenGL, an "expressivity only" concurrence system. I mean that to be able to fork user threads that are executed in the new OS thread. These new threads would be blocked on other threads in that kernel thread blocked, but can all access to this library, and will make programming easier. This sounds a lot like the "thread group" idea that somebody had when we last discussed this. I think it gives us added flexibility at the cost of more difficult implementation and the danger of accidentally blocking OS threads [it might be just yet another source of bugs]. It is not bad that threads working in the OpenGL world are blocked when OpenGL can't receive orders. The user would see new OS thread as a thread for a kind of group : group of people using OpenGL, are blocked wwhen OpenGl blocks. Think again of other example : imagine the glorious haskell web server using a database library allowing only one thread access. One can't write all the request in only one thread, the programmer will have to add a monothreaded layer that serve requests from other threads that are preparing pages with database datas. I don't know if that library (database monothread) exits but a good exercise would be to all try to find example library relevant to this problem. I can start adding a small example : SDL, which allows to manage every low level parts of 2D games and all that isn't OpenGl in an OpenGl game. I have a small and dirty binder to SDL, and in SDL one have to use the same thread for pumping events (asking what have be done), than the one which was use to open video window !!! A program would here be far better organize if multithreaded is allowed in one thread... With that kind of problem, having a way to program multithreaded and run monothread is a power. As there already is user level threads, it would be a pity to lose that. I'll first write up something in order to explain/accurately define the simple solution I proposed. After that, we can still design a more complex solution that addresses these two issues. Great, Best regards, Nicolas Oury Cheers, Wolfgang Thaller ___ Glasgow-haskell-users mailing list [EMAIL PROTECTED] http://www.haskell.org/mailman/listinfo/glasgow-haskell-users ___ Glasgow-haskell-users mailing list [EMAIL PROTECTED] http://www.haskell.org/mailman/listinfo/glasgow-haskell-users
Re: Native Threads in the RTS
Nicolas Oury wrote: I don't know if what I say is pertinent, but there was another problem that was discussed in the thread about threaded RTS. One may want to use a finalizer in a particular thread. For example, a finalizer that put make a rotating cube on screen must be ran in the same thread as the Opengl/GLUT things... Good point. That feature won't be covered by my first proposal (As I said, I'll write up a proper document about that ASAP, that is, as soon as I find an entire hour of free time). It sounds useful at first, but I'm not that sure about it: after all, we can't rely on when the finalizer will be executed: the thread might no longer be around, and the GLUT window might be long closed. We should definitely think about it a little more, though. I don't know if it is planned but I think it could be great to be able to have, in the new OS thread for OpenGL, an "expressivity only" concurrence system. I mean that to be able to fork user threads that are executed in the new OS thread. These new threads would be blocked on other threads in that kernel thread blocked, but can all access to this library, and will make programming easier. This sounds a lot like the "thread group" idea that somebody had when we last discussed this. I think it gives us added flexibility at the cost of more difficult implementation and the danger of accidentally blocking OS threads [it might be just yet another source of bugs]. I'll first write up something in order to explain/accurately define the simple solution I proposed. After that, we can still design a more complex solution that addresses these two issues. Cheers, Wolfgang Thaller ___ Glasgow-haskell-users mailing list [EMAIL PROTECTED] http://www.haskell.org/mailman/listinfo/glasgow-haskell-users
Re: Native Threads in the RTS
I don't know if it is planned but I think it could be great to be able to have, in the new OS thread for OpenGL, an "expressivity only" concurrence system. I mean that to be able to fork user threads that are executed in the new OS thread. These new threads would be blocked on other threads in that kernel thread blocked, but can all access to this library, and will make programming easier. Best regards, Nicolas Oury Le vendredi 15 novembre 2002, à 06:02 , Wolfgang Thaller a écrit : Hello All, A while ago there was a discussion on the shortcomings of the threaded RTS (in short, it doesn't work with foreign APIs that use thread-local state, and that breaks HOpenGL). Back then, it was decided to just keep the threaded RTS off by default and to do something about it some time after 5.04. I believe it's time to think about it again, so I'll take the liberty of proposing an extension to the RTS that might solve the problem. I propose adding something like forkNativeThread :: IO () -> IO () which forks a new Haskell thread that has its own OS thread to execute in. Note that the fact that only one Haskell thread may execute at a time remains unchanged. Whenever the scheduler determines that a "native" haskell thread is next, it sends the OS worker thread to sleep and wakes up the OS thread corresponding to the "native" haskell thread. When the "native" haskell thread yields again, so does the corresponding OS thread. Foreign calls from "normal" (non-native) haskell threads should be handled in exactly the same way as they are currently. If a callback is entered and the current OS thread corresponds to a native haskell thread, the callback should be executed in the current OS thread. Other haskell threads continue to run in the worker thread or in their own dedicated OS thread. Programs that don't use forkNativeThread won't be affected by the change. Thread switching to and from native threads will be slower, but not painfully slow. Wrapping an entire HOpenGL program in forkNativeThread should solve the OpenGL/GLUT thread-local-state problem, for example, and who knows what else it is good for. Any comments? Opinions? Wolfgang ___ Glasgow-haskell-users mailing list [EMAIL PROTECTED] http://www.haskell.org/mailman/listinfo/glasgow-haskell-users ___ Glasgow-haskell-users mailing list [EMAIL PROTECTED] http://www.haskell.org/mailman/listinfo/glasgow-haskell-users
Re: Native Threads in the RTS
I don't know if what I say is pertinent, but there was another problem that was discussed in the thread about threaded RTS. One may want to use a finalizer in a particular thread. For example, a finalizer that put make a rotating cube on screen must be ran in the same thread as the Opengl/GLUT things... Best regards, Nicolas Oury Le vendredi 15 novembre 2002, à 06:02 , Wolfgang Thaller a écrit : I propose adding something like forkNativeThread :: IO () -> IO () which forks a new Haskell thread that has its own OS thread to execute in. Note that the fact that only one Haskell thread may execute at a time remains unchanged. Whenever the scheduler determines that a "native" haskell thread is next, it sends the OS worker thread to sleep and wakes up the OS thread corresponding to the "native" haskell thread. When the "native" haskell thread yields again, so does the corresponding OS thread. Foreign calls from "normal" (non-native) haskell threads should be handled in exactly the same way as they are currently. If a callback is entered and the current OS thread corresponds to a native haskell thread, the callback should be executed in the current OS thread. Other haskell threads continue to run in the worker thread or in their own dedicated OS thread. Programs that don't use forkNativeThread won't be affected by the change. Thread switching to and from native threads will be slower, but not painfully slow. Wrapping an entire HOpenGL program in forkNativeThread should solve the OpenGL/GLUT thread-local-state problem, for example, and who knows what else it is good for. Any comments? Opinions? Wolfgang ___ Glasgow-haskell-users mailing list [EMAIL PROTECTED] http://www.haskell.org/mailman/listinfo/glasgow-haskell-users ___ Glasgow-haskell-users mailing list [EMAIL PROTECTED] http://www.haskell.org/mailman/listinfo/glasgow-haskell-users
RE: Native Threads in the RTS
> We can't currently allow several Haskell threads to really run > simultaneosly [e.g. on two separate processors, or preemtively > scheduled on a single processor], because they always mutate the same > global heap. Currently, GHC switches its green threads only at times > when the heap is in a defined state [not truly preemptively]. There > seems to be some SMP support in the RTS, I don't know if it ever > worked. If anyone wants to fix/finish it, that would be > great, but it's not what I'm proposing here. The SMP support is an experiment that was never finished. There are serious issues to be solved regarding reducing the locking overhead on a shared-memory heap. > My proposal is only a minimum solution intended to resolve > the inherent > incompatibility between the "threaded RTS" and libraries like OpenGL, > which require thread-local-state. I think I'm happy with that, although I don't have the whole context swapped in. That seems to be the conclusion we came to at the last discussion, though: http://www.haskell.org/pipermail/glasgow-haskell-users/2002-June/003592. html Cheers, Simon ___ Glasgow-haskell-users mailing list [EMAIL PROTECTED] http://www.haskell.org/mailman/listinfo/glasgow-haskell-users
RE: Native Threads in the RTS
> I'm still unconvinced that the current optional > RTS support for mixed green/native threads is the right way > to go. It looks to > me like a workaround for poor OS support for really > lightweight threads. It is a workaround for the lack of truly lightweight threads at the OS level. But I don't expect that situation to change, even with the recent improvements on the Linux front. The new RedHat Linux threads folk claim to be able to create 10^5 threads in a couple of seconds, whereas we can create 10^6 threads in about that time (on an old 500MHz machine, too). Cheers, Simon ___ Glasgow-haskell-users mailing list [EMAIL PROTECTED] http://www.haskell.org/mailman/listinfo/glasgow-haskell-users
RE: Native Threads in the RTS
| I propose adding something like | | forkNativeThread :: IO () -> IO () I haven't talked to Simon about this, but it sounds possible. Three thoughts. First, before doing anything like this I'd like to ask you or someone else, or a group, to write a clear exposition of what the problem is and what the solution is, to add to the GHC user manual. (If there are implementation related questions, they can go into the Commentary.) As you say, this is a topic that we have visited regularly, and it's a slippery one, so I'd like to capture it. Second, there's the question of what it really means. In particular, what if that thread forks further (Haskell, green) threads? Are they too bound to the native thread? A library you call might in principle fork threads to get its job done... Third | If a callback is entered and the current OS thread corresponds to a | native haskell thread, the callback should be executed in the current | OS thread. | Other haskell threads continue to run in the worker thread or in their | own dedicated OS thread. I'm not sure what this means. What is the "current" OS thread? Perhaps an example? Simon ___ Glasgow-haskell-users mailing list [EMAIL PROTECTED] http://www.haskell.org/mailman/listinfo/glasgow-haskell-users
Re: Native Threads in the RTS
I wrote: > [...] Note that the fact that only one Haskell thread may execute at a > time remains unchanged. [...] Sven Panne wrote: I haven't thought very deeply about your proposal yet, but I don't understand the remark above: What about e.g. a multi-processor Solaris machine (where pthreads work as intended, [...] We can't currently allow several Haskell threads to really run simultaneosly [e.g. on two separate processors, or preemtively scheduled on a single processor], because they always mutate the same global heap. Currently, GHC switches its green threads only at times when the heap is in a defined state [not truly preemptively]. There seems to be some SMP support in the RTS, I don't know if it ever worked. If anyone wants to fix/finish it, that would be great, but it's not what I'm proposing here. My proposal is only a minimum solution intended to resolve the inherent incompatibility between the "threaded RTS" and libraries like OpenGL, which require thread-local-state. Cheers, Wolfgang ___ Glasgow-haskell-users mailing list [EMAIL PROTECTED] http://www.haskell.org/mailman/listinfo/glasgow-haskell-users
Re: Native Threads in the RTS
On Sun, 17 Nov 2002 12:23:06 +0100 Sven Panne wrote: >> Nevertheless, you make a good point: Better support for "real" >> multi-threading is definitely an area where I'd like to see some >> improvement for the next non-patchlevel release of GHC. I'm still >> unconvinced that the current optional RTS support for mixed >> green/native threads is the right way to go. It looks to me like a >> workaround for poor OS support for really lightweight threads. On Sun, Nov 17, 2002 at 11:33:44AM +, Duncan Coutts wrote: > Which of course has been improving greatly recently - on Linux at least. > The 2.6 kernel will apparently have threading on par with Solaris. In > fact, the next Linux pthreads library looks as though it will be based > on a 1:1 model rather than a M:N model because it is simpler and (with > the recent threading improvements) performs better. > So that means that all of ghc's major platforms (Solaris, Linux, Win32) > will have good OS thread support in the near future. 1:1 threading is inferior by virtue of resource scalability on 32-bit machines. This is not the final word. Bill ___ Glasgow-haskell-users mailing list [EMAIL PROTECTED] http://www.haskell.org/mailman/listinfo/glasgow-haskell-users
Re: Native Threads in the RTS
On Sun, 17 Nov 2002 12:23:06 +0100 Sven Panne <[EMAIL PROTECTED]> wrote: > Nevertheless, you make a good point: Better support for "real" > multi-threading is definitely an area where I'd like to see some > improvement for the next non-patchlevel release of GHC. I'm still > unconvinced that the current optional RTS support for mixed > green/native threads is the right way to go. It looks to me like a > workaround for poor OS support for really lightweight threads. Which of course has been improving greatly recently - on Linux at least. The 2.6 kernel will apparently have threading on par with Solaris. In fact, the next Linux pthreads library looks as though it will be based on a 1:1 model rather than a M:N model because it is simpler and (with the recent threading improvements) performs better. So that means that all of ghc's major platforms (Solaris, Linux, Win32) will have good OS thread support in the near future. Duncan ___ Glasgow-haskell-users mailing list [EMAIL PROTECTED] http://www.haskell.org/mailman/listinfo/glasgow-haskell-users
Re: Native Threads in the RTS
Wolfgang Thaller wrote: > [...] I propose adding something like > > forkNativeThread :: IO () -> IO () > > which forks a new Haskell thread that has its own OS thread to execute > in. Note that the fact that only one Haskell thread may execute at a > time remains unchanged. [...] I haven't thought very deeply about your proposal yet, but I don't understand the remark above: What about e.g. a multi-processor Solaris machine (where pthreads work as intended, not the rather poor stuff currently shipped with Linux)? In such an environment there are often multiple processors executing different threads (or LWPs, or whatever you call it) of the same process simultaneously. Perhaps I misunderstood something here... :-} Nevertheless, you make a good point: Better support for "real" multi-threading is definitely an area where I'd like to see some improvement for the next non-patchlevel release of GHC. I'm still unconvinced that the current optional RTS support for mixed green/native threads is the right way to go. It looks to me like a workaround for poor OS support for really lightweight threads. Cheers, S. ___ Glasgow-haskell-users mailing list [EMAIL PROTECTED] http://www.haskell.org/mailman/listinfo/glasgow-haskell-users
Native Threads in the RTS
Hello All, A while ago there was a discussion on the shortcomings of the threaded RTS (in short, it doesn't work with foreign APIs that use thread-local state, and that breaks HOpenGL). Back then, it was decided to just keep the threaded RTS off by default and to do something about it some time after 5.04. I believe it's time to think about it again, so I'll take the liberty of proposing an extension to the RTS that might solve the problem. I propose adding something like forkNativeThread :: IO () -> IO () which forks a new Haskell thread that has its own OS thread to execute in. Note that the fact that only one Haskell thread may execute at a time remains unchanged. Whenever the scheduler determines that a "native" haskell thread is next, it sends the OS worker thread to sleep and wakes up the OS thread corresponding to the "native" haskell thread. When the "native" haskell thread yields again, so does the corresponding OS thread. Foreign calls from "normal" (non-native) haskell threads should be handled in exactly the same way as they are currently. If a callback is entered and the current OS thread corresponds to a native haskell thread, the callback should be executed in the current OS thread. Other haskell threads continue to run in the worker thread or in their own dedicated OS thread. Programs that don't use forkNativeThread won't be affected by the change. Thread switching to and from native threads will be slower, but not painfully slow. Wrapping an entire HOpenGL program in forkNativeThread should solve the OpenGL/GLUT thread-local-state problem, for example, and who knows what else it is good for. Any comments? Opinions? Wolfgang ___ Glasgow-haskell-users mailing list [EMAIL PROTECTED] http://www.haskell.org/mailman/listinfo/glasgow-haskell-users