type initialisation deadlock in GObject
Submitted by Allison (desrt)
Link to original bug (#674885)
Description
Imagine we have two very simple classes, A and B.
A has a GObject property "foo" of type B.
This means that the class init function for A contains a call to B's get_type() function (in order to create the paramspec of the correct type).
Now imagine we have two threads, A and B.
- A calls a_get_type().
- B calls b_get_type().
The typical get_type() boilerplate (as in G_DEFINE_TYPE) uses g_once_init_enter() to guard the initialisation of the static GType copy.
Let's say that thread B gets there first: it's now in the critical section of b_get_type() and the once is "owned" by thread B. Thread B sleeps immediately after entering the once.
Meanwhile, thread A is in a_get_type() which causes a_class_init() to be called. The 'class_init_rec_mutex' (in gtype.c) is held. a_class_init() makes its call to b_get_type(). Since thread B is in the critical section of the once, we sleep.
Meanwhile, in thread B, we've just entered the once. Now we have to initialise our GType. It's rather typical to call g_type_add_interface_static() here. That wants to acquire 'class_init_rec_mutex', which is held by thread A, so now thread B sleeps.
We're deadlocked.