gobjectnotifyqueue.c   gobjectnotifyqueue.c 
skipping to change at line 51 skipping to change at line 51
GTrashStack *_nqueue_trash; /* unused */ GTrashStack *_nqueue_trash; /* unused */
}; };
struct _GObjectNotifyQueue struct _GObjectNotifyQueue
{ {
GObjectNotifyContext *context; GObjectNotifyContext *context;
GSList *pspecs; GSList *pspecs;
guint16 n_pspecs; guint16 n_pspecs;
guint16 freeze_count; guint16 freeze_count;
}; };
G_LOCK_DEFINE_STATIC(notify_lock);
/* --- functions --- */ /* --- functions --- */
static void static void
g_object_notify_queue_free (gpointer data) g_object_notify_queue_free (gpointer data)
{ {
GObjectNotifyQueue *nqueue = data; GObjectNotifyQueue *nqueue = data;
g_slist_free (nqueue->pspecs); g_slist_free (nqueue->pspecs);
g_slice_free (GObjectNotifyQueue, nqueue); g_slice_free (GObjectNotifyQueue, nqueue);
} }
static inline GObjectNotifyQueue* static inline GObjectNotifyQueue*
g_object_notify_queue_freeze (GObject *object, g_object_notify_queue_freeze (GObject *object,
GObjectNotifyContext *context) GObjectNotifyContext *context)
{ {
GObjectNotifyQueue *nqueue; GObjectNotifyQueue *nqueue;
G_LOCK(notify_lock);
nqueue = g_datalist_id_get_data (&object->qdata, context->quark_notify_qu eue); nqueue = g_datalist_id_get_data (&object->qdata, context->quark_notify_qu eue);
if (!nqueue) if (!nqueue)
{ {
nqueue = g_slice_new0 (GObjectNotifyQueue); nqueue = g_slice_new0 (GObjectNotifyQueue);
nqueue->context = context; nqueue->context = context;
g_datalist_id_set_data_full (&object->qdata, context->quark_notify_qu eue, g_datalist_id_set_data_full (&object->qdata, context->quark_notify_qu eue,
nqueue, g_object_notify_queue_free); nqueue, g_object_notify_queue_free);
} }
g_return_val_if_fail (nqueue->freeze_count < 65535, nqueue); if (nqueue->freeze_count >= 65535)
nqueue->freeze_count++; g_critical("Free queue for %s (%p) is larger than 65535,"
" called g_object_freeze_notify() too often."
" Forgot to call g_object_thaw_notify() or infinite loop",
G_OBJECT_TYPE_NAME (object), object);
else
nqueue->freeze_count++;
G_UNLOCK(notify_lock);
return nqueue; return nqueue;
} }
static inline void static inline void
g_object_notify_queue_thaw (GObject *object, g_object_notify_queue_thaw (GObject *object,
GObjectNotifyQueue *nqueue) GObjectNotifyQueue *nqueue)
{ {
GObjectNotifyContext *context = nqueue->context; GObjectNotifyContext *context = nqueue->context;
GParamSpec *pspecs_mem[16], **pspecs, **free_me = NULL; GParamSpec *pspecs_mem[16], **pspecs, **free_me = NULL;
GSList *slist; GSList *slist;
guint n_pspecs = 0; guint n_pspecs = 0;
g_return_if_fail (nqueue->freeze_count > 0); g_return_if_fail (nqueue->freeze_count > 0);
g_return_if_fail (g_atomic_int_get(&object->ref_count) > 0);
G_LOCK(notify_lock);
/* Just make sure we never get into some nasty race condition */
if (G_UNLIKELY(nqueue->freeze_count == 0)) {
G_UNLOCK(notify_lock);
g_warning ("%s: property-changed notification for %s(%p) is not frozen"
,
G_STRFUNC, G_OBJECT_TYPE_NAME (object), object);
return;
}
nqueue->freeze_count--; nqueue->freeze_count--;
if (nqueue->freeze_count) if (nqueue->freeze_count) {
G_UNLOCK(notify_lock);
return; return;
g_return_if_fail (object->ref_count > 0); }
pspecs = nqueue->n_pspecs > 16 ? free_me = g_new (GParamSpec*, nqueue->n_ pspecs) : pspecs_mem; pspecs = nqueue->n_pspecs > 16 ? free_me = g_new (GParamSpec*, nqueue->n_ pspecs) : pspecs_mem;
/* set first entry to NULL since it's checked unconditionally */
pspecs[0] = NULL;
for (slist = nqueue->pspecs; slist; slist = slist->next) for (slist = nqueue->pspecs; slist; slist = slist->next)
{ {
GParamSpec *pspec = slist->data; pspecs[n_pspecs++] = slist->data;
guint i = 0;
/* dedup, make pspecs in the list unique */
redo_dedup_check:
if (pspecs[i] == pspec)
continue;
if (++i < n_pspecs)
goto redo_dedup_check;
pspecs[n_pspecs++] = pspec;
} }
g_datalist_id_set_data (&object->qdata, context->quark_notify_queue, NULL ); g_datalist_id_set_data (&object->qdata, context->quark_notify_queue, NULL );
G_UNLOCK(notify_lock);
if (n_pspecs) if (n_pspecs)
context->dispatcher (object, n_pspecs, pspecs); context->dispatcher (object, n_pspecs, pspecs);
g_free (free_me); g_free (free_me);
} }
static inline void static inline void
g_object_notify_queue_clear (GObject *object, g_object_notify_queue_clear (GObject *object,
GObjectNotifyQueue *nqueue) GObjectNotifyQueue *nqueue)
{ {
g_return_if_fail (nqueue->freeze_count > 0); g_return_if_fail (nqueue->freeze_count > 0);
G_LOCK(notify_lock);
g_slist_free (nqueue->pspecs); g_slist_free (nqueue->pspecs);
nqueue->pspecs = NULL; nqueue->pspecs = NULL;
nqueue->n_pspecs = 0; nqueue->n_pspecs = 0;
G_UNLOCK(notify_lock);
} }
static inline void static inline void
g_object_notify_queue_add (GObject *object, g_object_notify_queue_add (GObject *object,
GObjectNotifyQueue *nqueue, GObjectNotifyQueue *nqueue,
GParamSpec *pspec) GParamSpec *pspec)
{ {
if (pspec->flags & G_PARAM_READABLE) if (pspec->flags & G_PARAM_READABLE)
{ {
GParamSpec *redirect; GParamSpec *redirect;
G_LOCK(notify_lock);
g_return_if_fail (nqueue->n_pspecs < 65535); g_return_if_fail (nqueue->n_pspecs < 65535);
redirect = g_param_spec_get_redirect_target (pspec); redirect = g_param_spec_get_redirect_target (pspec);
if (redirect) if (redirect)
pspec = redirect; pspec = redirect;
/* we do the deduping in _thaw */ /* we do the deduping in _thaw */
nqueue->pspecs = g_slist_prepend (nqueue->pspecs, pspec); if (g_slist_find (nqueue->pspecs, pspec) == NULL)
nqueue->n_pspecs++; {
nqueue->pspecs = g_slist_prepend (nqueue->pspecs, pspec);
nqueue->n_pspecs++;
}
G_UNLOCK(notify_lock);
} }
} }
/* NB: This function is not threadsafe, do not ever use it if
* you need a threadsafe notify queue.
* Use g_object_notify_queue_freeze() to acquire the queue and
* g_object_notify_queue_thaw() after you are done instead.
*/
static inline GObjectNotifyQueue* static inline GObjectNotifyQueue*
g_object_notify_queue_from_object (GObject *object, g_object_notify_queue_from_object (GObject *object,
GObjectNotifyContext *context) GObjectNotifyContext *context)
{ {
return g_datalist_id_get_data (&object->qdata, context->quark_notify_queu e); return g_datalist_id_get_data (&object->qdata, context->quark_notify_queu e);
} }
G_END_DECLS G_END_DECLS
#endif /* __G_OBJECT_NOTIFY_QUEUE_H__ */ #endif /* __G_OBJECT_NOTIFY_QUEUE_H__ */
 End of changes. 15 change blocks. 
20 lines changed or deleted 49 lines changed or added

This html diff was produced by rfcdiff 1.41. The latest version is available from http://tools.ietf.org/tools/rfcdiff/