mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2025-02-26 12:12:10 +01:00
Replace the global RWLock with per-object locking. Note that there are three places where we needed to take the globlal lock. g_weak_ref_get(), g_weak_ref_set() and in _object_unref_clear_weak_locations(), during g_object_unref(). The calls during g_object_unref() seem the most relevant here, where we would want to avoid a global lock. Luckily, that global lock only had to be taken if the object ever had a GWeakRef registered, so most objects wouldn't care. The global lock only affects objects, that are ever set via g_weak_ref_set(). Still, try to avoid that global lock. Related to GWeakRef, there are various moments when we don't hold a strong reference to the object. So the per-object lock cannot be on the object itself, because when we want to unlock we no longer have access to the object. And we cannot take a strong reference on the GObject either, because that triggers toggle notifications. And worse, when one thread holds the last strong reference of an object and decides to destroy it, then a `g_weak_ref_set(weak_ref, NULL)` on another thread could acquire a temporary reference, and steal the destruction of the object from the other thread. Instead, we already had a "quark_weak_locations" GData and an allocated structure for tracking the GSList with GWeakRef. Extend that to be ref-counted and have a separate lifetime from the object. This WeakRefData now contains the per-object mutex for locking. We can request the WeakRefData from an object, take a reference to keep it alive, and use it to hold the lock without having the object alive. We also need a bitlock on GWeakRef itself. So to set or get a GWeakRef we must take the per-object lock on the WeakRefData and the lock on the GWeakRef (in this order). During g_weak_ref_set() there may be of course two objects (and two WeakRefData) involved, the previous and the new object. Note that now once an object gets a WeakRefData allocated, it can no longer be freed. It must stick until the object gets destroyed. This allocation happens, once an object is set via g_weak_ref_set(). In other words, objects involved with GWeakRef will have extra data allocated. It may be possible to also release the WeakRefData once it's no longer needed. However, that would be quite complicated, and require additional atomic operations, so it's not clear to be worth it. So it's not done. Instead, the WeakRefData sticks on the object once it's set.