]> granicus.if.org Git - mutt/commitdiff
Work around open mailbox monitor code check issue.
authorKevin McCarthy <kevin@8t8.us>
Tue, 26 Jun 2018 00:54:43 +0000 (17:54 -0700)
committerKevin McCarthy <kevin@8t8.us>
Tue, 26 Jun 2018 00:54:43 +0000 (17:54 -0700)
The monitor code is too fast, and can result in all the changes for a
single directory stat update being missed.

Work around this issue by not recording stat time updates when the
check_mailbox() is triggered by the monitor.  This will cause the next
subsequent check to take another look.

mh.c
monitor.c
monitor.h

diff --git a/mh.c b/mh.c
index a48dd832d5449ff1fbe0912aeaa0afbe17f15721..cda81fe80b545df47321ebfa6be67c328ca01c02 100644 (file)
--- a/mh.c
+++ b/mh.c
@@ -37,6 +37,9 @@
 #endif
 #include "mutt_curses.h"
 #include "buffy.h"
+#ifdef USE_INOTIFY
+#include "monitor.h"
+#endif
 
 #include <sys/stat.h>
 #include <sys/types.h>
@@ -2123,9 +2126,21 @@ static int maildir_check_mailbox (CONTEXT * ctx, int *index_hint)
   if (!changed)
     return 0;                  /* nothing to do */
 
-  /* update the modification times on the mailbox */
-  mutt_get_stat_timespec (&data->mtime_cur, &st_cur, MUTT_STAT_MTIME);
-  mutt_get_stat_timespec (&ctx->mtime, &st_new, MUTT_STAT_MTIME);
+  /* Update the modification times on the mailbox.
+   *
+   * The monitor code notices changes in the open mailbox too quickly.
+   * In practice, this sometimes leads to all the new messages not being
+   * noticed during the SAME group of mtime stat updates.  To work around
+   * the problem, don't update the stat times for a monitor caused check. */
+#ifdef USE_INOTIFY
+  if (MonitorContextChanged)
+    MonitorContextChanged = 0;
+  else
+#endif
+  {
+    mutt_get_stat_timespec (&data->mtime_cur, &st_cur, MUTT_STAT_MTIME);
+    mutt_get_stat_timespec (&ctx->mtime, &st_new, MUTT_STAT_MTIME);
+  }
 
   /* do a fast scan of just the filenames in
    * the subdirectories that have changed.
@@ -2287,8 +2302,21 @@ static int mh_check_mailbox (CONTEXT * ctx, int *index_hint)
   if (!modified)
     return 0;
 
-  mutt_get_stat_timespec (&data->mtime_cur, &st_cur, MUTT_STAT_MTIME);
-  mutt_get_stat_timespec (&ctx->mtime, &st, MUTT_STAT_MTIME);
+  /* Update the modification times on the mailbox.
+   *
+   * The monitor code notices changes in the open mailbox too quickly.
+   * In practice, this sometimes leads to all the new messages not being
+   * noticed during the SAME group of mtime stat updates.  To work around
+   * the problem, don't update the stat times for a monitor caused check. */
+#ifdef USE_INOTIFY
+  if (MonitorContextChanged)
+    MonitorContextChanged = 0;
+  else
+#endif
+  {
+    mutt_get_stat_timespec (&data->mtime_cur, &st_cur, MUTT_STAT_MTIME);
+    mutt_get_stat_timespec (&ctx->mtime, &st, MUTT_STAT_MTIME);
+  }
 
   memset (&mhs, 0, sizeof (mhs));
 
index 7979897a2c9e82b7eca3c6ce7b489e248cdb589c..da9afc6985d52ef4a96d2a37b202fc7445f22fb6 100644 (file)
--- a/monitor.c
+++ b/monitor.c
@@ -52,6 +52,8 @@ static size_t PollFdsCount = 0;
 static size_t PollFdsLen = 0;
 static struct pollfd *PollFds;
 
+static int MonitorContextDescriptor = -1;
+
 typedef struct monitorinfo_t
 {
   short magic;
@@ -193,6 +195,9 @@ static int monitor_handle_ignore (int descr)
       dprint (3, (debugfile, "monitor: cleanup watch (implicitly removed) - descriptor=%d\n", descr));
     }
 
+    if (MonitorContextDescriptor == descr)
+      MonitorContextDescriptor = new_descr;
+
     if (new_descr == -1)
     {
       monitor_delete (iter);
@@ -275,6 +280,8 @@ int mutt_monitor_poll (void)
                             event->wd, event->mask));
                 if (event->mask & IN_IGNORED)
                   monitor_handle_ignore (event->wd);
+                else if (event->wd == MonitorContextDescriptor)
+                  MonitorContextChanged = 1;
                 ptr += sizeof(struct inotify_event) + event->len;
               }
             }
@@ -374,7 +381,11 @@ int mutt_monitor_add (BUFFY *buffy)
 
   descr = monitor_resolve (&info, buffy);
   if (descr != RESOLVERES_OK_NOTEXISTING)
+  {
+    if (!buffy && (descr == RESOLVERES_OK_EXISTING))
+      MonitorContextDescriptor = info.monitor->descr;
     return descr == RESOLVERES_OK_EXISTING ? 0 : -1;
+  }
 
   mask = info.isdir ? INOTIFY_MASK_DIR : INOTIFY_MASK_FILE;
   if ((INotifyFd == -1 && monitor_init () == -1)
@@ -385,6 +396,9 @@ int mutt_monitor_add (BUFFY *buffy)
   }
 
   dprint (3, (debugfile, "monitor: inotify_add_watch descriptor=%d for '%s'\n", descr, info.path));
+  if (!buffy)
+    MonitorContextDescriptor = descr;
+
   monitor_create (&info, descr);
   return 0;
 }
@@ -421,6 +435,9 @@ int mutt_monitor_remove (BUFFY *buffy)
   inotify_rm_watch(info.monitor->descr, INotifyFd);
   dprint (3, (debugfile, "monitor: inotify_rm_watch for '%s' descriptor=%d\n", info.path, info.monitor->descr));
 
+  if (!buffy && (MonitorContextDescriptor == info.monitor->descr))
+    MonitorContextDescriptor = -1;
+
   monitor_delete (info.monitor);
   monitor_check_free ();
   return 0;
index cd4918b264000e922098e1cb143d6ef4b66419ad..3f21413dd90286ff54e2a9c0999c36163b68ece3 100644 (file)
--- a/monitor.h
+++ b/monitor.h
@@ -20,6 +20,7 @@
 #define MONITOR_H
 
 WHERE int MonitorFilesChanged INITVAL (0);
+WHERE int MonitorContextChanged INITVAL (0);
 
 #ifdef _BUFFY_H
 int mutt_monitor_add (BUFFY *b);