[libgdata] core: Ensure that synchronous progress callbacks aren't done in idle callbacks



commit baa8e41dd9079411e90c7ec3bd6381a24192bc06
Author: Philip Withnall <philip tecnocode co uk>
Date:   Tue Jun 28 00:06:26 2011 +0100

    core: Ensure that synchronous progress callbacks aren't done in idle callbacks
    
    Progress callbacks should only be made in idle callbacks if the operation is
    being performed asynchronously. If it's being performed synchronously, we
    should be able to guarantee that all progress callbacks have been executed
    by the time the synchronous operation function call returns.

 gdata/gdata-access-handler.c |   60 +++++++++++++++++-------------
 gdata/gdata-feed.c           |   20 +++++++---
 gdata/gdata-private.h        |    5 +-
 gdata/gdata-service.c        |   84 ++++++++++++++++++++++++------------------
 4 files changed, 99 insertions(+), 70 deletions(-)
---
diff --git a/gdata/gdata-access-handler.c b/gdata/gdata-access-handler.c
index ba73878..5203bc3 100644
--- a/gdata/gdata-access-handler.c
+++ b/gdata/gdata-access-handler.c
@@ -77,6 +77,37 @@ get_rules_async_data_free (GetRulesAsyncData *self)
 	g_slice_free (GetRulesAsyncData, self);
 }
 
+static GDataFeed *
+_gdata_access_handler_get_rules (GDataAccessHandler *self, GDataService *service, GCancellable *cancellable,
+                                 GDataQueryProgressCallback progress_callback, gpointer progress_user_data, gboolean is_async, GError **error)
+{
+	GDataAccessHandlerIface *iface;
+	GDataAuthorizationDomain *domain = NULL;
+	GDataFeed *feed;
+	GDataLink *_link;
+	SoupMessage *message;
+
+	_link = gdata_entry_look_up_link (GDATA_ENTRY (self), GDATA_LINK_ACCESS_CONTROL_LIST);
+	g_assert (_link != NULL);
+
+	iface = GDATA_ACCESS_HANDLER_GET_IFACE (self);
+	if (iface->get_authorization_domain != NULL) {
+		domain = iface->get_authorization_domain (self);
+	}
+
+	message = _gdata_service_query (service, domain, gdata_link_get_uri (_link), NULL, cancellable, error);
+	if (message == NULL) {
+		return NULL;
+	}
+
+	g_assert (message->response_body->data != NULL);
+	feed = _gdata_feed_new_from_xml (GDATA_TYPE_FEED, message->response_body->data, message->response_body->length, GDATA_TYPE_ACCESS_RULE,
+	                                 progress_callback, progress_user_data, is_async, error);
+	g_object_unref (message);
+
+	return feed;
+}
+
 static void
 get_rules_thread (GSimpleAsyncResult *result, GDataAccessHandler *access_handler, GCancellable *cancellable)
 {
@@ -84,8 +115,8 @@ get_rules_thread (GSimpleAsyncResult *result, GDataAccessHandler *access_handler
 	GetRulesAsyncData *data = g_simple_async_result_get_op_res_gpointer (result);
 
 	/* Execute the query and return */
-	data->feed = gdata_access_handler_get_rules (access_handler, data->service, cancellable, data->progress_callback, data->progress_user_data,
-	                                             &error);
+	data->feed = _gdata_access_handler_get_rules (access_handler, data->service, cancellable, data->progress_callback, data->progress_user_data,
+	                                              TRUE, &error);
 	if (data->feed == NULL && error != NULL) {
 		g_simple_async_result_set_from_error (result, error);
 		g_error_free (error);
@@ -173,33 +204,10 @@ GDataFeed *
 gdata_access_handler_get_rules (GDataAccessHandler *self, GDataService *service, GCancellable *cancellable,
                                 GDataQueryProgressCallback progress_callback, gpointer progress_user_data, GError **error)
 {
-	GDataAccessHandlerIface *iface;
-	GDataAuthorizationDomain *domain = NULL;
-	GDataFeed *feed;
-	GDataLink *_link;
-	SoupMessage *message;
-
 	g_return_val_if_fail (GDATA_IS_ACCESS_HANDLER (self), NULL);
 	g_return_val_if_fail (GDATA_IS_SERVICE (service), NULL);
 	g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL);
 	g_return_val_if_fail (error == NULL || *error == NULL, NULL);
 
-	_link = gdata_entry_look_up_link (GDATA_ENTRY (self), GDATA_LINK_ACCESS_CONTROL_LIST);
-	g_assert (_link != NULL);
-
-	iface = GDATA_ACCESS_HANDLER_GET_IFACE (self);
-	if (iface->get_authorization_domain != NULL) {
-		domain = iface->get_authorization_domain (self);
-	}
-
-	message = _gdata_service_query (service, domain, gdata_link_get_uri (_link), NULL, cancellable, error);
-	if (message == NULL)
-		return NULL;
-
-	g_assert (message->response_body->data != NULL);
-	feed = _gdata_feed_new_from_xml (GDATA_TYPE_FEED, message->response_body->data, message->response_body->length, GDATA_TYPE_ACCESS_RULE,
-	                                 progress_callback, progress_user_data, error);
-	g_object_unref (message);
-
-	return feed;
+	return _gdata_access_handler_get_rules (self, service, cancellable, progress_callback, progress_user_data, FALSE, error);
 }
diff --git a/gdata/gdata-feed.c b/gdata/gdata-feed.c
index dd3b6e0..868ed94 100644
--- a/gdata/gdata-feed.c
+++ b/gdata/gdata-feed.c
@@ -406,6 +406,7 @@ typedef struct {
 	GDataQueryProgressCallback progress_callback;
 	gpointer progress_user_data;
 	guint entry_i;
+	gboolean is_async;
 } ParseData;
 
 static gboolean
@@ -610,7 +611,7 @@ _gdata_feed_new (const gchar *title, const gchar *id, gint64 updated)
 
 GDataFeed *
 _gdata_feed_new_from_xml (GType feed_type, const gchar *xml, gint length, GType entry_type,
-                          GDataQueryProgressCallback progress_callback, gpointer progress_user_data, GError **error)
+                          GDataQueryProgressCallback progress_callback, gpointer progress_user_data, gboolean is_async, GError **error)
 {
 	ParseData *data;
 	GDataFeed *feed;
@@ -620,7 +621,7 @@ _gdata_feed_new_from_xml (GType feed_type, const gchar *xml, gint length, GType
 	g_return_val_if_fail (g_type_is_a (entry_type, GDATA_TYPE_ENTRY), NULL);
 	g_return_val_if_fail (error == NULL || *error == NULL, NULL);
 
-	data = _gdata_feed_parse_data_new (entry_type, progress_callback, progress_user_data);
+	data = _gdata_feed_parse_data_new (entry_type, progress_callback, progress_user_data, is_async);
 	feed = GDATA_FEED (_gdata_parsable_new_from_xml (feed_type, xml, length, data, error));
 	_gdata_feed_parse_data_free (data);
 
@@ -963,7 +964,7 @@ _gdata_feed_add_entry (GDataFeed *self, GDataEntry *entry)
 }
 
 gpointer
-_gdata_feed_parse_data_new (GType entry_type, GDataQueryProgressCallback progress_callback, gpointer progress_user_data)
+_gdata_feed_parse_data_new (GType entry_type, GDataQueryProgressCallback progress_callback, gpointer progress_user_data, gboolean is_async)
 {
 	ParseData *data;
 	data = g_slice_new (ParseData);
@@ -971,6 +972,8 @@ _gdata_feed_parse_data_new (GType entry_type, GDataQueryProgressCallback progres
 	data->progress_callback = progress_callback;
 	data->progress_user_data = progress_user_data;
 	data->entry_i = 0;
+	data->is_async = is_async;
+
 	return data;
 }
 
@@ -1005,9 +1008,14 @@ _gdata_feed_call_progress_callback (GDataFeed *self, gpointer user_data, GDataEn
 		progress_data->entry_i = data->entry_i;
 		progress_data->total_results = MIN (self->priv->items_per_page, self->priv->total_results);
 
-		/* Send the callback; use G_PRIORITY_DEFAULT rather than G_PRIORITY_DEFAULT_IDLE
-		* to contend with the priorities used by the callback functions in GAsyncResult */
-		g_idle_add_full (G_PRIORITY_DEFAULT, (GSourceFunc) progress_callback_idle, progress_data, NULL);
+		if (data->is_async == TRUE) {
+			/* Send the callback; use G_PRIORITY_DEFAULT rather than G_PRIORITY_DEFAULT_IDLE
+			* to contend with the priorities used by the callback functions in GAsyncResult */
+			g_idle_add_full (G_PRIORITY_DEFAULT, (GSourceFunc) progress_callback_idle, progress_data, NULL);
+		} else {
+			/* If we're running synchronously, just call the callbacks directly */
+			progress_callback_idle (progress_data);
+		}
 	}
 	data->entry_i++;
 }
diff --git a/gdata/gdata-private.h b/gdata/gdata-private.h
index 0c00aee..6e55451 100644
--- a/gdata/gdata-private.h
+++ b/gdata/gdata-private.h
@@ -74,10 +74,11 @@ G_GNUC_INTERNAL gboolean _gdata_parsable_is_constructed_from_xml (GDataParsable
 #include "gdata-feed.h"
 G_GNUC_INTERNAL GDataFeed *_gdata_feed_new (const gchar *title, const gchar *id, gint64 updated) G_GNUC_WARN_UNUSED_RESULT;
 G_GNUC_INTERNAL GDataFeed *_gdata_feed_new_from_xml (GType feed_type, const gchar *xml, gint length, GType entry_type,
-                                                     GDataQueryProgressCallback progress_callback, gpointer progress_user_data,
+                                                     GDataQueryProgressCallback progress_callback, gpointer progress_user_data, gboolean is_async,
                                                      GError **error) G_GNUC_WARN_UNUSED_RESULT G_GNUC_MALLOC;
 G_GNUC_INTERNAL void _gdata_feed_add_entry (GDataFeed *self, GDataEntry *entry);
-G_GNUC_INTERNAL gpointer _gdata_feed_parse_data_new (GType entry_type, GDataQueryProgressCallback progress_callback, gpointer progress_user_data);
+G_GNUC_INTERNAL gpointer _gdata_feed_parse_data_new (GType entry_type, GDataQueryProgressCallback progress_callback, gpointer progress_user_data,
+                                                     gboolean is_async);
 G_GNUC_INTERNAL void _gdata_feed_parse_data_free (gpointer data);
 G_GNUC_INTERNAL void _gdata_feed_call_progress_callback (GDataFeed *self, gpointer user_data, GDataEntry *entry);
 
diff --git a/gdata/gdata-service.c b/gdata/gdata-service.c
index b81b30a..848914c 100644
--- a/gdata/gdata-service.c
+++ b/gdata/gdata-service.c
@@ -72,6 +72,10 @@ static void notify_timeout_cb (GObject *gobject, GParamSpec *pspec, GObject *sel
 static void debug_handler (const char *log_domain, GLogLevelFlags log_level, const char *message, gpointer user_data);
 static void soup_log_printer (SoupLogger *logger, SoupLoggerLogLevel level, char direction, const char *data, gpointer user_data);
 
+static GDataFeed *__gdata_service_query (GDataService *self, GDataAuthorizationDomain *domain, const gchar *feed_uri, GDataQuery *query,
+                                         GType entry_type, GCancellable *cancellable, GDataQueryProgressCallback progress_callback,
+                                         gpointer progress_user_data, GError **error, gboolean is_async);
+
 struct _GDataServicePrivate {
 	SoupSession *session;
 	gchar *locale;
@@ -726,8 +730,8 @@ query_thread (GSimpleAsyncResult *result, GDataService *service, GCancellable *c
 	QueryAsyncData *data = g_simple_async_result_get_op_res_gpointer (result);
 
 	/* Execute the query and return */
-	data->feed = gdata_service_query (service, data->domain, data->feed_uri, data->query, data->entry_type, cancellable,
-	                                  data->progress_callback, data->progress_user_data, &error);
+	data->feed = __gdata_service_query (service, data->domain, data->feed_uri, data->query, data->entry_type, cancellable,
+	                                    data->progress_callback, data->progress_user_data, &error, TRUE);
 	if (data->feed == NULL && error != NULL) {
 		g_simple_async_result_set_from_error (result, error);
 		g_error_free (error);
@@ -867,6 +871,47 @@ _gdata_service_query (GDataService *self, GDataAuthorizationDomain *domain, cons
 	return message;
 }
 
+static GDataFeed *
+__gdata_service_query (GDataService *self, GDataAuthorizationDomain *domain, const gchar *feed_uri, GDataQuery *query, GType entry_type,
+                       GCancellable *cancellable, GDataQueryProgressCallback progress_callback, gpointer progress_user_data, GError **error,
+                       gboolean is_async)
+{
+	GDataServiceClass *klass;
+	GDataFeed *feed;
+	SoupMessage *message;
+
+	message = _gdata_service_query (self, domain, feed_uri, query, cancellable, error);
+	if (message == NULL)
+		return NULL;
+
+	g_assert (message->response_body->data != NULL);
+	klass = GDATA_SERVICE_GET_CLASS (self);
+	feed = _gdata_feed_new_from_xml (klass->feed_type, message->response_body->data, message->response_body->length, entry_type,
+	                                 progress_callback, progress_user_data, is_async, error);
+	g_object_unref (message);
+
+	if (feed == NULL)
+		return NULL;
+
+	/* Update the query with the feed's ETag */
+	if (query != NULL && feed != NULL && gdata_feed_get_etag (feed) != NULL)
+		gdata_query_set_etag (query, gdata_feed_get_etag (feed));
+
+	/* Update the query with the next and previous URIs from the feed */
+	if (query != NULL && feed != NULL) {
+		GDataLink *_link;
+
+		_link = gdata_feed_look_up_link (feed, "next");
+		if (_link != NULL)
+			_gdata_query_set_next_uri (query, gdata_link_get_uri (_link));
+		_link = gdata_feed_look_up_link (feed, "previous");
+		if (_link != NULL)
+			_gdata_query_set_previous_uri (query, gdata_link_get_uri (_link));
+	}
+
+	return feed;
+}
+
 /**
  * gdata_service_query:
  * @self: a #GDataService
@@ -907,10 +952,6 @@ GDataFeed *
 gdata_service_query (GDataService *self, GDataAuthorizationDomain *domain, const gchar *feed_uri, GDataQuery *query, GType entry_type,
                      GCancellable *cancellable, GDataQueryProgressCallback progress_callback, gpointer progress_user_data, GError **error)
 {
-	GDataServiceClass *klass;
-	GDataFeed *feed;
-	SoupMessage *message;
-
 	g_return_val_if_fail (GDATA_IS_SERVICE (self), NULL);
 	g_return_val_if_fail (domain == NULL || GDATA_IS_AUTHORIZATION_DOMAIN (domain), NULL);
 	g_return_val_if_fail (feed_uri != NULL, NULL);
@@ -918,36 +959,7 @@ gdata_service_query (GDataService *self, GDataAuthorizationDomain *domain, const
 	g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE);
 	g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
 
-	message = _gdata_service_query (self, domain, feed_uri, query, cancellable, error);
-	if (message == NULL)
-		return NULL;
-
-	g_assert (message->response_body->data != NULL);
-	klass = GDATA_SERVICE_GET_CLASS (self);
-	feed = _gdata_feed_new_from_xml (klass->feed_type, message->response_body->data, message->response_body->length, entry_type,
-	                                 progress_callback, progress_user_data, error);
-	g_object_unref (message);
-
-	if (feed == NULL)
-		return NULL;
-
-	/* Update the query with the feed's ETag */
-	if (query != NULL && feed != NULL && gdata_feed_get_etag (feed) != NULL)
-		gdata_query_set_etag (query, gdata_feed_get_etag (feed));
-
-	/* Update the query with the next and previous URIs from the feed */
-	if (query != NULL && feed != NULL) {
-		GDataLink *_link;
-
-		_link = gdata_feed_look_up_link (feed, "next");
-		if (_link != NULL)
-			_gdata_query_set_next_uri (query, gdata_link_get_uri (_link));
-		_link = gdata_feed_look_up_link (feed, "previous");
-		if (_link != NULL)
-			_gdata_query_set_previous_uri (query, gdata_link_get_uri (_link));
-	}
-
-	return feed;
+	return __gdata_service_query (self, domain, feed_uri, query, entry_type, cancellable, progress_callback, progress_user_data, error, FALSE);
 }
 
 /**



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]