[libgdata] core: Port GDataDownloadStream to use the safe message cancellation methods
- From: Philip Withnall <pwithnall src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [libgdata] core: Port GDataDownloadStream to use the safe message cancellation methods
- Date: Mon, 20 Dec 2010 13:47:53 +0000 (UTC)
commit 7dfcadbc0e34e378eff8890a269e91cc0dab298e
Author: Philip Withnall <philip tecnocode co uk>
Date: Thu Dec 16 18:27:34 2010 +0000
core: Port GDataDownloadStream to use the safe message cancellation methods
GDataDownloadStream now uses _gdata_service_actually_send_message(), and
consequently message cancellation is properly an non-racily supported by
holding a GCancellable in the GDataDownloadStream's private data.
Helps: bgo#637036
gdata/gdata-download-stream.c | 51 +++++++++++++++++++++++++++++------------
1 files changed, 36 insertions(+), 15 deletions(-)
---
diff --git a/gdata/gdata-download-stream.c b/gdata/gdata-download-stream.c
index 0380ab6..a12a4a2 100644
--- a/gdata/gdata-download-stream.c
+++ b/gdata/gdata-download-stream.c
@@ -69,7 +69,9 @@ struct _GDataDownloadStreamPrivate {
SoupMessage *message;
GDataBuffer *buffer;
goffset offset; /* seek offset */
+
GThread *network_thread;
+ GCancellable *cancellable;
gboolean finished;
GCond *finished_cond;
@@ -227,8 +229,12 @@ gdata_download_stream_dispose (GObject *object)
{
GDataDownloadStreamPrivate *priv = GDATA_DOWNLOAD_STREAM (object)->priv;
- if (priv->network_thread != NULL)
- g_thread_join (priv->network_thread);
+ /* Block on closing the stream */
+ g_input_stream_close (G_INPUT_STREAM (object), NULL, NULL);
+
+ if (priv->cancellable != NULL)
+ g_object_unref (priv->cancellable);
+ priv->cancellable = NULL;
if (priv->service != NULL)
g_object_unref (priv->service);
@@ -354,9 +360,9 @@ gdata_download_stream_close (GInputStream *stream, GCancellable *cancellable, GE
g_static_mutex_lock (&(priv->finished_mutex));
- /* If the operation has started but hasn't already finished, cancel the SoupMessage and wait for it to finish before returning */
+ /* If the operation has started but hasn't already finished, cancel the network thread and wait for it to finish before returning */
if (priv->network_thread != NULL && priv->finished == FALSE) {
- soup_session_cancel_message (priv->session, priv->message, SOUP_STATUS_CANCELLED);
+ g_cancellable_cancel (priv->cancellable);
g_cond_wait (priv->finished_cond, g_static_mutex_get_mutex (&(priv->finished_mutex)));
}
@@ -399,12 +405,9 @@ gdata_download_stream_seek (GSeekable *seekable, goffset offset, GSeekType type,
return FALSE;
/* Cancel the current network thread if it exists */
- if (priv->network_thread != NULL) {
- soup_session_cancel_message (priv->session, priv->message, SOUP_STATUS_CANCELLED);
- soup_message_io_cleanup (priv->message);
-
- g_thread_join (priv->network_thread);
- }
+ if (gdata_download_stream_close (G_INPUT_STREAM (seekable), NULL, error) == FALSE)
+ goto done;
+ soup_message_io_cleanup (priv->message);
switch (type) {
case G_SEEK_CUR:
@@ -427,6 +430,7 @@ gdata_download_stream_seek (GSeekable *seekable, goffset offset, GSeekType type,
/* Launch a new thread with the modified message */
create_network_thread (GDATA_DOWNLOAD_STREAM (seekable), error);
+done:
g_input_stream_clear_pending (G_INPUT_STREAM (seekable));
if (priv->network_thread == NULL)
@@ -497,12 +501,16 @@ finished_cb (SoupMessage *message, GDataDownloadStream *self)
static gpointer
download_thread (GDataDownloadStream *self)
{
+ GDataDownloadStreamPrivate *priv = self->priv;
+
+ g_assert (priv->cancellable != NULL);
+
/* Connect to the got-headers signal so we can notify clients of the values of content-type and content-length */
- g_signal_connect (self->priv->message, "got-headers", (GCallback) got_headers_cb, self);
- g_signal_connect (self->priv->message, "got-chunk", (GCallback) got_chunk_cb, self);
- g_signal_connect (self->priv->message, "finished", (GCallback) finished_cb, self);
+ g_signal_connect (priv->message, "got-headers", (GCallback) got_headers_cb, self);
+ g_signal_connect (priv->message, "got-chunk", (GCallback) got_chunk_cb, self);
+ g_signal_connect (priv->message, "finished", (GCallback) finished_cb, self);
- soup_session_send_message (self->priv->session, self->priv->message);
+ _gdata_service_actually_send_message (priv->session, priv->message, priv->cancellable, NULL);
return NULL;
}
@@ -510,7 +518,20 @@ download_thread (GDataDownloadStream *self)
static void
create_network_thread (GDataDownloadStream *self, GError **error)
{
- self->priv->network_thread = g_thread_create ((GThreadFunc) download_thread, self, TRUE, error);
+ GDataDownloadStreamPrivate *priv = self->priv;
+ GError *child_error = NULL;
+
+ g_assert (priv->cancellable == NULL);
+ g_assert (priv->network_thread == NULL);
+
+ priv->cancellable = g_cancellable_new ();
+ priv->network_thread = g_thread_create ((GThreadFunc) download_thread, self, TRUE, &child_error);
+
+ if (child_error != NULL) {
+ g_object_unref (priv->cancellable);
+ priv->cancellable = NULL;
+ g_propagate_error (error, child_error);
+ }
}
/**
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]