[gnome-system-log] log: use a GCancellable when reading new lines from the log



commit 0aeb30fae9b5855804240972790045074854f1aa
Author: Cosimo Cecchi <cosimoc gnome org>
Date:   Thu Apr 11 16:34:10 2013 -0400

    log: use a GCancellable when reading new lines from the log
    
    So we can cancel the operation when the active log changes. This fixes a
    segfault where we would receive a read callback for a log that was
    already removed when closing logs in a row.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=697790

 src/logview-log.c       |   10 ++++++++--
 src/logview-log.h       |    1 +
 src/logview-window.c    |   40 +++++++++++++++++++++++++++++++++-------
 src/tests/test-reader.c |    2 +-
 4 files changed, 43 insertions(+), 10 deletions(-)
---
diff --git a/src/logview-log.c b/src/logview-log.c
index f0c9e8c..292f160 100644
--- a/src/logview-log.c
+++ b/src/logview-log.c
@@ -78,6 +78,7 @@ typedef struct {
   GError *err;
   const char **lines;
   GSList *new_days;
+  GCancellable *cancellable;
   LogviewNewLinesCallback callback;
   gpointer user_data;
 } NewLinesJob;
@@ -253,6 +254,8 @@ new_lines_job_done (gpointer data)
     job->callback (job->log, job->lines, job->new_days, job->err, job->user_data);
   }
 
+  g_clear_object (&job->cancellable);
+
   g_slist_foreach (job->new_days, (GFunc) logview_utils_day_free, NULL);
   g_slist_free (job->new_days);
 
@@ -290,7 +293,7 @@ do_read_new_lines (GIOSchedulerJob *io_job,
   g_ptr_array_remove_index (lines, lines->len - 1);
 
   while ((line = g_data_input_stream_read_line (log->priv->stream, NULL,
-                                                NULL, &err)) != NULL)
+                                                job->cancellable, &err)) != NULL)
   {
     g_ptr_array_add (lines, (gpointer) line);
   }
@@ -798,6 +801,7 @@ log_setup_load (LogviewLog *log, LogviewCreateCallback callback,
 
 void
 logview_log_read_new_lines (LogviewLog *log,
+                            GCancellable *cancellable,
                             LogviewNewLinesCallback callback,
                             gpointer user_data)
 {
@@ -807,6 +811,7 @@ logview_log_read_new_lines (LogviewLog *log,
   job = g_slice_new0 (NewLinesJob);
   job->callback = callback;
   job->user_data = user_data;
+  job->cancellable = (cancellable != NULL) ? g_object_ref (cancellable) : NULL;
   job->log = g_object_ref (log);
   job->err = NULL;
   job->lines = NULL;
@@ -815,7 +820,8 @@ logview_log_read_new_lines (LogviewLog *log,
   /* push the fetching job into another thread */
   g_io_scheduler_push_job (do_read_new_lines,
                            job,
-                           NULL, 0, NULL);
+                           NULL, 0,
+                           job->cancellable);
 }
 
 void
diff --git a/src/logview-log.h b/src/logview-log.h
index 6e69ad8..4f81af1 100644
--- a/src/logview-log.h
+++ b/src/logview-log.h
@@ -90,6 +90,7 @@ void          logview_log_create_from_gfile        (GFile *file,
                                                     LogviewCreateCallback callback,
                                                     gpointer user_data);
 void          logview_log_read_new_lines           (LogviewLog *log,
+                                                    GCancellable *cancellable,
                                                     LogviewNewLinesCallback callback,
                                                     gpointer user_data);
 
diff --git a/src/logview-window.c b/src/logview-window.c
index ef5c29f..93e5bc5 100644
--- a/src/logview-window.c
+++ b/src/logview-window.c
@@ -65,6 +65,8 @@ struct _LogviewWindowPrivate {
   gulong monitor_id;
   guint search_timeout_id;
 
+  GCancellable *read_cancellable;
+
   guint filter_merge_id;
   GList *active_filters;
   gboolean matches_only;
@@ -645,12 +647,29 @@ loglist_day_cleared_cb (LogviewLoglist *loglist,
 }
 
 static void
+logview_window_schedule_log_read (LogviewWindow *window,
+                                  LogviewLog *log)
+{
+  if (window->priv->read_cancellable != NULL) {
+    g_cancellable_cancel (window->priv->read_cancellable);
+    g_clear_object (&window->priv->read_cancellable);
+  }
+
+  window->priv->read_cancellable = g_cancellable_new ();
+  logview_log_read_new_lines (log,
+                              window->priv->read_cancellable,
+                              (LogviewNewLinesCallback) read_new_lines_cb,
+                              window);
+}
+
+static void
 log_monitor_changed_cb (LogviewLog *log,
                         gpointer user_data)
 {
+  LogviewWindow *window = user_data;
+
   /* reschedule a read */
-  logview_log_read_new_lines (log, (LogviewNewLinesCallback) read_new_lines_cb,
-                              user_data);
+  logview_window_schedule_log_read (window, log);
 }
 
 static void
@@ -686,10 +705,12 @@ read_new_lines_cb (LogviewLog *log,
   gsize len;
 
   if (error != NULL) {
-    primary = g_strdup_printf (_("Can't read from \"%s\""),
-                               logview_log_get_display_name (log));
-    logview_window_add_error (window, primary, error->message);
-    g_free (primary);
+    if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
+      primary = g_strdup_printf (_("Can't read from \"%s\""),
+                                 logview_log_get_display_name (log));
+      logview_window_add_error (window, primary, error->message);
+      g_free (primary);
+    }
 
     return;
   }
@@ -794,7 +815,7 @@ active_log_changed_cb (LogviewManager *manager,
 
   if (lines == NULL || logview_log_has_new_lines (log)) {
     /* read the new lines */
-    logview_log_read_new_lines (log, (LogviewNewLinesCallback) read_new_lines_cb, window);
+    logview_window_schedule_log_read (window, log);
   } else {
     /* start now monitoring the log for changes */
     window->priv->monitor_id = g_signal_connect (log, "log-changed",
@@ -909,6 +930,11 @@ logview_window_finalize (GObject *object)
 {
   LogviewWindow *logview = LOGVIEW_WINDOW (object);
 
+  if (logview->priv->read_cancellable != NULL) {
+    g_cancellable_cancel (logview->priv->read_cancellable);
+    g_clear_object (&logview->priv->read_cancellable);
+  }
+
   g_clear_object (&logview->priv->filters_placeholder);
   pango_font_description_free (logview->priv->monospace_description);
 
diff --git a/src/tests/test-reader.c b/src/tests/test-reader.c
index 77cc64e..b687ed1 100644
--- a/src/tests/test-reader.c
+++ b/src/tests/test-reader.c
@@ -46,7 +46,7 @@ callback (LogviewLog *log,
 {
   g_print ("callback! err %p, log %p\n", error, log);
 
-  logview_log_read_new_lines (log, new_lines_cb, NULL);
+  logview_log_read_new_lines (log, NULL, new_lines_cb, NULL);
 }
 
 int main (int argc, char **argv)


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