RE: [Haskell-cafe] FFI and callbacks

On 20 July 2005 14:35, John Goerzen wrote:
I'm looking at packaging an event-driven console widget set (CDK) for Haskell using FFI. I know that other event-driven widget sets have Haskell bindings, but I'm not quite sure how to make everything play nice with forkIO.
These systems generally have some sort of an opaque main loop, implemented in C. This loop would usually never return, or perhaps only return once the UI is destroyed.
Is the library thread-safe or not? I mean OS-thread safe. If it is, then you're home and dry: just compile your program with GHC's -threaded option, and any foreign calls that need to run concurrently with Haskell threads must be declared "safe" (which is the default in fact, so instead I should really advise you to mark all calls that don't need to run concurrently as "unsafe", because that's good for performance). If the library isn't thread-safe, then you're in the same boat as Gtk and wxHaskell (I believe) where there are known problems with having a multithreaded Haskell GUI app. You can only have one OS thread (and hence only one Haskell thread) doing GUI operations, and that is the thread in the main loop. You have to somehow set up a communication between your other Haskell threads and the thread running the main loop - perhaps you can send requests of type (IO ()) down a channel to the main loop thread which wakes up occasionally to run them, for example. Cheers, Simon

On Wed, Jul 20, 2005 at 04:10:38PM +0100, Simon Marlow wrote:
On 20 July 2005 14:35, John Goerzen wrote:
These systems generally have some sort of an opaque main loop, implemented in C. This loop would usually never return, or perhaps only return once the UI is destroyed.
Is the library thread-safe or not? I mean OS-thread safe. If it is, then you're home and dry: just compile your program with GHC's -threaded option, and any foreign calls that need to run concurrently with Haskell threads must be declared "safe" (which is the default in fact, so instead I should really advise you to mark all calls that don't need to run concurrently as "unsafe", because that's good for performance).
That's half of the question. The other half is: what is the canonical way of handling this mainloop that doesn't return from Haskell? Do we just treat it that way in Haskell as well, or would some people forkIO it? Does any part of your answer vary depending on whether the Haskell threads in question are forkIO threads or forkOS threads? I imagine that it might. Unfortunately, the library I'm leaning towards packaging is not thread-safe. There is another library that is, but it is written in C++, and making a Haskell binding for that is a little more than I have the skills to do at the moment.
If the library isn't thread-safe, then you're in the same boat as Gtk and wxHaskell (I believe) where there are known problems with having a multithreaded Haskell GUI app. You can only have one OS thread (and hence only one Haskell thread) doing GUI operations, and that is the
What about multiple forkIO threads?
thread in the main loop. You have to somehow set up a communication between your other Haskell threads and the thread running the main loop - perhaps you can send requests of type (IO ()) down a channel to the main loop thread which wakes up occasionally to run them, for example.
I imagine there could be exceptions to this.. For instance, perhaps a given operation needs to do 5 things, perhaps simultaneously, before displaying a result. It could, perhaps, fire off five threads and just not display a result until all five have terminated, yes? Thanks, -- John

On Wed, 2005-07-20 at 16:10 +0100, Simon Marlow wrote:
On 20 July 2005 14:35, John Goerzen wrote:
I'm looking at packaging an event-driven console widget set (CDK) for Haskell using FFI. I know that other event-driven widget sets have Haskell bindings, but I'm not quite sure how to make everything play nice with forkIO.
These systems generally have some sort of an opaque main loop, implemented in C. This loop would usually never return, or perhaps only return once the UI is destroyed.
Is the library thread-safe or not? I mean OS-thread safe. If it is, then you're home and dry: just compile your program with GHC's -threaded option, and any foreign calls that need to run concurrently with Haskell threads must be declared "safe" (which is the default in fact, so instead I should really advise you to mark all calls that don't need to run concurrently as "unsafe", because that's good for performance).
If the library isn't thread-safe, then you're in the same boat as Gtk and wxHaskell (I believe) where there are known problems with having a multithreaded Haskell GUI app.
Yep.
You can only have one OS thread (and hence only one Haskell thread) doing GUI operations, and that is the thread in the main loop.
To be more precise, they can only be acessed from one OS thread. You can use multiple Haskell threads so long as they only make GUI calls from within the main OS thread. The problem then as John noted is that the main loop of these toolkits block and so the other Haskell threads would not get a chance to schedule. So the challenge is to give the Haskell threads a chance to schedule. Most toolkits with a main loop system allow you to setup timers. In the Gtk2Hs bindings we can use this trick: -- 50ms timeout, so GHC will get a chance to scheule about 20 times a second -- which gives reasonable latency without the polling generating too much -- cpu load. timeoutAddFull (yield >> return True) priorityDefaultIdle 50 This causes the Gtk main loop to yeild to the ghc rts and give it a chance to run any runnable threads for a while. It is unfortunately a polling solution which has it's obvious disadvantages. However in practice it seems to generate negligable load when idle. The GHC rts yield function seems to be quite good about not doing much work when there is no work to be done! With this trick you can then use forkIO as much as you like and all Haskell threads can make GUI calls. We have a nice multi-threaded IRC client example, where one thread listens to incomming network traffic and updates the GUI from there (the main thread is in the Gtk main loop of course). However, this is all assuming you're using the single threaded ghc rts. If you link using -threaded then this all goes wrong. This is because with -threaded we can no longer guarantee the all the Haskell threads that want to make GUI calls will do so from the main OS thread (specifically the one that originally entered the Gtk main loop). Unfortnately the current bound threads system does not help. The current bound threads system allows you to fork a new Haskell thread bound to a *new* OS thread. This is just what you need for OpenGL. However for UI toolkits like Gtk, wxWidgets, CDK etc we need to fork a new Haskell thread bound to an *existing* OS thread. If we could do that then the existing mechanism would continue to work. To eliminate the polling and do something more satisfactory would probably require some support from the RTS to find out the event sources (file handles) and timers that would cause the RTS to wake up.
You have to somehow set up a communication between your other Haskell threads and the thread running the main loop - perhaps you can send requests of type (IO ()) down a channel to the main loop thread which wakes up occasionally to run them, for example.
I think that sending every GUI request through a pipe and across a thread boundary would be a great deal of overhead. Many GUI calls are quite fine grained. Duncan

Duncan Coutts wrote:
Most toolkits with a main loop system allow you to setup timers. In the Gtk2Hs bindings we can use this trick:
-- 50ms timeout, so GHC will get a chance to scheule about 20 times a second -- which gives reasonable latency without the polling generating too much -- cpu load. timeoutAddFull (yield >> return True) priorityDefaultIdle 50
Just for the record, above line in wxHaskell is spelled as: timer mainWindow [ interval := 50, on command := return () ] By the way, thanks for this tip! This helped me to work around showstopper bug in my program :) -- Gracjan

On 7/23/05, Duncan Coutts
On Wed, 2005-07-20 at 16:10 +0100, Simon Marlow wrote:
On 20 July 2005 14:35, John Goerzen wrote:
I'm looking at packaging an event-driven console widget set (CDK) for Haskell using FFI. I know that other event-driven widget sets have Haskell bindings, but I'm not quite sure how to make everything play nice with forkIO.
These systems generally have some sort of an opaque main loop, implemented in C. This loop would usually never return, or perhaps only return once the UI is destroyed.
Is the library thread-safe or not? I mean OS-thread safe. If it is, then you're home and dry: just compile your program with GHC's -threaded option, and any foreign calls that need to run concurrently with Haskell threads must be declared "safe" (which is the default in fact, so instead I should really advise you to mark all calls that don't need to run concurrently as "unsafe", because that's good for performance).
If the library isn't thread-safe, then you're in the same boat as Gtk and wxHaskell (I believe) where there are known problems with having a multithreaded Haskell GUI app.
Yep.
You can only have one OS thread (and hence only one Haskell thread) doing GUI operations, and that is the thread in the main loop.
To be more precise, they can only be acessed from one OS thread. You can use multiple Haskell threads so long as they only make GUI calls from within the main OS thread.
The problem then as John noted is that the main loop of these toolkits block and so the other Haskell threads would not get a chance to schedule. So the challenge is to give the Haskell threads a chance to schedule.
Most toolkits with a main loop system allow you to setup timers. In the Gtk2Hs bindings we can use this trick:
-- 50ms timeout, so GHC will get a chance to scheule about 20 times a second -- which gives reasonable latency without the polling generating too much -- cpu load. timeoutAddFull (yield >> return True) priorityDefaultIdle 50
This causes the Gtk main loop to yeild to the ghc rts and give it a chance to run any runnable threads for a while. It is unfortunately a polling solution which has it's obvious disadvantages. However in practice it seems to generate negligable load when idle. The GHC rts yield function seems to be quite good about not doing much work when there is no work to be done!
Does anyone know how wxHaskell deals with this? I mean is it safe to call wxHaskell GUI stuff from several threads at once? Initial experimentation seems to suggest it is. I wrote a simple chat client / server, and to abstract away the networking I implemented a function "talk" which just takes a handle and then maps input and output to that handle using two Chans. So I basically have two threads, one which waits for stuff to be sent out (readChan, blocking when there's nothing in it) and the other which waits for stuff coming in (hWaitForInput h (-1), and then writeChan to the "in" Chan). In addition to that I, in the client GUI, spawn of a thread which just reads the "in" channel over and over and appends whatever's coming in to the chat area. So that's three threads right there, plus the main thread. So to experiment I implemented this in wxHaskell using a timer to unblock the main loop every now and then. To make sure the performance was visible I set it at 1000 ms. Naturally it took several seconds for all the different threads to get a chance to do anything so sending messages was very slow. Then I simply recompiled with "-threaded" and everything is super fast (the timer hack isn't even necessary). I haven't found any issues with wxHaskell misbehaving when it's called from different threads, but I'd like to know for sure that it's actually honest-to-goodness thread safe. So does anyone know? /S -- Sebastian Sylvan +46(0)736-818655 UIN: 44640862

On Mon, 2005-08-22 at 15:45 +0200, Sebastian Sylvan wrote:
On 7/23/05, Duncan Coutts
wrote: On Wed, 2005-07-20 at 16:10 +0100, Simon Marlow wrote:
On 20 July 2005 14:35, John Goerzen wrote:
I'm looking at packaging an event-driven console widget set (CDK) for Haskell using FFI. I know that other event-driven widget sets have Haskell bindings, but I'm not quite sure how to make everything play nice with forkIO.
These systems generally have some sort of an opaque main loop, implemented in C. This loop would usually never return, or perhaps only return once the UI is destroyed.
Is the library thread-safe or not? I mean OS-thread safe. If it is, then you're home and dry: just compile your program with GHC's -threaded option, and any foreign calls that need to run concurrently with Haskell threads must be declared "safe" (which is the default in fact, so instead I should really advise you to mark all calls that don't need to run concurrently as "unsafe", because that's good for performance).
If the library isn't thread-safe, then you're in the same boat as Gtk and wxHaskell (I believe) where there are known problems with having a multithreaded Haskell GUI app.
Yep.
You can only have one OS thread (and hence only one Haskell thread) doing GUI operations, and that is the thread in the main loop.
To be more precise, they can only be acessed from one OS thread. You can use multiple Haskell threads so long as they only make GUI calls from within the main OS thread.
The problem then as John noted is that the main loop of these toolkits block and so the other Haskell threads would not get a chance to schedule. So the challenge is to give the Haskell threads a chance to schedule.
Most toolkits with a main loop system allow you to setup timers. In the Gtk2Hs bindings we can use this trick:
-- 50ms timeout, so GHC will get a chance to scheule about 20 times a second -- which gives reasonable latency without the polling generating too much -- cpu load. timeoutAddFull (yield >> return True) priorityDefaultIdle 50
This causes the Gtk main loop to yeild to the ghc rts and give it a chance to run any runnable threads for a while. It is unfortunately a polling solution which has it's obvious disadvantages. However in practice it seems to generate negligable load when idle. The GHC rts yield function seems to be quite good about not doing much work when there is no work to be done!
Does anyone know how wxHaskell deals with this? I mean is it safe to call wxHaskell GUI stuff from several threads at once? Initial experimentation seems to suggest it is.
It may appear so at first and then mysteriously fail. I don't think wx is thread safe (since the underlying gui libs are not thread safe either). I don't believe that wx does it's own per-widget locking, but I may be wrong. Here's a bit from the wx manual: http://www.wxwidgets.org/manuals/2.4.2/wx494.htm "If you do decide to use threads in your application, it is strongly recommended that no more than one thread calls GUI functions. The thread sample shows that it is possible for many different threads to call GUI functions at once (all the threads created in the sample access GUI), but it is a very poor design choice for anything except an example. The design which uses one GUI thread and several worker threads which communicate with the main one using events is much more robust and will undoubtedly save you countless problems (example: under Win32 a thread can only access GDI objects such as pens, brushes, &c created by itself and not by the other threads)."
I wrote a simple chat client / server, and to abstract away the networking I implemented a function "talk" which just takes a handle and then maps input and output to that handle using two Chans. So I basically have two threads, one which waits for stuff to be sent out (readChan, blocking when there's nothing in it) and the other which waits for stuff coming in (hWaitForInput h (-1), and then writeChan to the "in" Chan). In addition to that I, in the client GUI, spawn of a thread which just reads the "in" channel over and over and appends whatever's coming in to the chat area.
So that's three threads right there, plus the main thread. So to experiment I implemented this in wxHaskell using a timer to unblock the main loop every now and then. To make sure the performance was visible I set it at 1000 ms. Naturally it took several seconds for all the different threads to get a chance to do anything so sending messages was very slow. Then I simply recompiled with "-threaded" and everything is super fast (the timer hack isn't even necessary).
I haven't found any issues with wxHaskell misbehaving when it's called from different threads, but I'd like to know for sure that it's actually honest-to-goodness thread safe. So does anyone know?
So you can do this stuff when not using "-threaded" however when using "-threaded" you are using multiple OS threads and you should heed the advice from the wx manual above (ie don't do it). Actually as noted above, some wx backend (win32) have even stricter requirements for threads than others (Gtk+). Win32 does not even allow you to access drawing objects from threads which did not create them rather than simple not allowing concurrent access (as in Gtk+). Duncan

On Mon, 2005-08-22 at 15:45 +0200, Sebastian Sylvan wrote:
I haven't found any issues with wxHaskell misbehaving when it's called from different threads, but I'd like to know for sure that it's actually honest-to-goodness thread safe. So does anyone know?
Actually here's an even more direct statement. From: http://www.wxwidgets.org/whychoos.htm Multithreading Like many frameworks, wxWidgets isn't 'thread-safe' in the sense that the programmer can use GUI code indiscriminately from threads, but it does have a range of thread and mutex classes for the careful and more ambitious programmer. These classes are under development. Unfortunately, when using wxHaskell (or indeed Gtk2Hs) with -threaded, this is exactly what's happening "using GUI code indiscriminately from OS threads". Which is why we need some better solution. Duncan

On 8/22/05, Duncan Coutts
On Mon, 2005-08-22 at 15:45 +0200, Sebastian Sylvan wrote:
I haven't found any issues with wxHaskell misbehaving when it's called from different threads, but I'd like to know for sure that it's actually honest-to-goodness thread safe. So does anyone know?
Actually here's an even more direct statement. From:
http://www.wxwidgets.org/whychoos.htm
Multithreading
Like many frameworks, wxWidgets isn't 'thread-safe' in the sense that the programmer can use GUI code indiscriminately from threads, but it does have a range of thread and mutex classes for the careful and more ambitious programmer. These classes are under development.
Unfortunately, when using wxHaskell (or indeed Gtk2Hs) with -threaded, this is exactly what's happening "using GUI code indiscriminately from OS threads".
Which is why we need some better solution.
Hmm... Perhaps some operations are thread safe? It would seem that there's no real reason for why "appendText" couldn't be thread-safe (maybe it just triggers an event for the control which is then handled by the event-system on the C-side). It certainly does seem that in this particular case it does work. It would be nice to know exactly when it works, and exactly when it won't. I want my forkIO's dammit! Using a timer to yield every 20 ms may work fine for an app with just one or two threads, but for each thread you spawn you potentially add 20 ms latency to other threads which quickly becomes unacceptable. It's especially troublesome when the number of threads varies, cause then you'll have to prioritize between excessive polling or too high latency... /S -- Sebastian Sylvan +46(0)736-818655 UIN: 44640862

On Mon, 2005-08-22 at 18:13 +0200, Sebastian Sylvan wrote:
On 8/22/05, Duncan Coutts
wrote: On Mon, 2005-08-22 at 15:45 +0200, Sebastian Sylvan wrote:
I haven't found any issues with wxHaskell misbehaving when it's called from different threads, but I'd like to know for sure that it's actually honest-to-goodness thread safe. So does anyone know?
Actually here's an even more direct statement. From:
http://www.wxwidgets.org/whychoos.htm
Multithreading
Like many frameworks, wxWidgets isn't 'thread-safe' in the sense that the programmer can use GUI code indiscriminately from threads, but it does have a range of thread and mutex classes for the careful and more ambitious programmer. These classes are under development.
Unfortunately, when using wxHaskell (or indeed Gtk2Hs) with -threaded, this is exactly what's happening "using GUI code indiscriminately from OS threads".
Which is why we need some better solution.
Hmm... Perhaps some operations are thread safe? It would seem that there's no real reason for why "appendText" couldn't be thread-safe (maybe it just triggers an event for the control which is then handled by the event-system on the C-side). It certainly does seem that in this particular case it does work. It would be nice to know exactly when it works, and exactly when it won't.
I don't think this is a very profitable approach. Many operations may seem to work on most platforms however that doesn't really help us in general. For example consider your appendText exmaple. Suppose I'm using Windows. I create a text widget in OS thread A. Now I use appendText in thread B. If it does relayed repainging then you might be ok, if it does immediate repointing then it'll try to use GDI objects in thread B that were created in thread A. Even if it does use delayed rendering (in which case it'll be re-rendered in thread A) you have the clasic problem of concurrently modifying some object. Suppose you're using appendText in two Haskell threads, then potentially they may be in two OS threads and you could end up concurrently modifying the text widget's text buffer object. This may work or it may corrupt the heap and segfault. The point is, GUIs are complex libs that need to use propper locking (in the case of wx on gtk) against concurrent modification or simply canot be used cocurrently at all (in the case of drawing operations with wx on win32).
I want my forkIO's dammit!
Me too!
Using a timer to yield every 20 ms may work fine for an app with just one or two threads, but for each thread you spawn you potentially add 20 ms latency to other threads which quickly becomes unacceptable. It's especially troublesome when the number of threads varies, cause then you'll have to prioritize between excessive polling or too high latency...
A propper solution is to do something at the the wxHaskell/Gtk2Hs library level to allow Haskell threads to be used freely. Personally I think this will require more help from the Haskell runtime system. However there are other techniques that have to be tried first. Duncan
participants (5)
-
Duncan Coutts
-
Gracjan Polak
-
John Goerzen
-
Sebastian Sylvan
-
Simon Marlow