[libgdata] core: Port GDataDownloadStream to use the safe message cancellation methods



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]