gmain: add GSourceIter

add an explicit iterator for GMainContext sources

https://bugzilla.gnome.org/show_bug.cgi?id=619329
This commit is contained in:
Dan Winship 2012-06-22 22:21:05 -04:00
parent 8e65c30431
commit aaaaab91de

View File

@ -309,6 +309,13 @@ struct _GSourcePrivate
GSource *parent_source; GSource *parent_source;
}; };
typedef struct _GSourceIter
{
GMainContext *context;
gboolean may_modify;
GSource *source;
} GSourceIter;
#define LOCK_CONTEXT(context) g_mutex_lock (&context->mutex) #define LOCK_CONTEXT(context) g_mutex_lock (&context->mutex)
#define UNLOCK_CONTEXT(context) g_mutex_unlock (&context->mutex) #define UNLOCK_CONTEXT(context) g_mutex_unlock (&context->mutex)
#define G_THREAD_SELF g_thread_self () #define G_THREAD_SELF g_thread_self ()
@ -347,6 +354,13 @@ static void g_main_context_add_poll_unlocked (GMainContext *context,
static void g_main_context_remove_poll_unlocked (GMainContext *context, static void g_main_context_remove_poll_unlocked (GMainContext *context,
GPollFD *fd); GPollFD *fd);
static void g_source_iter_init (GSourceIter *iter,
GMainContext *context,
gboolean may_modify);
static gboolean g_source_iter_next (GSourceIter *iter,
GSource **source);
static void g_source_iter_clear (GSourceIter *iter);
static gboolean g_timeout_prepare (GSource *source, static gboolean g_timeout_prepare (GSource *source,
gint *timeout); gint *timeout);
static gboolean g_timeout_check (GSource *source); static gboolean g_timeout_check (GSource *source);
@ -472,7 +486,9 @@ poll_rec_list_free (GMainContext *context,
void void
g_main_context_unref (GMainContext *context) g_main_context_unref (GMainContext *context)
{ {
GSourceIter iter;
GSource *source; GSource *source;
g_return_if_fail (context != NULL); g_return_if_fail (context != NULL);
g_return_if_fail (g_atomic_int_get (&context->ref_count) > 0); g_return_if_fail (g_atomic_int_get (&context->ref_count) > 0);
@ -483,13 +499,9 @@ g_main_context_unref (GMainContext *context)
main_context_list = g_slist_remove (main_context_list, context); main_context_list = g_slist_remove (main_context_list, context);
G_UNLOCK (main_context_list); G_UNLOCK (main_context_list);
source = context->source_list; g_source_iter_init (&iter, context, TRUE);
while (source) while (g_source_iter_next (&iter, &source))
{ g_source_destroy_internal (source, context, FALSE);
GSource *next = source->next;
g_source_destroy_internal (source, context, FALSE);
source = next;
}
g_mutex_clear (&context->mutex); g_mutex_clear (&context->mutex);
@ -804,6 +816,53 @@ g_source_new (GSourceFuncs *source_funcs,
return source; return source;
} }
/* Holds context's lock */
static void
g_source_iter_init (GSourceIter *iter,
GMainContext *context,
gboolean may_modify)
{
iter->context = context;
iter->source = NULL;
iter->may_modify = may_modify;
}
/* Holds context's lock */
static gboolean
g_source_iter_next (GSourceIter *iter, GSource **source)
{
GSource *next_source;
if (iter->source)
{
next_source = iter->source->next;
if (iter->may_modify)
SOURCE_UNREF (iter->source, iter->context);
}
else
next_source = iter->context->source_list;
iter->source = next_source;
if (iter->source && iter->may_modify)
iter->source->ref_count++;
*source = iter->source;
return *source != NULL;
}
/* Holds context's lock. Only necessary to call if you broke out of
* the g_source_iter_next() loop early.
*/
static void
g_source_iter_clear (GSourceIter *iter)
{
if (iter->source && iter->may_modify)
{
SOURCE_UNREF (iter->source, iter->context);
iter->source = NULL;
}
}
/* Holds context's lock /* Holds context's lock
*/ */
static void static void
@ -1702,6 +1761,7 @@ GSource *
g_main_context_find_source_by_id (GMainContext *context, g_main_context_find_source_by_id (GMainContext *context,
guint source_id) guint source_id)
{ {
GSourceIter iter;
GSource *source; GSource *source;
g_return_val_if_fail (source_id > 0, NULL); g_return_val_if_fail (source_id > 0, NULL);
@ -1711,14 +1771,14 @@ g_main_context_find_source_by_id (GMainContext *context,
LOCK_CONTEXT (context); LOCK_CONTEXT (context);
source = context->source_list; g_source_iter_init (&iter, context, FALSE);
while (source) while (g_source_iter_next (&iter, &source))
{ {
if (!SOURCE_DESTROYED (source) && if (!SOURCE_DESTROYED (source) &&
source->source_id == source_id) source->source_id == source_id)
break; break;
source = source->next;
} }
g_source_iter_clear (&iter);
UNLOCK_CONTEXT (context); UNLOCK_CONTEXT (context);
@ -1742,6 +1802,7 @@ g_main_context_find_source_by_funcs_user_data (GMainContext *context,
GSourceFuncs *funcs, GSourceFuncs *funcs,
gpointer user_data) gpointer user_data)
{ {
GSourceIter iter;
GSource *source; GSource *source;
g_return_val_if_fail (funcs != NULL, NULL); g_return_val_if_fail (funcs != NULL, NULL);
@ -1751,8 +1812,8 @@ g_main_context_find_source_by_funcs_user_data (GMainContext *context,
LOCK_CONTEXT (context); LOCK_CONTEXT (context);
source = context->source_list; g_source_iter_init (&iter, context, FALSE);
while (source) while (g_source_iter_next (&iter, &source))
{ {
if (!SOURCE_DESTROYED (source) && if (!SOURCE_DESTROYED (source) &&
source->source_funcs == funcs && source->source_funcs == funcs &&
@ -1766,8 +1827,8 @@ g_main_context_find_source_by_funcs_user_data (GMainContext *context,
if (callback_data == user_data) if (callback_data == user_data)
break; break;
} }
source = source->next;
} }
g_source_iter_clear (&iter);
UNLOCK_CONTEXT (context); UNLOCK_CONTEXT (context);
@ -1789,6 +1850,7 @@ GSource *
g_main_context_find_source_by_user_data (GMainContext *context, g_main_context_find_source_by_user_data (GMainContext *context,
gpointer user_data) gpointer user_data)
{ {
GSourceIter iter;
GSource *source; GSource *source;
if (context == NULL) if (context == NULL)
@ -1796,8 +1858,8 @@ g_main_context_find_source_by_user_data (GMainContext *context,
LOCK_CONTEXT (context); LOCK_CONTEXT (context);
source = context->source_list; g_source_iter_init (&iter, context, FALSE);
while (source) while (g_source_iter_next (&iter, &source))
{ {
if (!SOURCE_DESTROYED (source) && if (!SOURCE_DESTROYED (source) &&
source->callback_funcs) source->callback_funcs)
@ -1810,8 +1872,8 @@ g_main_context_find_source_by_user_data (GMainContext *context,
if (callback_data == user_data) if (callback_data == user_data)
break; break;
} }
source = source->next;
} }
g_source_iter_clear (&iter);
UNLOCK_CONTEXT (context); UNLOCK_CONTEXT (context);
@ -2562,30 +2624,6 @@ g_main_dispatch (GMainContext *context)
g_ptr_array_set_size (context->pending_dispatches, 0); g_ptr_array_set_size (context->pending_dispatches, 0);
} }
/* Holds context's lock */
static inline GSource *
next_valid_source (GMainContext *context,
GSource *source)
{
GSource *new_source = source ? source->next : context->source_list;
while (new_source)
{
if (!SOURCE_DESTROYED (new_source))
{
new_source->ref_count++;
break;
}
new_source = new_source->next;
}
if (source)
SOURCE_UNREF (source, context);
return new_source;
}
/** /**
* g_main_context_acquire: * g_main_context_acquire:
* @context: a #GMainContext * @context: a #GMainContext
@ -2761,6 +2799,7 @@ g_main_context_prepare (GMainContext *context,
gint n_ready = 0; gint n_ready = 0;
gint current_priority = G_MAXINT; gint current_priority = G_MAXINT;
GSource *source; GSource *source;
GSourceIter iter;
if (context == NULL) if (context == NULL)
context = g_main_context_default (); context = g_main_context_default ();
@ -2802,18 +2841,15 @@ g_main_context_prepare (GMainContext *context,
context->timeout = -1; context->timeout = -1;
source = next_valid_source (context, NULL); g_source_iter_init (&iter, context, TRUE);
while (source) while (g_source_iter_next (&iter, &source))
{ {
gint source_timeout = -1; gint source_timeout = -1;
if (SOURCE_DESTROYED (source) || SOURCE_BLOCKED (source))
continue;
if ((n_ready > 0) && (source->priority > current_priority)) if ((n_ready > 0) && (source->priority > current_priority))
{ break;
SOURCE_UNREF (source, context);
break;
}
if (SOURCE_BLOCKED (source))
goto next;
if (!(source->flags & G_SOURCE_READY)) if (!(source->flags & G_SOURCE_READY))
{ {
@ -2856,10 +2892,8 @@ g_main_context_prepare (GMainContext *context,
else else
context->timeout = MIN (context->timeout, source_timeout); context->timeout = MIN (context->timeout, source_timeout);
} }
next:
source = next_valid_source (context, source);
} }
g_source_iter_clear (&iter);
UNLOCK_CONTEXT (context); UNLOCK_CONTEXT (context);
@ -2954,6 +2988,7 @@ g_main_context_check (GMainContext *context,
gint n_fds) gint n_fds)
{ {
GSource *source; GSource *source;
GSourceIter iter;
GPollRec *pollrec; GPollRec *pollrec;
gint n_ready = 0; gint n_ready = 0;
gint i; gint i;
@ -2991,16 +3026,13 @@ g_main_context_check (GMainContext *context,
i++; i++;
} }
source = next_valid_source (context, NULL); g_source_iter_init (&iter, context, TRUE);
while (source) while (g_source_iter_next (&iter, &source))
{ {
if (SOURCE_DESTROYED (source) || SOURCE_BLOCKED (source))
continue;
if ((n_ready > 0) && (source->priority > max_priority)) if ((n_ready > 0) && (source->priority > max_priority))
{ break;
SOURCE_UNREF (source, context);
break;
}
if (SOURCE_BLOCKED (source))
goto next;
if (!(source->flags & G_SOURCE_READY)) if (!(source->flags & G_SOURCE_READY))
{ {
@ -3041,10 +3073,8 @@ g_main_context_check (GMainContext *context,
*/ */
max_priority = source->priority; max_priority = source->priority;
} }
next:
source = next_valid_source (context, source);
} }
g_source_iter_clear (&iter);
UNLOCK_CONTEXT (context); UNLOCK_CONTEXT (context);