xmobar-0.7rc1 testers needed

Hi, today I added XEvents handling to xmobar, a status bar you should know I'm writing. Now, this is more difficult of what I first thought, since xmobar makes heavy use of Haskell threads. Since we need to call XNextEvent, it seems, as far as I can understand, that this is going to block every other Haskell threads, unless the threaded RTS is used and/or (?) forkOS (which requires anyway the threaded RTS) is used instead of forkIO. While this is working fine on my system, I have a system with an old Xorg build (I cannot compile X11-1.2.2 and X11-extras on that machine), which seem to block all threads no matter what I do. This is not a valuable test for me, so I need testers to confirm or refute my personal test. Here you can grab the source, which now requires x11-extras (I think that 0.2 should go, but I did not check: please let me know if you find out): http://gorgias.mine.nu/xmobar/xmobar-0.7rc1.tar.gz If no tester will show up, well, no problem: no refreshing xmobar will be released....;-) ciao andrea

On Tuesday 17 July 2007 12:27:38 Andrea Rossato wrote:
Hi,
today I added XEvents handling to xmobar, a status bar you should know I'm writing.
Now, this is more difficult of what I first thought, since xmobar makes heavy use of Haskell threads.
Since we need to call XNextEvent, it seems, as far as I can understand, that this is going to block every other Haskell threads, unless the threaded RTS is used and/or (?) forkOS (which requires anyway the threaded RTS) is used instead of forkIO.
Here is the relevant source from X11: foreign import ccall safe "HsXlib.h XNextEvent" nextEvent :: Display -> XEventPtr -> IO () The "safe" bit means that the FFI call will run in it's own OS thread -- it shouldn't block any Haskell threads. However, I believe that Xlib has internal locking that will cause XNextEvent to block all other Xlib calls. If forkOS changes the behavior here, we most likely have a mismarked "unsafe" function in X11.
While this is working fine on my system, I have a system with an old Xorg build (I cannot compile X11-1.2.2 and X11-extras on that machine), which seem to block all threads no matter what I do. This is not a valuable test for me, so I need testers to confirm or refute my personal test.
I believe this is XNextEvent blocking other threads. I've got an idea for a solution, expect another email shortly :). Cheers, Spencer Janssen

On Tuesday 17 July 2007 12:27:38 Andrea Rossato wrote:
Hi,
today I added XEvents handling to xmobar, a status bar you should know I'm writing.
Now, this is more difficult of what I first thought, since xmobar makes heavy use of Haskell threads.
Since we need to call XNextEvent, it seems, as far as I can understand, that this is going to block every other Haskell threads, unless the threaded RTS is used and/or (?) forkOS (which requires anyway the threaded RTS) is used instead of forkIO.
While this is working fine on my system, I have a system with an old Xorg build (I cannot compile X11-1.2.2 and X11-extras on that machine), which seem to block all threads no matter what I do. This is not a valuable test for me, so I need testers to confirm or refute my personal test.
Here you can grab the source, which now requires x11-extras (I think that 0.2 should go, but I did not check: please let me know if you find out):
http://gorgias.mine.nu/xmobar/xmobar-0.7rc1.tar.gz
If no tester will show up, well, no problem: no refreshing xmobar will be released....;-)
ciao andrea
It seems to work on my machine. I have a recent Xlib (the XCB based 1.1.2). I tried replacing forkOS with forkIO, and things still seemed to work. However, removing -threaded caused serious hangs before text updates (perhaps only happening after each expose event?). Cheers, Spencer Janssen

On Tue, Jul 17, 2007 at 01:12:59PM -0500, Spencer Janssen wrote:
I tried replacing forkOS with forkIO, and things still seemed to work. However, removing -threaded caused serious hangs before text updates (perhaps only happening after each expose event?).
without -threaded I would expect that *only* an expose event would update the window (with override_redirect this means switching to a console or another X server and back, or pressing F11 with firefox). The safe call will run an OS thread only with -threaded, right? In other words, with -threaded using forkIO or forkOS makes no difference if we make a safe call. But, as you noted before, we have XNextEvent on one thread, and XSendEvent on the delayed thread (the one that will send the event to the blocked one - to XNextEvent). For this reason I think it is appropriate to use forkOS together with -threaded. It works perfectly here, but I have that strange case of that specific machine with a broken tool chain. It is a dual core (two processors are seen by the kernel) and all concurrent threads get blocked. The only way to update xmobar is to create an expose event. This is the only thing that puzzles me. And I don't have enough knowledge of all this FFI stuff (moreover mixed with concurrency -let alone the C side of the moon) to work it out. I'm afraid it is just too much for me. Thanks for you kind attention, though. Andrea BTW, I've been thinking about it, and I do not see any other possible solution for the specific problem of blocking a thread and resuming it in two different cases: an event *or* the elapsed time. You need the real event or another thread that sends a fake event. Am I right?

On Tuesday 17 July 2007 13:43:23 Andrea Rossato wrote:
On Tue, Jul 17, 2007 at 01:12:59PM -0500, Spencer Janssen wrote:
I tried replacing forkOS with forkIO, and things still seemed to work. However, removing -threaded caused serious hangs before text updates (perhaps only happening after each expose event?).
without -threaded I would expect that *only* an expose event would update the window (with override_redirect this means switching to a console or another X server and back, or pressing F11 with firefox).
The safe call will run an OS thread only with -threaded, right?
Right.
In other words, with -threaded using forkIO or forkOS makes no difference if we make a safe call.
But, as you noted before, we have XNextEvent on one thread, and XSendEvent on the delayed thread (the one that will send the event to the blocked one - to XNextEvent).
On my machine, XSendEvent and XNextEvent do not seem to block each other -- but I'm not sure whether this is the case for older versions of Xlib.
For this reason I think it is appropriate to use forkOS together with -threaded.
We should try to avoid forkOS if at all possible -- forking an OS thread requires much more memory than a lightweight Haskell thread.
It works perfectly here, but I have that strange case of that specific machine with a broken tool chain. It is a dual core (two processors are seen by the kernel) and all concurrent threads get blocked. The only way to update xmobar is to create an expose event.
This is the only thing that puzzles me. And I don't have enough knowledge of all this FFI stuff (moreover mixed with concurrency -let alone the C side of the moon) to work it out. I'm afraid it is just too much for me.
Thanks for you kind attention, though.
Andrea
BTW, I've been thinking about it, and I do not see any other possible solution for the specific problem of blocking a thread and resuming it in two different cases: an event *or* the elapsed time. You need the real event or another thread that sends a fake event. Am I right?
It is possible, but annoying. It requires a magic version of nextEvent that doesn't block inside foreign calls. Thankfully, this isn't so hard to write with threadWaitRead and XPending. With this magic nextEvent, we can use asynchronous exceptions to interrupt the thread with a timer. I've sent you a patch that implements this. The next step, I think, is to remove the 'refresh' configuration entirely -- just have plugins throw exceptions to the event/drawing thread whenever they update. Cheers, Spencer Janssen PS: xmobar is quite nice, I use it as my statusbar now.

On Tue, Jul 17, 2007 at 06:19:13PM -0500, Spencer Janssen wrote:
BTW, I've been thinking about it, and I do not see any other possible solution for the specific problem of blocking a thread and resuming it in two different cases: an event *or* the elapsed time. You need the real event or another thread that sends a fake event. Am I right?
It is possible, but annoying. It requires a magic version of nextEvent that doesn't block inside foreign calls. Thankfully, this isn't so hard to write with threadWaitRead and XPending. With this magic nextEvent, we can use asynchronous exceptions to interrupt the thread with a timer. I've sent you a patch that implements this.
I thought that having a thread send an XEvent to another thread was hackish, but your solution is the haskeller's way to hackerdom...;-) I think it is going to take me at least a couple of days to grasp your code entirely, but it works perfectly without that 30% increase in memory consumption. Without you I just couldn't do it. Thanks!
The next step, I think, is to remove the 'refresh' configuration entirely -- just have plugins throw exceptions to the event/drawing thread whenever they update.
Well, there is another use of refresh: in the output template you can
set unix commands, and have an empty "commands" list, such as:
Config { font = "-misc-fixed-*-*-*-*-10-*-*-*-*-*-*-*"
, bgColor = "black"
, fgColor = "grey"
, xPos = 0
, yPos = 0
, width = 1024
, height = 15
, align = "right"
, refresh = 10
, commands = []
, sepChar = "%"
, template = "

On Tue, Jul 17, 2007 at 06:19:13PM -0500, Spencer Janssen wrote:
It is possible, but annoying. It requires a magic version of nextEvent that doesn't block inside foreign calls. Thankfully, this isn't so hard to write with threadWaitRead and XPending. With this magic nextEvent, we can use asynchronous exceptions to interrupt the thread with a timer. I've sent you a patch that implements this.
Just a marginal note. I'm thinking about writing a tutorial about X programming for the Haskell.org wiki. I think, indeed, that some documentation for writing an X application, such as a status bar, in Haskell could be useful. My major problem, indeed, is that I could not find code examples, and I presume I'm not the only one that can grasp Haskell but have quite some problems in reading C. I was lucky because there is this XMonad project going on, with you guys, real X and/or Haskell experts. Since I'm sure I'm going to forget everything in a couple of months, if I write it down all the information that thanks to your help I was able to gather won't get lost. This is basically the possible outline of such a tutorial: 1. the process of windows creation and mapping - (with the Hello World example) 2. writing to windows (creating a pixmap, writing to it and copying it to the window, drawing strings, selecting fonts, colors, calculating string length, etc.) 3. handling events I think the example code could be a simple splash screen that reads a text file, and displays each row at every mouse bottom press. And what about mixing events and time driven updates? After studying Spencer's code I have the impression that his solution is the Haskell way of doing this kind of stuff, if I read correctly the documentation.[1] But I don't now whether I should cover it or not. I'm afraid it could be confusing and too complicated. On the other side, since there seems to exist no other Haskell examples of such a case probably it should be covered and solved with asynchronous exceptions. What do you think? Thanks, Andrea [1] http://haskell.org/ghc/docs/latest/html/libraries/base/Control-Exception.htm...

On Tue, Jul 17, 2007 at 06:19:13PM -0500, Spencer Janssen wrote:
The next step, I think, is to remove the 'refresh' configuration entirely -- just have plugins throw exceptions to the event/drawing thread whenever they update.
Apart from what I've said in my previous message (we need it for unix commands not configured in the command list), I don't think that letting the plugins to force window's update is good: I run, for instance, many monitors at once. If I let each one to force a window update as soon as its job is done and its MVar updated, I expect to have such a frequency of window's updates that resource consumption for window's updating becomes the critical factor. I tried to write xmobar in such a way that the use of all the resources that are needed to monitor the system is spread over a relatively long interval of time, with the hope to mitigate/minimize the measurement disturbance. As a downside I cannot assure that the resource consumption is directly related to each monitor refresh rate. Threads are not synchronized. The global refresh rate allows to tune also the window's update time, which, given the chaotic behaviour of monitors, could be relevant to the total resource consumption. I'm not sure if this is clear. And I'm not even sure if this makes sense...;-) This is way I'm writing this 3rd replay. But I swear it is the last one. Thanks Andrea

On Tue, Jul 17, 2007 at 06:19:13PM -0500, Spencer Janssen wrote:
On Tuesday 17 July 2007 13:43:23 Andrea Rossato wrote:
BTW, I've been thinking about it, and I do not see any other possible solution for the specific problem of blocking a thread and resuming it in two different cases: an event *or* the elapsed time. You need the real event or another thread that sends a fake event. Am I right?
It is possible, but annoying. It requires a magic version of nextEvent that doesn't block inside foreign calls. Thankfully, this isn't so hard to write with threadWaitRead and XPending. With this magic nextEvent, we can use asynchronous exceptions to interrupt the thread with a timer. I've sent you a patch that implements this.
Hi, I'm finishing the tutorial I talked about, and when writing the XEvent part (the last one), I found out that XCopyArea will produce a NoExpose event. If I sync the output buffer with False (that is to say, without discarding the events from queue), I can intercept it in the recursive loop without the need of nextEvent' and asynchronous exceptions... Now I'm even more puzzled... ;-) Andrea

On Sat, Jul 21, 2007 at 02:49:06PM +0200, Andrea Rossato wrote:
I'm finishing the tutorial I talked about, and when writing the XEvent part (the last one), I found out that XCopyArea will produce a NoExpose event. If I sync the output buffer with False (that is to say, without discarding the events from queue), I can intercept it in the recursive loop without the need of nextEvent' and asynchronous exceptions...
Now I'm even more puzzled... ;-)
Just forget this message: here it's hot (upper thirties - celsius), and I should be going somewhere instead of getting a headache over this stuff... I think I'm done for today... going to a lake with my dog... better for me, and for the haskell community too. ;-) andrea
participants (2)
-
Andrea Rossato
-
Spencer Janssen