Commit a49568ce authored by Dan Winship's avatar Dan Winship

gmain: block child sources when blocking the parent

When blocking a source that has child sources, we need to consider the
children blocked as well. Otherwise they will still trigger repeatedly
in an inner loop started from the parent source's callback.

https://bugzilla.gnome.org/show_bug.cgi?id=669260
parent b3b32be1
......@@ -191,7 +191,8 @@ typedef struct _GSourceCallback GSourceCallback;
typedef enum
{
G_SOURCE_READY = 1 << G_HOOK_FLAG_USER_SHIFT,
G_SOURCE_CAN_RECURSE = 1 << (G_HOOK_FLAG_USER_SHIFT + 1)
G_SOURCE_CAN_RECURSE = 1 << (G_HOOK_FLAG_USER_SHIFT + 1),
G_SOURCE_BLOCKED = 1 << (G_HOOK_FLAG_USER_SHIFT + 2)
} GSourceFlags;
typedef struct _GMainWaiter GMainWaiter;
......@@ -313,8 +314,7 @@ struct _GSourcePrivate
#define G_THREAD_SELF g_thread_self ()
#define SOURCE_DESTROYED(source) (((source)->flags & G_HOOK_FLAG_ACTIVE) == 0)
#define SOURCE_BLOCKED(source) (((source)->flags & G_HOOK_FLAG_IN_CALL) != 0 && \
((source)->flags & G_SOURCE_CAN_RECURSE) == 0)
#define SOURCE_BLOCKED(source) (((source)->flags & G_SOURCE_BLOCKED) != 0)
#define SOURCE_UNREF(source, context) \
G_STMT_START { \
......@@ -2426,12 +2426,24 @@ block_source (GSource *source)
g_return_if_fail (!SOURCE_BLOCKED (source));
source->flags |= G_SOURCE_BLOCKED;
tmp_list = source->poll_fds;
while (tmp_list)
{
g_main_context_remove_poll_unlocked (source->context, tmp_list->data);
tmp_list = tmp_list->next;
}
if (source->priv && source->priv->child_sources)
{
tmp_list = source->priv->child_sources;
while (tmp_list)
{
block_source (tmp_list->data);
tmp_list = tmp_list->next;
}
}
}
/* HOLDS: source->context's lock */
......@@ -2440,15 +2452,27 @@ unblock_source (GSource *source)
{
GSList *tmp_list;
g_return_if_fail (!SOURCE_BLOCKED (source)); /* Source already unblocked */
g_return_if_fail (SOURCE_BLOCKED (source)); /* Source already unblocked */
g_return_if_fail (!SOURCE_DESTROYED (source));
source->flags &= ~G_SOURCE_BLOCKED;
tmp_list = source->poll_fds;
while (tmp_list)
{
g_main_context_add_poll_unlocked (source->context, source->priority, tmp_list->data);
tmp_list = tmp_list->next;
}
if (source->priv && source->priv->child_sources)
{
tmp_list = source->priv->child_sources;
while (tmp_list)
{
unblock_source (tmp_list->data);
tmp_list = tmp_list->next;
}
}
}
/* HOLDS: context's lock */
......@@ -2527,8 +2551,7 @@ g_main_dispatch (GMainContext *context)
if (!was_in_call)
source->flags &= ~G_HOOK_FLAG_IN_CALL;
if ((source->flags & G_SOURCE_CAN_RECURSE) == 0 &&
!SOURCE_DESTROYED (source))
if (SOURCE_BLOCKED (source) && !SOURCE_DESTROYED (source))
unblock_source (source);
/* Note: this depends on the fact that we can't switch
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment