[Haskell-cafe] How to ensure code executes in the context of a specific OS thread?

Simon Marlow marlowsd at gmail.com
Wed Jul 6 17:51:38 CEST 2011


On 06/07/2011 16:24, Jason Dagit wrote:
> On Wed, Jul 6, 2011 at 8:09 AM, Simon Marlow<marlowsd at gmail.com>  wrote:
>> On 06/07/2011 15:42, Jason Dagit wrote:
>>>
>>> On Wed, Jul 6, 2011 at 2:23 AM, Simon Marlow<marlowsd at gmail.com>    wrote:
>>>>
>>>> On 06/07/2011 07:37, Jason Dagit wrote:
>>>>>
>>>>> On Jul 5, 2011 1:04 PM, "Jason Dagit"<dagitj at gmail.com
>>>>> <mailto:dagitj at gmail.com>>    wrote:
>>>>>   >
>>>>>   >    On Tue, Jul 5, 2011 at 12:33 PM, Ian Lynagh<igloo at earth.li
>>>>> <mailto:igloo at earth.li>>    wrote:
>>>>>   >    >    On Tue, Jul 05, 2011 at 08:11:21PM +0100, Simon Marlow wrote:
>>>>>   >    >>
>>>>>   >    >>    In GHCi it's a different matter, because the main thread is
>>>>> running
>>>>>   >    >>    GHCi itself, and all the expressions/statements typed at the
>>>>> prompt
>>>>>   >    >>    are run in forkIO'd threads (a new one for each statement, in
>>>>> fact).
>>>>>   >    >>    If you want a way to run command-line operations in the main
>>>>> thread,
>>>>>   >    >>    please submit a feature request.  I'm not sure it can be done,
>>>>> but
>>>>>   >    >>    I'll look into it.
>>>>>   >    >
>>>>>   >    >    We already have a way: -fno-ghci-sandbox
>>>>>   >
>>>>>   >    I've removed all my explicit attempts to forkIO/forkOS and passed
>>>>> the
>>>>>   >    command line flag you mention.  I just tried this but it doesn't
>>>>>   >    change the behavior in my example.
>>>>>
>>>>> I tried it again and discovered that due to an argument parsing bug in
>>>>> cabal-dev that the flag was not passed correctly. I explicitly passed it
>>>>> and verified that it works. Thanks for the workaround. By the way, I did
>>>>> look at the user guide for options like this and didn't see it. Which
>>>>> part of the manual is it in?
>>>>>
>>>>> Can I still make a feature request for a function to make code run on
>>>>> the original thread? My reasoning is that the code which needs to run on
>>>>> the main thread may appear in a library in which case the developer has
>>>>> no control over how ghc is invoked.
>>>>
>>>> I'm not sure how that would work.  The programmer is in control of what
>>>> the
>>>> main thread does, not GHC.  So in order to implement some mechanism to
>>>> run
>>>> code on the main thread, we would need some cooperation from the main
>>>> thread
>>>> itself.  For example, in gtk2hs the main thread runs an event handler
>>>> loop
>>>> which occasionally checks a queue for requests from other threads (at
>>>> least,
>>>> I think that's how it works).
>>>
>>> What I'm wrestling with is the following.  Say I make a GUI library.
>>> As author of the GUI library I discover issues like this where the
>>> library code needs to execute on the "main" thread.  Users of the
>>> library expect the typical Haskell environment where you can't tell
>>> the difference between threads, and you fork at will.  How can I make
>>> sure my library works from GHC (with arbitrary user threads) and from
>>> GHCI?
>>>
>>> As John Lato points out in his email lots of people bump into this
>>> without realizing it and don't understand what the problem is.  We can
>>> try our best to educate everyone, but I have this sense that we could
>>> also do a better job of providing primitives to make it so that code
>>> will run on the main thread regardless of how people invoke the
>>> library.
>>>
>>> In my specific case (Cocoa on OSX), it is possible for me to use some
>>> Cocoa functions to force things to run on the main thread.  From what
>>> I've read Cocoa uses pthreads to implement this. I was hoping we could
>>> expose something from the RTS code in Control.Concurrent so that it's
>>> part of an "official" Haskell API that library writers can assume.
>>>
>>> Judging by this SO question, it's easier to implement this in Haskell
>>> on top of pthreads than to implement it in C (here I'm assuming GHC's
>>> RTS uses pthreads, but I've never checked):
>>>
>>> http://stackoverflow.com/questions/6130823/pthreads-perform-function-on-main-thread
>>>
>>> In fact, the it sounds like what Gtk2hs is doing with the postGUI
>>> functions.
>>
>> Right, but usually the way this is implemented is with some cooperation from
>> the main thread.  That SO answer explains it - the main thread runs some
>> kind of loop that periodically checks for requests from other threads and
>> services them.  I expect that's how it works on Cocoa.
>> So you can't just do this from a library - the main thread has to be in on
>> the game.
>
> Yes.  From my perspective (that of a library writer) that's what makes
> this tricky in GHCi.  I need GHCi's cooperation.  From GHCi's
> perspective it's tricky too.
>
>> I suppose you might wonder whether the GHC RTS could implement
>> runInMainThread by preempting the main thread and running some different
>> code on it.
>
> Yes, that's roughly what I was wondering about.
>
>>   In theory that's possible, but whether it's a good idea or not
>> is a different matter!  I think it amounts to the same thing as the gtk2hs
>> folks have been asking for - multiple Haskell threads bound to the same OS
>> thread.
>
> I'm starting to realize that I don't understand the GHC threading
> model very well :)  I thought that was already possible.  I may be
> mixing GHC's thread model up with other language implementations, but
> I thought that it had a pool of OS threads and that Haskell threads
> ran on them as needed.  I think what you're saying is that the RTS has
> bound threads and it has thread pooling, but what it doesn't have is
> "bound thread pooling" (that is, the combination of being bound and
> pooled).
>
>>   runInMainThread then becomes the same as forking a temporary new
>> thread bound to the main OS thread, or temporarily binding the current
>> thread to the main OS thread.  If the main OS thread is off making a foreign
>> call (e.g. in the GUI library's main loop) then it can't run any other
>> Haskell threads anyway, and then I have to figure out what to do with all
>> these Haskell threads waiting for their bound OS thread to come back from
>> the foreign call.  My guess is that all this would be pretty complex to
>> implement.
>
> Yes it does sound complex.  I'd really like help as much as possible.
> I know very little about GHC internals but perhaps I could take a look
> at some of the RTS code.  Is there some background reading I could do?
>   Perhaps a specific reference to a paper or wiki page?

This is the paper that explains the design:

   http://community.haskell.org/~simonmar/papers/conc-ffi.pdf

And there's some documentation on the implementation here:

   http://hackage.haskell.org/trac/ghc/wiki/Commentary/Rts/Scheduler

though I think the latter is very incomplete.  I'd really like to flesh 
it out sometime.

Cheers,
	Simon



More information about the Haskell-Cafe mailing list