summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGeorges Basile Stavracas Neto <georges.stavracas@gmail.com>2023-03-10 13:19:30 -0300
committerGeorges Basile Stavracas Neto <georges.stavracas@gmail.com>2023-03-16 12:27:47 +0000
commitdaec07c9f682967e2e1fc74494762e94bd3ed64b (patch)
tree4a1c7218a5f2857114c7576b9b66301256a8519e
parentf751803e07d08bb72b84fc6a3007c744cb36727c (diff)
downloadgnome-calendar-daec07c9f682967e2e1fc74494762e94bd3ed64b.tar.gz
search: Rework threading
Search uses GcalTimeline, an object that is meant to be single threaded, in multple threads. That mostly worked okay because GcalTimeline mostly relies on GcalCalendarMonitor, which is heavily threaded. But, sometimes it failed. Rework that to be single-threaded, and asynchronous. Closes https://gitlab.gnome.org/GNOME/gnome-calendar/-/issues/981 Closes https://gitlab.gnome.org/GNOME/gnome-calendar/-/issues/987 Closes https://gitlab.gnome.org/GNOME/gnome-calendar/-/issues/988
-rw-r--r--src/search/gcal-search-engine.c102
-rw-r--r--src/search/gcal-search-model.c74
-rw-r--r--src/search/gcal-search-model.h8
3 files changed, 100 insertions, 84 deletions
diff --git a/src/search/gcal-search-engine.c b/src/search/gcal-search-engine.c
index 253daff8..47179ae6 100644
--- a/src/search/gcal-search-engine.c
+++ b/src/search/gcal-search-engine.c
@@ -22,20 +22,12 @@
#include "gcal-context.h"
#include "gcal-date-time-utils.h"
+#include "gcal-debug.h"
#include "gcal-search-engine.h"
#include "gcal-search-model.h"
#include "gcal-timeline.h"
#include "gcal-timeline-subscriber.h"
-typedef struct
-{
- GcalSearchEngine *engine;
- gchar *query;
- gint max_results;
- GDateTime *range_start;
- GDateTime *range_end;
-} SearchData;
-
struct _GcalSearchEngine
{
GObject parent;
@@ -58,59 +50,10 @@ static GParamSpec *properties [N_PROPS];
/*
- * Auxiliary methods
- */
-
-static void
-search_data_free (gpointer data)
-{
- SearchData *search_data = data;
-
- if (!data)
- return;
-
- gcal_clear_date_time (&search_data->range_start);
- gcal_clear_date_time (&search_data->range_end);
- g_clear_pointer (&search_data->query, g_free);
- g_clear_object (&search_data->engine);
- g_slice_free (SearchData, data);
-}
-
-
-/*
* Callbacks
*/
static void
-search_func (GTask *task,
- gpointer source_object,
- gpointer task_data,
- GCancellable *cancellable)
-{
- g_autoptr (GcalSearchModel) model = NULL;
- GcalSearchEngine *self;
- SearchData *data;
-
- self = GCAL_SEARCH_ENGINE (source_object);
- data = (SearchData*) task_data;
-
- model = gcal_search_model_new (cancellable,
- data->max_results,
- data->range_start,
- data->range_end);
-
- gcal_timeline_set_filter (self->timeline, data->query);
- gcal_timeline_add_subscriber (self->timeline, GCAL_TIMELINE_SUBSCRIBER (model));
-
- gcal_search_model_wait_for_hits (model, cancellable);
-
- if (g_cancellable_is_cancelled (cancellable))
- g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_CANCELLED, "Cancelled");
- else
- g_task_return_pointer (task, g_steal_pointer (&model), g_object_unref);
-}
-
-static void
on_manager_calendar_added_cb (GcalManager *manager,
GcalCalendar *calendar,
GcalSearchEngine *self)
@@ -130,6 +73,31 @@ on_manager_calendar_removed_cb (GcalManager *manager,
gcal_timeline_remove_calendar (self->timeline, calendar);
}
+static void
+search_model_hits_cb (GObject *source,
+ GAsyncResult *result,
+ gpointer data)
+{
+ g_autoptr (GError) error = NULL;
+ g_autoptr (GTask) task = data;
+ GcalSearchModel *search_model;
+
+ GCAL_ENTRY;
+
+ search_model = GCAL_SEARCH_MODEL (source);
+ gcal_search_model_wait_for_hits_finish (search_model, result, &error);
+
+ if (error)
+ {
+ g_task_return_error (task, g_steal_pointer (&error));
+ GCAL_RETURN ();
+ }
+
+ g_task_return_pointer (task, g_object_ref (search_model), NULL);
+
+ GCAL_EXIT;
+}
+
/*
* GObject overrides
@@ -246,9 +214,11 @@ gcal_search_engine_search (GcalSearchEngine *self,
GAsyncReadyCallback callback,
gpointer user_data)
{
+ g_autoptr (GcalSearchModel) model = NULL;
+ g_autoptr (GDateTime) range_start = NULL;
+ g_autoptr (GDateTime) range_end = NULL;
g_autoptr (GDateTime) now = NULL;
g_autoptr (GTask) task = NULL;
- SearchData *data = NULL;
GTimeZone *timezone;
g_return_if_fail (GCAL_IS_SEARCH_ENGINE (self));
@@ -256,20 +226,18 @@ gcal_search_engine_search (GcalSearchEngine *self,
timezone = gcal_context_get_timezone (self->context);
now = g_date_time_new_now (timezone);
+ range_start = g_date_time_add_weeks (now, -1);
+ range_end = g_date_time_add_weeks (now, 3);
+ model = gcal_search_model_new (cancellable, max_results, range_start, range_end);
- data = g_slice_new0 (SearchData);
- data->engine = g_object_ref (self);
- data->query = g_strdup (search_query);
- data->max_results = max_results;
- data->range_start = g_date_time_add_weeks (now, -1);
- data->range_end = g_date_time_add_weeks (now, 3);
+ gcal_timeline_set_filter (self->timeline, search_query);
+ gcal_timeline_add_subscriber (self->timeline, GCAL_TIMELINE_SUBSCRIBER (model));
task = g_task_new (self, cancellable, callback, user_data);
g_task_set_source_tag (task, gcal_search_engine_search);
g_task_set_priority (task, G_PRIORITY_LOW);
- g_task_set_task_data (task, data, (GDestroyNotify) search_data_free);
- g_task_run_in_thread (task, search_func);
+ gcal_search_model_wait_for_hits (model, cancellable, search_model_hits_cb, g_object_ref (task));
}
GListModel*
diff --git a/src/search/gcal-search-model.c b/src/search/gcal-search-model.c
index 892878b3..08cc0370 100644
--- a/src/search/gcal-search-model.c
+++ b/src/search/gcal-search-model.c
@@ -42,6 +42,9 @@ struct _GcalSearchModel
GDateTime *range_end;
GListModel *model;
+
+ GTimer *timer;
+ guint idle_id;
};
static void gcal_timeline_subscriber_interface_init (GcalTimelineSubscriberInterface *iface);
@@ -58,6 +61,33 @@ G_DEFINE_TYPE_WITH_CODE (GcalSearchModel, gcal_search_model, G_TYPE_OBJECT,
* Callbacks
*/
+static gboolean
+check_for_search_hits_cb (gpointer user_data)
+{
+ GcalSearchModel *self;
+ GTask *task;
+
+ task = G_TASK (user_data);
+ self = GCAL_SEARCH_MODEL (g_task_get_source_object (task));
+
+ if (g_task_return_error_if_cancelled (task))
+ goto stop_idle;
+
+ if (g_timer_elapsed (self->timer, NULL) >= WAIT_FOR_RESULTS_MS ||
+ g_list_model_get_n_items (self->model) >= MIN_RESULTS)
+ {
+ g_task_return_boolean (task, TRUE);
+ goto stop_idle;
+ }
+
+ return G_SOURCE_CONTINUE;
+
+stop_idle:
+ g_clear_pointer (&self->timer, g_timer_destroy);
+ self->idle_id = 0;
+ return G_SOURCE_REMOVE;
+}
+
static void
on_model_items_changed_cb (GListModel *model,
guint position,
@@ -208,6 +238,9 @@ gcal_search_model_finalize (GObject *object)
{
GcalSearchModel *self = (GcalSearchModel *)object;
+ g_assert (self->timer == NULL);
+ g_assert (self->idle_id == 0);
+
g_cancellable_cancel (self->cancellable);
gcal_clear_date_time (&self->range_start);
@@ -251,29 +284,38 @@ gcal_search_model_new (GCancellable *cancellable,
}
void
-gcal_search_model_wait_for_hits (GcalSearchModel *self,
- GCancellable *cancellable)
+gcal_search_model_wait_for_hits (GcalSearchModel *self,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
{
- g_autoptr (GMainContext) thread_context = NULL;
- g_autoptr (GTimer) timer = NULL;
+ g_autoptr (GTask) task = NULL;
GCAL_ENTRY;
- g_return_if_fail (GCAL_IS_SEARCH_MODEL (self));
+ g_assert (self->timer == NULL);
+ g_assert (self->idle_id == 0);
- thread_context = g_main_context_ref_thread_default ();
- timer = g_timer_new ();
+ task = g_task_new (self, cancellable, callback, user_data);
+ g_task_set_source_tag (task, gcal_search_model_wait_for_hits);
+ g_task_set_priority (task, G_PRIORITY_LOW);
- g_timer_start (timer);
+ self->timer = g_timer_new ();
+ self->idle_id = g_idle_add_full (G_PRIORITY_LOW,
+ check_for_search_hits_cb,
+ g_object_ref (task),
+ g_object_unref);
- while (g_list_model_get_n_items (self->model) < MIN_RESULTS &&
- g_timer_elapsed (timer, NULL) < WAIT_FOR_RESULTS_MS)
- {
- if (g_cancellable_is_cancelled (cancellable))
- break;
+ GCAL_EXIT;
+}
- g_main_context_iteration (thread_context, FALSE);
- }
+gboolean
+gcal_search_model_wait_for_hits_finish (GcalSearchModel *self,
+ GAsyncResult *result,
+ GError **error)
+{
+ g_return_val_if_fail (GCAL_IS_SEARCH_MODEL (self), FALSE);
+ g_return_val_if_fail (g_task_is_valid (result, self), FALSE);
- GCAL_EXIT;
+ return g_task_propagate_boolean (G_TASK (result), error);
}
diff --git a/src/search/gcal-search-model.h b/src/search/gcal-search-model.h
index 97775834..8f040a00 100644
--- a/src/search/gcal-search-model.h
+++ b/src/search/gcal-search-model.h
@@ -33,6 +33,12 @@ GcalSearchModel* gcal_search_model_new (GCancellable
GDateTime *range_end);
void gcal_search_model_wait_for_hits (GcalSearchModel *self,
- GCancellable *cancellable);
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+
+gboolean gcal_search_model_wait_for_hits_finish (GcalSearchModel *self,
+ GAsyncResult *result,
+ GError **error);
G_END_DECLS