mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2025-04-14 11:38:05 +02:00
gobject: optimize notify-queue handling for a single freeze
When we set a property we usually tend to freeze the queue notification and thaw it at the end. This always requires a per-object allocation that is necessary to track the freeze count and frozen properties. But there are cases cases, where we freeze only a single time and never add a property to unfreeze. In such cases, we can avoid allocating a new GObjectNotifyQueue instance. Optimize for that case by initially adding a global, immutable sentinel pointer "notify_queue_empty". Only when requiring a per-object queue, allocate one. This can be useful before calling dispose(). While there are probably dispose functions that still try to set properties on the object (which is the main reason to freeze the notification), most probably don't. In this case, we can avoid allocating the memory during g_object_unref(). Another such case is object construction. If the object has no construct properties and the user didn't specify any properties during g_object_new(), we may well freeze the object but never add properties to it. In that case too, we can get away without ever allocating the GObjectNotifyQueue.
This commit is contained in:
parent
e0ccac2fff
commit
a2da296230
@ -657,6 +657,24 @@ object_bit_unlock (GObject *object, guint lock_bit)
|
||||
|
||||
/* --- functions --- */
|
||||
|
||||
static const GObjectNotifyQueue notify_queue_empty = {
|
||||
.freeze_count = 0,
|
||||
};
|
||||
|
||||
G_ALWAYS_INLINE static inline gboolean
|
||||
_is_notify_queue_empty (const GObjectNotifyQueue *nqueue)
|
||||
{
|
||||
/* Only the notify_queue_empty as a zero freeze count. We check here for that
|
||||
* condition instead of pointer comparing to ¬ify_queue_empty. That seems
|
||||
* useful, because callers will afterwards anyway dereferenciate
|
||||
* "freeze_count" from memory.
|
||||
*/
|
||||
#if G_ENABLE_DEBUG
|
||||
g_assert ((nqueue == ¬ify_queue_empty) == (nqueue->freeze_count == 0));
|
||||
#endif
|
||||
return nqueue->freeze_count == 0;
|
||||
}
|
||||
|
||||
G_ALWAYS_INLINE static inline gsize
|
||||
g_object_notify_queue_alloc_size (gsize alloc)
|
||||
{
|
||||
@ -688,9 +706,9 @@ g_object_notify_queue_freeze_cb (gpointer *data,
|
||||
|
||||
if (!nqueue)
|
||||
{
|
||||
/* The nqueue doesn't exist yet. We create it, and freeze thus 1 time. */
|
||||
*data = g_object_notify_queue_new_frozen ();
|
||||
*destroy_notify = g_free;
|
||||
/* The nqueue doesn't exist yet. We use the dummy object that is shared
|
||||
* by all instances. */
|
||||
*data = (gpointer) ¬ify_queue_empty;
|
||||
}
|
||||
else if (!freeze_always)
|
||||
{
|
||||
@ -701,7 +719,14 @@ g_object_notify_queue_freeze_cb (gpointer *data,
|
||||
}
|
||||
else
|
||||
{
|
||||
if (G_UNLIKELY (nqueue->freeze_count == G_MAXUINT16))
|
||||
if (_is_notify_queue_empty (nqueue))
|
||||
{
|
||||
nqueue = g_object_notify_queue_new_frozen ();
|
||||
*data = nqueue;
|
||||
*destroy_notify = g_free;
|
||||
nqueue->freeze_count++;
|
||||
}
|
||||
else if (G_UNLIKELY (nqueue->freeze_count == G_MAXUINT16))
|
||||
{
|
||||
g_critical ("Free queue for %s (%p) is larger than 65535,"
|
||||
" called g_object_freeze_notify() too often."
|
||||
@ -732,13 +757,19 @@ g_object_notify_queue_thaw_cb (gpointer *data,
|
||||
GObject *object = user_data;
|
||||
GObjectNotifyQueue *nqueue = *data;
|
||||
|
||||
if (G_UNLIKELY (!nqueue || nqueue->freeze_count == 0))
|
||||
if (G_UNLIKELY (!nqueue))
|
||||
{
|
||||
g_critical ("%s: property-changed notification for %s(%p) is not frozen",
|
||||
G_STRFUNC, G_OBJECT_TYPE_NAME (object), object);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (_is_notify_queue_empty (nqueue))
|
||||
{
|
||||
*data = NULL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
nqueue->freeze_count--;
|
||||
|
||||
if (nqueue->freeze_count > 0)
|
||||
@ -820,6 +851,12 @@ g_object_notify_queue_add_cb (gpointer *data,
|
||||
*data = nqueue;
|
||||
*destroy_notify = g_free;
|
||||
}
|
||||
else if (_is_notify_queue_empty (nqueue))
|
||||
{
|
||||
nqueue = g_object_notify_queue_new_frozen ();
|
||||
*data = nqueue;
|
||||
*destroy_notify = g_free;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (i = 0; i < nqueue->len; i++)
|
||||
|
Loading…
x
Reference in New Issue
Block a user