summaryrefslogtreecommitdiff
path: root/gtk
diff options
context:
space:
mode:
authorMarc-André Lureau <marcandre.lureau@redhat.com>2012-01-09 16:34:16 +0100
committerMarc-André Lureau <marcandre.lureau@redhat.com>2012-01-12 19:43:38 +0100
commit173841cb216c244580f72d61892f67f91a4c7b8a (patch)
tree95eade2dfdb12cab1328dafd623ad5d6f3bd92a3 /gtk
parent348acdb3ad40282b9675b4706298df31d60ac11d (diff)
Make g_coroutine_condition_wait() cancellable
https://bugs.freedesktop.org/show_bug.cgi?id=44570
Diffstat (limited to 'gtk')
-rw-r--r--gtk/channel-base.c3
-rw-r--r--gtk/channel-main.c10
-rw-r--r--gtk/decode-glz.c2
-rw-r--r--gtk/gio-coroutine.c48
-rw-r--r--gtk/gio-coroutine.h12
-rw-r--r--gtk/spice-channel-priv.h2
-rw-r--r--gtk/spice-channel.c17
7 files changed, 67 insertions, 27 deletions
diff --git a/gtk/channel-base.c b/gtk/channel-base.c
index e41b1f5..fd36696 100644
--- a/gtk/channel-base.c
+++ b/gtk/channel-base.c
@@ -116,6 +116,7 @@ static gboolean wait_for_channel(gpointer data)
G_GNUC_INTERNAL
void spice_channel_handle_wait_for_channels(SpiceChannel *channel, SpiceMsgIn *in)
{
+ SpiceChannelPrivate *c = channel->priv;
SpiceMsgWaitForChannels *wfc = spice_msg_in_parsed(in);
int i;
@@ -129,7 +130,7 @@ void spice_channel_handle_wait_for_channels(SpiceChannel *channel, SpiceMsgIn *i
};
SPICE_DEBUG("waiting for serial %lu (%d/%d)", data.wait->message_serial, i + 1, wfc->wait_count);
- g_condition_wait(wait_for_channel, &data);
+ g_coroutine_condition_wait(&c->coroutine, wait_for_channel, &data);
SPICE_DEBUG("waiting for serial %lu, done", data.wait->message_serial);
}
}
diff --git a/gtk/channel-main.c b/gtk/channel-main.c
index 42e4494..ebf660f 100644
--- a/gtk/channel-main.c
+++ b/gtk/channel-main.c
@@ -1709,7 +1709,7 @@ static gboolean timer_set_display(gpointer data)
c->timer_id = 0;
if (c->agent_connected)
spice_main_send_monitor_config(SPICE_MAIN_CHANNEL(channel));
- spice_channel_wakeup(channel);
+ spice_channel_wakeup(channel, FALSE);
return false;
}
@@ -1783,7 +1783,7 @@ void spice_main_clipboard_selection_grab(SpiceMainChannel *channel, guint select
g_return_if_fail(SPICE_IS_MAIN_CHANNEL(channel));
agent_clipboard_grab(channel, selection, types, ntypes);
- spice_channel_wakeup(SPICE_CHANNEL(channel));
+ spice_channel_wakeup(SPICE_CHANNEL(channel), FALSE);
}
/**
@@ -1822,7 +1822,7 @@ void spice_main_clipboard_selection_release(SpiceMainChannel *channel, guint sel
return;
agent_clipboard_release(channel, selection);
- spice_channel_wakeup(SPICE_CHANNEL(channel));
+ spice_channel_wakeup(SPICE_CHANNEL(channel), FALSE);
}
/**
@@ -1863,7 +1863,7 @@ void spice_main_clipboard_selection_notify(SpiceMainChannel *channel, guint sele
g_return_if_fail(SPICE_IS_MAIN_CHANNEL(channel));
agent_clipboard_notify(channel, selection, type, data, size);
- spice_channel_wakeup(SPICE_CHANNEL(channel));
+ spice_channel_wakeup(SPICE_CHANNEL(channel), FALSE);
}
/**
@@ -1899,7 +1899,7 @@ void spice_main_clipboard_selection_request(SpiceMainChannel *channel, guint sel
g_return_if_fail(SPICE_IS_MAIN_CHANNEL(channel));
agent_clipboard_request(channel, selection, type);
- spice_channel_wakeup(SPICE_CHANNEL(channel));
+ spice_channel_wakeup(SPICE_CHANNEL(channel), FALSE);
}
/**
diff --git a/gtk/decode-glz.c b/gtk/decode-glz.c
index 317fa9e..377f7af 100644
--- a/gtk/decode-glz.c
+++ b/gtk/decode-glz.c
@@ -153,7 +153,7 @@ static void *glz_decoder_window_bits(SpiceGlzDecoderWindow *w, uint64_t id,
.id = id - dist,
};
- g_condition_wait(wait_for_image, &data);
+ g_coroutine_condition_wait(g_coroutine_self(), wait_for_image, &data);
slot = (id - dist) % w->nimages;
}
diff --git a/gtk/gio-coroutine.c b/gtk/gio-coroutine.c
index 806dad9..355c75c 100644
--- a/gtk/gio-coroutine.c
+++ b/gtk/gio-coroutine.c
@@ -23,8 +23,8 @@
typedef struct _GConditionWaitSource
{
+ GCoroutine *self;
GSource src;
- struct coroutine *co;
GConditionWaitFunc func;
gpointer data;
} GConditionWaitSource;
@@ -70,6 +70,17 @@ GIOCondition g_coroutine_socket_wait(GCoroutine *self,
return val;
}
+void g_coroutine_condition_cancel(GCoroutine *coroutine)
+{
+ g_return_if_fail(coroutine != NULL);
+
+ if (coroutine->condition_id == 0)
+ return;
+
+ g_source_remove(coroutine->condition_id);
+ coroutine->condition_id = 0;
+}
+
void g_coroutine_wakeup(GCoroutine *coroutine)
{
g_return_if_fail(coroutine != NULL);
@@ -79,7 +90,6 @@ void g_coroutine_wakeup(GCoroutine *coroutine)
coroutine_yieldto(&coroutine->coroutine, NULL);
}
-
/*
* Call immediately before the main loop does an iteration. Returns
* true if the condition we're checking is ready for dispatch
@@ -120,15 +130,32 @@ static gboolean g_condition_wait_helper(gpointer data)
return FALSE;
}
-gboolean g_condition_wait(GConditionWaitFunc func, gpointer data)
+/*
+ * g_coroutine_condition_wait:
+ * @coroutine: the coroutine to wait on
+ * @func: the condition callback
+ * @data: the user data passed to @func callback
+ *
+ * This function will wait on caller coroutine until @func returns %TRUE.
+ *
+ * @func is called when entering the main loop from the main context (coroutine).
+ *
+ * The condition can be cancelled by calling g_coroutine_wakeup()
+ *
+ * Returns: %TRUE if condition reached, %FALSE if not and cancelled
+ */
+gboolean g_coroutine_condition_wait(GCoroutine *self, GConditionWaitFunc func, gpointer data)
{
GSource *src;
GConditionWaitSource *vsrc;
+ g_return_val_if_fail(self != NULL, FALSE);
+ g_return_val_if_fail(self->condition_id == 0, FALSE);
+ g_return_val_if_fail(func != NULL, FALSE);
+
/* Short-circuit check in case we've got it ahead of time */
- if (func(data)) {
+ if (func(data))
return TRUE;
- }
/*
* Don't have it, so yield to the main loop, checking the condition
@@ -139,13 +166,18 @@ gboolean g_condition_wait(GConditionWaitFunc func, gpointer data)
vsrc->func = func;
vsrc->data = data;
- vsrc->co = coroutine_self();
+ vsrc->self = self;
- g_source_attach(src, NULL);
- g_source_set_callback(src, g_condition_wait_helper, coroutine_self(), NULL);
+ self->condition_id = g_source_attach(src, NULL);
+ g_source_set_callback(src, g_condition_wait_helper, self, NULL);
coroutine_yield(NULL);
g_source_unref(src);
+ /* it got woked up / cancelled? */
+ if (self->condition_id == 0)
+ return func(data);
+
+ self->condition_id = 0;
return TRUE;
}
diff --git a/gtk/gio-coroutine.h b/gtk/gio-coroutine.h
index cb96a52..1c4094e 100644
--- a/gtk/gio-coroutine.h
+++ b/gtk/gio-coroutine.h
@@ -32,6 +32,7 @@ struct _GCoroutine
{
struct coroutine coroutine;
guint wait_id;
+ guint condition_id;
};
/*
@@ -47,11 +48,14 @@ typedef gboolean (*GConditionWaitFunc)(gpointer);
typedef void (*GSignalEmitMainFunc)(GObject *object, int signum, gpointer params);
-GCoroutine* g_coroutine_self (void);
-void g_coroutine_wakeup (GCoroutine *coroutine);
-GIOCondition g_coroutine_socket_wait(GCoroutine *coroutine, GSocket *sock, GIOCondition cond);
+GCoroutine* g_coroutine_self (void);
+void g_coroutine_wakeup (GCoroutine *coroutine);
+GIOCondition g_coroutine_socket_wait (GCoroutine *coroutine,
+ GSocket *sock, GIOCondition cond);
+gboolean g_coroutine_condition_wait (GCoroutine *coroutine,
+ GConditionWaitFunc func, gpointer data);
+void g_coroutine_condition_cancel(GCoroutine *coroutine);
-gboolean g_condition_wait (GConditionWaitFunc func, gpointer data);
void g_signal_emit_main_context(GObject *object, GSignalEmitMainFunc func,
int signum, gpointer params, const char *debug_info);
void g_object_notify_main_context(GObject *object, const gchar *property_name);
diff --git a/gtk/spice-channel-priv.h b/gtk/spice-channel-priv.h
index 7fa005c..ebdc5ce 100644
--- a/gtk/spice-channel-priv.h
+++ b/gtk/spice-channel-priv.h
@@ -154,7 +154,7 @@ uint16_t spice_header_get_msg_type(uint8_t *header, gboolean is_mini_header);
uint32_t spice_header_get_msg_size(uint8_t *header, gboolean is_mini_header);
void spice_channel_up(SpiceChannel *channel);
-void spice_channel_wakeup(SpiceChannel *channel);
+void spice_channel_wakeup(SpiceChannel *channel, gboolean cancel);
SpiceSession* spice_channel_get_session(SpiceChannel *channel);
diff --git a/gtk/spice-channel.c b/gtk/spice-channel.c
index 806f37c..9316f90 100644
--- a/gtk/spice-channel.c
+++ b/gtk/spice-channel.c
@@ -650,7 +650,7 @@ static gboolean spice_channel_idle_wakeup(gpointer user_data)
{
SpiceChannel *channel = SPICE_CHANNEL(user_data);
- spice_channel_wakeup(channel);
+ spice_channel_wakeup(channel, FALSE);
g_object_unref(channel);
return FALSE;
@@ -674,7 +674,7 @@ void spice_msg_out_send(SpiceMsgOut *out)
g_timeout_add_full(G_PRIORITY_HIGH, 0, spice_channel_idle_wakeup,
g_object_ref(out->channel), NULL);
else
- spice_channel_wakeup(out->channel);
+ spice_channel_wakeup(out->channel, FALSE);
}
/* coroutine context */
@@ -1690,11 +1690,14 @@ error:
/* system context */
/* TODO: we currently flush/wakeup immediately all buffered messages */
G_GNUC_INTERNAL
-void spice_channel_wakeup(SpiceChannel *channel)
+void spice_channel_wakeup(SpiceChannel *channel, gboolean cancel)
{
- SpiceChannelPrivate *c = channel->priv;
+ GCoroutine *c = &channel->priv->coroutine;
+
+ if (cancel)
+ g_coroutine_condition_cancel(c);
- g_coroutine_wakeup(&c->coroutine);
+ g_coroutine_wakeup(c);
}
G_GNUC_INTERNAL
@@ -1996,7 +1999,7 @@ static gboolean spice_channel_iterate(SpiceChannel *channel)
do {
/* freeze coroutine */
if (c->state == SPICE_CHANNEL_STATE_MIGRATING)
- g_condition_wait(wait_migration, channel);
+ g_coroutine_condition_wait(&c->coroutine, wait_migration, channel);
if (c->has_error) {
SPICE_DEBUG("channel has error, breaking loop");
@@ -2407,7 +2410,7 @@ void spice_channel_disconnect(SpiceChannel *channel, SpiceChannelEvent reason)
if (c->state == SPICE_CHANNEL_STATE_MIGRATING) {
c->state = SPICE_CHANNEL_STATE_READY;
} else
- spice_channel_wakeup(channel);
+ spice_channel_wakeup(channel, TRUE);
if (reason != SPICE_CHANNEL_NONE)
g_signal_emit(G_OBJECT(channel), signals[SPICE_CHANNEL_EVENT], 0, reason);