The optional flags should be used for bit locks. That means,
we must only use atomic operations when updating the flags.
Having a variant of _X methods that update the flags without
locks (_X), means that we must take care not to take bit locks
during construction.
That is hard to get right. There is so much happening during object
construction, that it's unclear when it's really safe to access the
flags without atomic. Don't do this.
Add a GObjectPrivate struct and let GObject have private data.
On architectures where we have an alignment gap in GObject struct (64
bit), we use the gap for "optional_flags". Use the private data for
those optional flags, on architectures where we don't have them.
For now, private data is only added for those optional flags (and not on
architectures, where the flags fit inside GObject). In the future, we
may add additional fields there, and add the private struct always.
The main purpose will be to replace all the global locks with per-object
locks, and make "optional_flags" also available on 32bit.
_Thread_local is also C11, so possibly other compilers would also support
it.
However, since not *all* compilers support it, it can anyway only be
used as optimization and conditional asserts. As such, the current
detection based on __GNUC__ to only support gcc (and clang) is good
enough.
GWeakRef calls g_object_ref() while holding a read lock.
g_object_ref() can emit a toggle notification.
If you then inside the toggle notification setup a GWeakRef
(to the same or another object), the code will try to get
a write lock. Deadlock will happen.
Add a test to "show" that (the breaking part is commented out).
Will be fixed next.
In g_object_unref(), we call _object_unref_clear_weak_locations() before
and after dispose() already. At those places it is necessary to do.
Calling it a third time during g_object_real_dispose() seems not useful,
has unnecessary overhead and actually undesirable.
In particular, because g_object_real_dispose() is the implementation for
the virtual function GObject.dispose(). For subclasses that override dispose(),
it's not well defined at which point they should chain up the parent
implementation (for dispose(), I'd argue that usually they chain up at
the end of their own code). If they chain up at the end, this has no
effect.
This only really matters if you try to register GWeakRef during dipose
and/or resurrect the object.
static void dispose(GObject *object)
{
g_weak_ref_set(&global_weak_ref, object);
global_ref = g_object_ref(object);
G_OBJECT_CLASS (parent_class)->dispose (object);
}
the object was resurrected, but g_object_real_dispose() would clear the
weak ref. That is not desirable, nor does it make sense.
Instead, the virtual function dispose() is called from two places, from
g_object_unref() and g_object_run_dispose(). In both cases, it is
ensured that weak locations are cleared *after* dispatching the virtual
function. Don't do it somewhere in the middle from
g_object_real_dispose().
A few applications such as gnome-music load the GIRepository typelib
and use it to adjust their search paths.
GLib 2.79.x now provides libgirepository-2.0.so.0 (GIRepository-3.0),
but each OS distribution is likely to have a transitional period during
which GLib's libgirepository-2.0.so.0 has become available, but bindings
like PyGI and gjs are still linked to gobject-introspection's
libgirepository-1.0.so.1 (GIRepository-2.0).
During this transitional period, interpreted languages that load the
GIRepository namespace could get the "wrong" version, which will result
in adjusting a search path that will not actually affect the language
binding's typelib lookup, and could also lead to symbol and type-system
conflicts.
We can avoid this collision by making GLib's GIRepository library refuse
to load versions of the GIRepository typelib that are not 3.0, and
similarly making gobject-introspection's GIRepository library refuse to
load typelib versions that are not 2.0. A relatively neat way to achieve
that is to make each version behave as if the other one doesn't exist.
Signed-off-by: Simon McVittie <smcv@debian.org>
The title of an interface can be arbitrarily long, considering that
reverse DNS namespaces can be pretty complex. Instead of using the whole
interface name, we can use the name without the prefix.
dispose() can resurrect an object and/or register a weak-ref. After
returning from dispose(), we must check again. And we must do so in a
race-free manner, where we check that we have no more weak-locations
and the ref-count is one.
In fact, if _object_unref_clear_weak_locations() determines that the
ref-count is 1, it must also decrement the ref-count to zero while
holding the weak_locations_lock. This prevents g_weak_ref_set() to
still register a weak-pointer after the reference count dropped to zero.
Also add an assertion to g_weak_ref_set(), that the object is still
alive. The assertion is useful to finding bugs, but the change really
makes it impossible that a wrongly used g_weak_ref_set() can still
resurrect the object after finalization starts.
The final
g_datalist_id_set_data (&object->qdata, quark_weak_locations, NULL);
during finalization is no longer necessary and dropped.
We never set any data for quark_weak_refs. It's unused, drop it.
Also, fail a g_critical() assertion, if the GWeakRef is unexpectedly not
registered in the object. That really shouldn't happen.
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.
The previous g_object_unref() was racy. There were three places where we
decremented the ref count, but still accessed the object afterwards
(while assuming that somebody else might still hold a reference). For
example:
if (!g_atomic_int_compare_and_exchange_full ((int *) &object->ref_count,
old_ref, old_ref - 1,
&old_ref))
continue;
TRACE (GOBJECT_OBJECT_UNREF (object, G_TYPE_FROM_INSTANCE (object), old_ref));
/* if we went from 2->1 we need to notify toggle refs if any */
if (old_ref == 2 && OBJECT_HAS_TOGGLE_REF (object))
{
/* The last ref being held in this case is owned by the toggle_ref */
toggle_refs_notify (object, TRUE);
}
After we decrement the reference count (and gave up our reference), we
are only allowed to access object if we know we have the only possible
reference to it. In particular, if old_ref is larger than 1, then
somebody else holds references and races against destroying object.
The object might be a dangling pointer already.
This is slightly complicated due to toggle references and clearing of
weak-locations.
For toggle references, we must take a lock on the mutex. Luckily, that
is only necessary, when the current reference count is exactly 2.
Note that we emit the TRACE() after the ref count was already decreased.
If another thread unrefs the object, inside the TRACE() we might have a
dangling pointer. That would only be fixable, by emitting the TRACE()
before the actual unref (which has its own problems). This problem
already existed previously.
The change to the test is necessary and correct. Before this patch,
g_object_unref() would call dispose() and decrement the reference count
right after.
In the test case at gobject/tests/reference.c:1108, the reference count
after dispose and decrement is 1. Then it thaws the queue notification,
which emits a property changed signal. The test then proceeds to
reference the object again and notifying the toggle reference.
Previously, the toggle reference was notified 3 times.
After this change, the property changed signal is emitted before
decreasing the reference count. Taking a reference then does not cause
an additional toggle on+off, so in total only one toggle happens.
That accounts for the change in the test. The new behavior is
correct.
The indentation level in g_object_unref() is wrong. Fix it by reformatting
the function with clang-format. That makes follow up patches easier to adhere
a consistent style.
No other changes.
Toggle refs are seldom used, and when they are, it makes mostly sense that
there is only one of them. Thus, when removing the last toggle ref, also
remove the associated data.
The library shipped by gobject-introspection.git was
`libgirepository-1.0.so`, but for some reason (accident?), it was
accompanied by `GIRepository-2.0.gir`. That’s been the case for the last
6 years.
In moving libgirepository to glib.git, we’ve bumped the version to
`libgirepository-2.0.so`, and have changed the API.
In order to avoid a collision between the new `GIRepository-2.0.gir` and
the old `GIRepository-2.0.gir`, we can either:
* Rename the basename of the library (confusing).
* Re-version the whole thing to 3.0 (would mean it’s completely out of
sync with the rest of glib.git, and would lead to build system
misery).
* Re-version only the GIR file (a bit confusing, but hopefully less
confusing).
So I’ve done the final option: glib.git now ships
`libgirepository-2.0.so` and `GIRepository-3.0.gir`. This avoids
collisions with what’s shipped by gobject-introspection.git, while
hopefully still making some sense.
We considered using version number 2.1 rather than 3.0, but decided
against it because that makes it look like it’s compatible with version
2.0, which it isn’t.
Note that none of these changes touch the
`${prefix}/lib/girepository-1.0` and `${prefix}/share/gir-1.0`
directories. The version numbers in those refer to the versions of the
GIR and typelib file formats, which have not changed.
Signed-off-by: Philip Withnall <pwithnall@gnome.org>
Helps: #3155
They are now installed to (e.g.)
`${prefix}/share/doc/glib-2.0/{glib,gmodule,gobject,gio}/index.html`.
We might want to drop one level of nesting out of that, but for the
moment I thought I’d keep it in so we can disambiguate by installed
major version.
Signed-off-by: Philip Withnall <pwithnall@gnome.org>
Helps: #3037
Previously, `-Dman=false` was the default, because the generated man
pages were shipped in the distribution tarball already, so the option
actually mostly controlled whether to *re*build them.
The generated pages are no longer shipped in the tarball (and probably
haven’t been since the port to Meson, though I haven’t checked), so it
makes sense to change the default to encourage building the man pages if
the right tooling (`rst2man`) is available.
Signed-off-by: Philip Withnall <pwithnall@gnome.org>