GNOME Bugzilla – Bug 425995
GDK/GTK locking not reentrant
Last modified: 2016-06-08 04:09:29 UTC
The functions gdk_threads_enter() and gdk_threads_leave() are not reentrant. Attempting to call gdk_threads_enter() from a thread that already holds the lock on the mutex is going to block. This is very painful in implementing the Java AWT bindings in GNU Classpath. Unfortunately, AWT is designed to allow access to the toolkit from arbitrary threads, and not beeing able to use reentrant locking has caused a lot of trouble in the past. While we have a somewhat working workaround now (basically replacing the locking functions with reentrant versions), it is the general consens that this is better done in GDK itself. See also: http://developer.classpath.org/pipermail/classpath-patches/2007-April/005246.html Do you think it is desirable to have such behaviour in GDK? If yes, I could try and help with implementing it.
By co-incidence, like two days ago another person wrote about the same thing in C: http://mail.gnome.org/archives/gtk-app-devel-list/2007-May/msg00128.html So perhaps this is indeed something we should explore more at the GDK level. AfC
Obviously, the "general consensus" does not include the people who designed the GDK locking.
For what it's worth, we have been successfully using a recursive mutex for the GDK lock in production for about 19 months now. Given that Owen helped us implement it, I would respectfully suggest that the concept is perhaps not quite as anathema as might have been thought. [I gather anacdotally that many others are already quite happily using a recursive lock as well. Theaded programming can be challenging, but then again using GTK effectively is too. If you're on top of your game then using a reentrant lock can be quite helpful] But in any case, the fact that the lock functions are settable is really wonderful and has been sufficient for us. Indeed, we wouldn't notice even if GTK did change the simple mutex currently deployed as the default GDK lock implementation. As such, and given the inevitable unhelpful resistance from the usual knee-jerk "threads are evil" crowd, I wouldn't really expect the default implementation to change, so I'm not sure this bug needs to remain open. But I would have been remiss if I didn't note that a reentrant GDK lock *does* work, and that we really appreciate the work of the people who originally created the flexibility that allows us to use one. AfC
I would like to add my experience in the hopes that it will convince the developers to revisit this issue. My application is currently encountering a deadlock scenario and we believe it is not caused by improper locking in our code but by an external library that GTK+ calls (libgail). When gdb is attached to it we get the following stacktrace (sorry no gtk+ debug symbols since it comes from a user; we can ask the user to reproduce with debug symbols upon request):
+ Trace 217879
Thread 11 (Thread 0xb4f7bb90 (LWP 13385))
So here we have a scenario where a library that GTK+ uses is invoking gdk_threads_enter() even though the gdk_threads_enter() has already been called by my code, resulting in deadlock since gdk_threads_enter() is not reentrant. If it was my code that was calling gdk_threads_enter() multiple times without unlocking first, I could probably fix it. But I cannot protect against a random library that is linked with GTK+ calling gdk_threads_enter() multiple times. Also, I believe my scenario will happen even if my code is within the main loop (say in a signal callback) and don't think it's related to calling GTK+ functions from another thread, but I have no way of confirming this. For this reason, I hope that the developers would look at making gdk locking reentrant to solve this scenario or at least allow an optional setting to be passed to gdk_threads_init() to specify whether the gdk mutex should be recursive or not. The latter option might be good if making the lock reentrant is a performance concern.
*** Bug 591827 has been marked as a duplicate of this bug. ***