[geany/geany-plugins] 84745f: git-changebar: Fix a race condition updating the diff

Colomban Wendling git-noreply at xxxxx
Tue Jun 23 20:29:34 UTC 2015


Branch:      refs/heads/master
Author:      Colomban Wendling <ban at herbesfolles.org>
Committer:   Colomban Wendling <ban at herbesfolles.org>
Date:        Tue, 23 Jun 2015 20:29:34 UTC
Commit:      84745fe6046fcab626f7dd68e91b44f5f48c1090
             https://github.com/geany/geany-plugins/commit/84745fe6046fcab626f7dd68e91b44f5f48c1090

Log Message:
-----------
git-changebar: Fix a race condition updating the diff

As the updates are delayed through an idle callback, but the cached
contents is cleared right when scheduling the idle callback, and the
thread also reports results through idle callbacks, it is possible for
a thread job to be reported between the moment the cached content is
cleared and the idle callback checks for the cache, leading to the use
of that job's result instead of scheduling a new one.

Fix this by tagging the cache with the document ID, allowing to check
not only if the cache is present but also whether it is actually valid
for the requested update.

Closes #244.


Modified Paths:
--------------
    git-changebar/src/gcb-plugin.c

Modified: git-changebar/src/gcb-plugin.c
25 lines changed, 17 insertions(+), 8 deletions(-)
===================================================================
@@ -82,6 +82,7 @@ typedef void (*BlobContentsReadyFunc) (const gchar *path,
 typedef struct AsyncBlobContentsJob AsyncBlobContentsJob;
 struct AsyncBlobContentsJob {
   gboolean              force;
+  guint                 tag;
   gchar                *path;
   git_buf               buf;
   BlobContentsReadyFunc callback;
@@ -140,6 +141,7 @@ static void         write_setting_boolean       (GKeyFile      *kf,
 
 /* cache */
 static git_buf          G_blob_contents       = { 0 };
+static guint            G_blob_contents_tag   = 0;
 /* global state */
 static GAsyncQueue     *G_queue               = NULL;
 static GThread         *G_thread              = NULL;
@@ -213,6 +215,7 @@ clear_cached_blob_contents (void)
     git_buf_free (&G_blob_contents);
     buf_zero (&G_blob_contents);
   }
+  G_blob_contents_tag = 0;
 }
 
 /* get the file blob for @relpath at HEAD */
@@ -278,6 +281,7 @@ report_work_in_idle (gpointer data)
   /* update cached blob */
   clear_cached_blob_contents ();
   G_blob_contents = job->buf;
+  G_blob_contents_tag = job->buf.ptr ? job->tag : 0;
   
   job->callback (job->path, job->buf.ptr ? &job->buf : NULL, job->user_data);
   
@@ -455,16 +459,19 @@ worker_thread (gpointer data)
 
 static void
 get_cached_blob_contents_async (const gchar          *path,
+                                guint                 tag,
                                 gboolean              force,
                                 BlobContentsReadyFunc callback,
                                 gpointer              user_data)
 {
-  if ((! force && G_blob_contents.ptr) || ! path) {
+  if ((! force && G_blob_contents.ptr && tag == G_blob_contents_tag) ||
+      ! path) {
     callback (path, &G_blob_contents, user_data);
   } else {
     AsyncBlobContentsJob *job = g_slice_alloc (sizeof *job);
     
     job->force      = force;
+    job->tag        = tag;
     job->path       = g_strdup (path);
     job->callback   = callback;
     job->user_data  = user_data;
@@ -801,7 +808,8 @@ on_sci_query_tooltip (GtkWidget  *widget,
   min_x = scintilla_send_message (sci, SCI_GETMARGINWIDTHN, 0, 0);
   max_x = min_x + scintilla_send_message (sci, SCI_GETMARGINWIDTHN, 1, 0);
   
-  if (x >= min_x && x <= max_x && G_blob_contents.ptr) {
+  if (x >= min_x && x <= max_x &&
+      G_blob_contents.ptr && G_blob_contents_tag == doc->id) {
     gint pos  = scintilla_send_message (sci, SCI_POSITIONFROMPOINT, x, y);
     gint line = sci_get_line_from_position (sci, pos);
     gint mask = scintilla_send_message (sci, SCI_MARKERGET, line, 0);
@@ -861,7 +869,7 @@ do_update_diff_idle (guint    doc_id,
   G_source_id = 0;
   /* make sure the document is still valid and current */
   if (doc && doc->id == doc_id) {
-    get_cached_blob_contents_async (doc->real_path, force, update_diff,
+    get_cached_blob_contents_async (doc->real_path, doc_id, force, update_diff,
                                     GUINT_TO_POINTER (doc->id));
   }
   
@@ -1024,8 +1032,8 @@ on_kb_goto_next_hunk (guint kb)
     data->line      = sci_get_current_line (doc->editor->sci);
     data->next_line = -1;
     
-    get_cached_blob_contents_async (doc->real_path, FALSE, goto_next_hunk_cb,
-                                    data);
+    get_cached_blob_contents_async (doc->real_path, doc->id, FALSE,
+                                    goto_next_hunk_cb, data);
   }
 }
 
@@ -1197,9 +1205,10 @@ plugin_init (GeanyData *data)
   GeanyKeyGroup *kb_group;
   
   buf_zero (&G_blob_contents);
-  G_source_id = 0;
-  G_thread    = NULL;
-  G_queue     = NULL;
+  G_blob_contents_tag = 0;
+  G_source_id         = 0;
+  G_thread            = NULL;
+  G_queue             = NULL;
   
   if (git_libgit2_init () < 0) {
     const git_error *err = giterr_last ();



--------------
This E-Mail was brought to you by github_commit_mail.py (Source: https://github.com/geany/infrastructure).


More information about the Plugins-Commits mailing list