glib/gmain: Avoid potential dispose race on GSource due to refcount dance
During g_source_unref()
we might end up calling dispose from
multiple threads, and due to the ref/unref dance we were doing we could
end up initiating a GSource finalization while another thread was about
to revive the source.
This was because we were unreffing a source in a thread, and potentially re-reffing it, at the same time, but it was not guaranteed that the final decrement and test couldn't be followed by a further re-ref.
To avoid this, do not do any ref/unref/re-ref/re-unref dance while we're about to dispose, but instead follow a bit more the g_object_unref() logic, and start the disposal phase only if we're about to drop the last reference, and only after the potential disposal call is done, we do an actual ref count decrement, which may lead to the finalization or not.
We don't bother following the same logic at later point, since after disposal we should really have just one thread running and revival of a GSource isn't supported anyways.
With this logic we can also avoid doing unneeded context locking when we've enough references on a GSource that disposal is unlikely to happen.
Closes: #3612 (closed)