[glib/freeze-shenanigans: 3/3] Handle a corner-case of notify avoidance
- From: Matthias Clasen <matthiasc src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [glib/freeze-shenanigans: 3/3] Handle a corner-case of notify avoidance
- Date: Thu, 9 Jun 2022 17:20:23 +0000 (UTC)
commit d175e66459dc453b12da4ff9a95afad2afbbf8b0
Author: Matthias Clasen <mclasen redhat com>
Date: Wed Jun 8 14:06:40 2022 -0400
Handle a corner-case of notify avoidance
The corner-case we are handling here is that
we don't freeze the notify queue in g_object_init
(because there's no custom ->notify vfunc, but
then we gain a notify handler during instance
init, and instance init also triggers a
notification. Handle this by jit freezing
notification in g_object_notify_by_spec_internal.
Note that this is bad code - instance init really
shouldn't be doing things like this.
Testcase included.
Fixes: #2665
gobject/gobject.c | 38 +++++++++++++++++++++++++++++++++-----
1 file changed, 33 insertions(+), 5 deletions(-)
---
diff --git a/gobject/gobject.c b/gobject/gobject.c
index 1d9db7bb84..7b402eba67 100644
--- a/gobject/gobject.c
+++ b/gobject/gobject.c
@@ -1441,24 +1441,51 @@ static inline void
g_object_notify_by_spec_internal (GObject *object,
GParamSpec *pspec)
{
+#ifdef HAVE_OPTIONAL_FLAGS
+ guint object_flags;
+#endif
+ gboolean has_notify;
+ gboolean in_init;
+
if (G_UNLIKELY (~pspec->flags & G_PARAM_READABLE))
return;
param_spec_follow_override (&pspec);
- if (pspec != NULL &&
- _g_object_has_notify_handler (object))
+#ifdef HAVE_OPTIONAL_FLAGS
+ /* get all flags we need with a single atomic read */
+ object_flags = object_get_optional_flags (object);
+ has_notify = ((object_flags & OPTIONAL_FLAG_HAS_NOTIFY_HANDLER) != 0) ||
+ CLASS_HAS_NOTIFY (G_OBJECT_GET_CLASS (object));
+ in_init = (object_flags & OPTIONAL_FLAG_IN_CONSTRUCTION) != 0;
+#else
+ has_notify = TRUE;
+ in_init = object_in_construction (object);
+#endif
+
+ if (pspec != NULL && has_notify)
{
GObjectNotifyQueue *nqueue;
+ gboolean need_thaw = TRUE;
/* conditional freeze: only increase freeze count if already frozen */
nqueue = g_object_notify_queue_freeze (object, TRUE);
+ if (in_init && !nqueue)
+ {
+ /* We did not freeze the queue in g_object_init, but
+ * we gained a notify handler in instance init, so
+ * now we need to freeze just-in-time
+ */
+ nqueue = g_object_notify_queue_freeze (object, FALSE);
+ need_thaw = FALSE;
+ }
if (nqueue != NULL)
{
/* we're frozen, so add to the queue and release our freeze */
g_object_notify_queue_add (object, nqueue, pspec);
- g_object_notify_queue_thaw (object, nqueue);
+ if (need_thaw)
+ g_object_notify_queue_thaw (object, nqueue);
}
else
{
@@ -2167,11 +2194,12 @@ g_object_new_internal (GObjectClass *class,
{
GSList *node;
- if (CLASS_HAS_NOTIFY (class))
+ if (_g_object_has_notify_handler (object))
{
/* This will have been setup in g_object_init() */
nqueue = g_datalist_id_get_data (&object->qdata, quark_notify_queue);
- g_assert (nqueue != NULL);
+ if (!nqueue)
+ nqueue = g_object_notify_queue_freeze (object, FALSE);
}
/* We will set exactly n_construct_properties construct
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]