summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBenjamin Otte <otte@gnome.org>2009-07-08 17:37:00 +0200
committerBenjamin Otte <otte@gnome.org>2009-07-08 17:37:00 +0200
commit81ee91ce9622f8bf269fdb2b4e6b18cb617cfcbf (patch)
tree6120e456039778e9e1440c8e15f7f3c4f2c0afb1
parent9e969883459bbc31c8709ea76dc741d6c1e6d64b (diff)
Lots of fixes for races
-rw-r--r--ephy-history.c47
1 files changed, 40 insertions, 7 deletions
diff --git a/ephy-history.c b/ephy-history.c
index 9d8d5b6..f0aad06 100644
--- a/ephy-history.c
+++ b/ephy-history.c
@@ -395,6 +395,7 @@ typedef struct {
guint progress_ms;
char *sql;
GSList *results;
+ GCancellable *cancellable;
/* need to store these because GSimpleAsyncResult doesn't allow querying */
GAsyncReadyCallback callback;
gpointer user_data;
@@ -407,13 +408,31 @@ select_data_free (gpointer data)
if (select->sql)
sqlite3_free (select->sql);
+ if (select->cancellable)
+ g_object_unref (select->cancellable);
g_slist_foreach (select->results, (GFunc) g_value_array_free, NULL);
g_slist_free (select->results);
g_slice_free (SelectData, select);
}
-/* FIXME: abort in idle callback when cancelled */
+static gboolean
+ephy_history_complete_in_idle_cb (gpointer _data)
+{
+ GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (_data);
+ SelectData *data = g_simple_async_result_get_op_res_gpointer (simple);
+
+ /*
+ * Don't complete the async result here, because then we'd
+ * get multiple cancellation errors - once for every progress
+ * update plus the final one.
+ */
+ if (!g_cancellable_is_cancelled (data->cancellable))
+ g_simple_async_result_complete (simple);
+
+ return FALSE;
+}
+
static void
ephy_history_select_emit_partial (EphyHistory *history,
GSList *list,
@@ -423,14 +442,25 @@ ephy_history_select_emit_partial (EphyHistory *history,
{
GSimpleAsyncResult *res;
SelectData *select;
+ GSource *source;
+
+ g_assert (list);
select = g_slice_new0 (SelectData);
select->results = list;
+ if (cancellable)
+ select->cancellable = g_object_ref (cancellable);
res = g_simple_async_result_new (G_OBJECT (history), callback, user_data, ephy_history_select_async);
g_simple_async_result_set_op_res_gpointer (res, select, select_data_free);
- g_simple_async_result_complete_in_idle (res);
+
+ source = g_idle_source_new ();
+ g_source_set_priority (source, G_PRIORITY_DEFAULT);
+ g_source_set_callback (source, ephy_history_complete_in_idle_cb, res, g_object_unref);
+
+ g_source_attach (source, NULL);
+ g_source_unref (source);
}
-
+
static void
ephy_history_select_thread (GSimpleAsyncResult *res,
GObject * object,
@@ -497,8 +527,8 @@ ephy_history_select_thread (GSimpleAsyncResult *res,
counter--;
if (counter == 0 ||
g_timer_elapsed (timer, NULL) > timeout) {
- ephy_history_select_emit_partial (history,
- select->results,
+ ephy_history_select_emit_partial (history,
+ g_slist_reverse (select->results),
select->callback,
select->user_data,
cancellable);
@@ -508,10 +538,11 @@ ephy_history_select_thread (GSimpleAsyncResult *res,
}
g_timer_destroy (timer);
- if (check_sqlite_result (history, res, sqlite3_finalize (stmt)))
+ if (check_sqlite_result (history, res, sqlite3_finalize (stmt)) &&
+ select->results != NULL)
{
ephy_history_select_emit_partial (history,
- select->results,
+ g_slist_reverse (select->results),
select->callback,
select->user_data,
cancellable);
@@ -545,6 +576,8 @@ ephy_history_select_async (EphyHistory * history,
select->user_data = user_data;
select->initial_results = initial_results;
select->progress_ms = progress_ms;
+ if (cancellable)
+ select->cancellable = g_object_ref (cancellable);
va_start (args, sql);
select->sql = sqlite3_vmprintf (sql, args);
va_end (args);