native threads vs. -threaded

I have been working on a Haskell interface to the platform API for Haiku (was BeOS.) It's C++, but the interesting thing at the moment is the use of threads - a UI window gets its own thread, and whatever Haskell code will be executed by callbacks from that thread. So it was surprising when this turned out to be incompatible with the -threaded link option. With that option, I get one callback from a non-main thread, and then that native thread will die, shortly after return from the callback. Results without -threaded are not really so good either (the application may run and work for a while, but inevitably fail with various errors that I suppose might be expected), so ... what do my threads need, to make -threaded work? The callbacks are `foreign "wrapper"' functions, which means rts_lock() is already getting called. It looks to me like that should work the same as if my thread had been invoked via forkOS, true? Is there anything else that I missed, that needs to be done to set the thread up for GHC? (I had been thinking this would not be a unique situation, rather there would be several other GUI toolkits out there that use threads in this obvious way, but after a brief review of the ones I usually hear about, not so sure. If there's another library that uses OS threads this way, with Haskell bindings already, that might be something I could steal a clue from.) thanks! Donn Cave, donn@avvanta.com

On 12/03/10 16:38, Donn Cave wrote:
I have been working on a Haskell interface to the platform API for Haiku (was BeOS.) It's C++, but the interesting thing at the moment is the use of threads - a UI window gets its own thread, and whatever Haskell code will be executed by callbacks from that thread.
So it was surprising when this turned out to be incompatible with the -threaded link option. With that option, I get one callback from a non-main thread, and then that native thread will die, shortly after return from the callback.
You'll need to elaborate a little. When you say you "get one callback from a non-main thread", are you saying that the external C++ code makes a call to a Haskell function? Was it Haskell that called C++ in the first place? What do you mean by a non-main thread? Why is the native thread dieing? You said a UI window gets its own thread - who creates that thread? If the app has more than one window, does each window get a different thread? Cheers, Simon
Results without -threaded are not really so good either (the application may run and work for a while, but inevitably fail with various errors that I suppose might be expected), so ... what do my threads need, to make -threaded work?
The callbacks are `foreign "wrapper"' functions, which means rts_lock() is already getting called. It looks to me like that should work the same as if my thread had been invoked via forkOS, true? Is there anything else that I missed, that needs to be done to set the thread up for GHC?
(I had been thinking this would not be a unique situation, rather there would be several other GUI toolkits out there that use threads in this obvious way, but after a brief review of the ones I usually hear about, not so sure. If there's another library that uses OS threads this way, with Haskell bindings already, that might be something I could steal a clue from.)

Quoth Simon Marlow
So it was surprising when this turned out to be incompatible with the -threaded link option. With that option, I get one callback from a non-main thread, and then that native thread will die, shortly after return from the callback.
You'll need to elaborate a little. When you say you "get one callback from a non-main thread", are you saying that the external C++ code makes a call to a Haskell function?
Yes.
Was it Haskell that called C++ in the first place?
Yes.
What do you mean by a non-main thread? Why is the native thread dieing?
By main thread I mean the original thread spawned by the process creation; the thread spawned by the foreign library window code is a non-main thread. I wish I knew why it dies! Without -threaded, I do get tracebacks from the various and sundry stack corruptions and whatever eventually occurs, but with -threaded, death is quick and silent. And, as far as I can tell, it happens in the foreign library code, not while executing a callback. The same type of callback works fine in the main thread (this API uses the same dispatch loop for the application itself, but it just doesn't spawn a new thread in that case.)
You said a UI window gets its own thread - who creates that thread? If the app has more than one window, does each window get a different thread?
Yes, each window runs its own thread. If it helps to have names, the BWindow::Show function spawns the thread, and from there its event loop calls virtual functions in the BWindow and BView classes that the application may override. That's where control goes back to the Haskell application, via foreign "wrapper" functions. But of course all that is perhaps unnecessary elaboration. The key points are, threads of foreign origin, with callbacks to Haskell foreign "wrapper" functions. Does the wrapper rts_lock() account for everything, or do threads need some initial setup I need to account for? Thanks! Donn Cave, donn@avvanta.com

On 13/03/2010 22:54, Donn Cave wrote:
Quoth Simon Marlow
, ... So it was surprising when this turned out to be incompatible with the -threaded link option. With that option, I get one callback from a non-main thread, and then that native thread will die, shortly after return from the callback.
You'll need to elaborate a little. When you say you "get one callback from a non-main thread", are you saying that the external C++ code makes a call to a Haskell function?
Yes.
Was it Haskell that called C++ in the first place?
Yes.
What do you mean by a non-main thread? Why is the native thread dieing?
By main thread I mean the original thread spawned by the process creation; the thread spawned by the foreign library window code is a non-main thread. I wish I knew why it dies! Without -threaded, I do get tracebacks from the various and sundry stack corruptions and whatever eventually occurs, but with -threaded, death is quick and silent. And, as far as I can tell, it happens in the foreign library code, not while executing a callback. The same type of callback works fine in the main thread (this API uses the same dispatch loop for the application itself, but it just doesn't spawn a new thread in that case.)
It is expected that you'll get problems without -threaded, because -threaded is needed to handle callbacks from different OS threads. Are you using threads in your Haskell code at all? Do you know how bound threads work in GHC? (I'm only asking because if you're already familiar with this stuff I don't need to explain it :-). I suggest the next thing to do is to find out why the thread is dieing.
You said a UI window gets its own thread - who creates that thread? If the app has more than one window, does each window get a different thread?
Yes, each window runs its own thread. If it helps to have names, the BWindow::Show function spawns the thread, and from there its event loop calls virtual functions in the BWindow and BView classes that the application may override. That's where control goes back to the Haskell application, via foreign "wrapper" functions.
But of course all that is perhaps unnecessary elaboration. The key points are, threads of foreign origin, with callbacks to Haskell foreign "wrapper" functions. Does the wrapper rts_lock() account for everything, or do threads need some initial setup I need to account for?
Nope, as long as the RTS is initialised properly via hs_init() you should be able to make callbacks from any OS thread. Cheers, Simon

Quoth Simon Marlow
... Does the wrapper rts_lock() account for everything, or do threads need some initial setup I need to account for?
Nope, as long as the RTS is initialised properly via hs_init() you should be able to make callbacks from any OS thread.
Thanks - I'm sorry to hear I'm doing everything right! Donn Cave, donn@avvanta.com
participants (2)
-
Donn Cave
-
Simon Marlow