mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2025-02-25 11:42:10 +01:00
Previously: 1. old_val = atomic_add(&object->ref_count); 2. if (old_val == 1 && OBJECT_HAS_TOGGLE_REF (object)) { toggle_notify() } As old_val was 1, you might think that no other thread can have a valid reference to object. However, that's not the case. For one, GWeakRef can be used to create another strong reference. More easily, the single reference can be shared between multiple threads (as long as the code takes care that the object lives long enough). That means, another thread can easily add and drop references (including toggle references). All between step 1 and 2. A race here might be hard to hit, and the effect might not be obviously bad. However, consider old_val is 1 due to a normal reference, and another thread adds a toggle ref between step 1. and 2. Then we would notify a toggle from 1->2, although a newly added toggle ref is expected to always start with a normal and a toggle reference. The first toggle notification is expected to notify about the loss of other references, not about getting a second reference. To handle this properly, when we increase the reference count from 1 to 2, we must do so under a lock and check for the toggle notification. As we now correctly track the toggle behavior, we can also assert in toggle_refs_get_notify_unlocked() that n_toggle_refs agrees with the number of references, that is, that the user did always match g_object_add_toggle_ref() with g_object_remove_toggle_ref(). The downside is here too, that there is now a case (when increasing the reference count from 1 to 2) where we need to take the global lock. That performance problem should be addresses by using per-object locks instead of a global lock.