Thread: [java-gnome-hackers] Ugly deadlock with Dialog.run()
Brought to you by:
afcowie
From: Vreixo F. <met...@ya...> - 2010-08-09 19:42:21
|
Hi, I would like to discuss with you an ugly behavior related with the way java-gnome automatically handles the Gtk thread-aware feature. I don't really think this is a bug, but I would like to talk about it. I've working for several years with java-gnome and I have to admit that is the best GUI-framework I've ever known for working with multi-thread applications. You just call java-gnome GUI functions from any thread and it works!!! This is really a pleasure. Of course, the reason for this is related with both the good thread-aware design on Gtk+, plus the acquisition of the mutex lock before invoking any gtk+ function that java-gnome does automatically. There is, however, one ugly case. When you call "blocking" methods such as Gtk.main() or Dialog.run(), Gtk+ takes care of releasing the lock, which makes possible to invoke gtk functions from another thread while the main thread is waiting on Gtk.main(). It works very well, except in one case: calling Dialog.run() inside a signal handler. It is a common situation, when you have to temporally show a dialog in response to a user action (e.g. clicking a Button). In this case, when you call run(), the calling thread already holds the lock (it is running in a signal handler). Internally, java-gnome re-acquires the lock before calling native gtk_dialog_run(). It also does it with every other function, and it works ok because java lock are re-entrant. However, differently from other functions, gtk_dialog_run() will wait in an event loop until the user closes the dialog. As I said above, Gtk+ knows that, so it will release the lock, but the problem is that we have acquired the lock twice, so the lock keeps owned by the calling thread. Therefore, no other thread can access Gtk+ when Dialog.run() is called inside a signal handler. In native Gtk+, I guess it is just a matter of calling gtk_dialog_run() without acquiring the lock first when you're inside a signal handler, but the java-gnome this is not possible as the lock is acquired automatically. What do you think about? Is this ok? Could we (maybe) add a runWithoutLock() function? Note that in my opinion is it ok as it is now, you can always forget about run() and connect to the Response signal if you have this problem. I'm writing this just because I found this problem this week and I wanted to tell you about it. Cheers Vreixo |
From: Andrew C. <an...@op...> - 2010-08-09 22:58:57
|
On Mon, 2010-08-09 at 21:42 +0200, Vreixo Formoso wrote: > I would like to discuss with you an ugly behavior related with the way > java-gnome automatically handles the Gtk thread-aware feature. I don't > really think this is a bug, but I would like to talk about it. Yeah, I raised this on 13 Jan, http://article.gmane.org/gmane.comp.gnome.bindings.java.devel/1436 and https://bugzilla.gnome.org/show_bug.cgi?id=606796 It is pretty ugly. > I've working for several years with java-gnome Well, you ARE the #2 committer :) http://www.ohloh.net/p/java-gnome/contributors > There is, however, one ugly case. When you call "blocking" methods such > as Gtk.main() or Dialog.run(), Gtk+ takes care of releasing the lock, > which makes possible to invoke gtk functions from another thread while > the main thread is waiting on Gtk.main(). It works very well, except in > one case: calling Dialog.run() inside a signal handler. It is a common > situation, when you have to temporally show a dialog in response to a > user action (e.g. clicking a Button). > > In this case, when you call run(), the calling thread already holds the > lock (it is running in a signal handler). Internally, java-gnome > re-acquires the lock before calling native gtk_dialog_run(). It also > does it with every other function, and it works ok because java lock are > re-entrant. However, differently from other functions, gtk_dialog_run() > will wait in an event loop until the user closes the dialog. As I said > above, Gtk+ knows that, so it will release the lock, but the problem is > that we have acquired the lock twice, so the lock keeps owned by the > calling thread.... I agree with your analysis. It's not so much "that we have acquired the lock twice" so much as it is that the gtk_dialog_run() code assumes it can unlock once and be clear. > What do you think about? Is this ok? Could we (maybe) add a > runWithoutLock() function? [please read my other email] We could 1. Take our own lock (which we could then manually unlock in special cases) 2. Just mess with a manual MonitorExit/MonitorEnter or 3. Seriously mess with the entire main loop process: If *we* were iterating the main loop manually, then we could control when it takes our lock and when it doesn't. The problem is replacing gtk_main() with gdk_events_pending() & gdk_main_iteration_do() is NOT really the right thing to do. All of these are invasive. #2 is probably easiest, but there's a bigger problem: what happens if you're not nested 2 deep, but nested 3 deep? Then it won't help. > Note that in my opinion is it ok as it is now, you can always forget > about run() I don't have any hard opinions about it. It's a bug, and we need to either fix it if we can. I'd like to keep run(), though. It's nice to use inside signal handlers. Or it would be if it worked :) AfC Sydney |