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/ |