]> granicus.if.org Git - neomutt/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)
committerRichard Russon <rich@flatcap.org>
Mon, 3 Sep 2018 01:04:32 +0000 (02:04 +0100)
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.

maildir/mh.c
monitor.c
monitor.h

index b106ba1722d086d0b8367428975ec904c716f6eb..4ecf442b21a6bbcf2d35f1dc3fb14794bd30ce45 100644 (file)
@@ -64,6 +64,9 @@
 #ifdef USE_HCACHE
 #include "hcache/hcache.h"
 #endif
+#ifdef USE_INOTIFY
+#include "monitor.h"
+#endif
 
 /* These Config Variables are only used in maildir/mh.c */
 bool CheckNew; ///< Config: (maildir,mh) Check for new mail while the mailbox is open
@@ -2348,9 +2351,21 @@ static int maildir_mbox_check(struct 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.
@@ -2516,8 +2531,21 @@ static int mh_mbox_check(struct 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);
+  }
 
   md = NULL;
   last = &md;
index 48b5c7960946c951d49bbdc89562c00ff876da64..620b5e5a718a98239979465879c449e26c78705c 100644 (file)
--- a/monitor.c
+++ b/monitor.c
@@ -41,6 +41,7 @@
 #include "mx.h"
 
 int MonitorFilesChanged;
+int MonitorContextChanged;
 
 struct Monitor
 {
@@ -58,6 +59,8 @@ static size_t PollFdsCount = 0;
 static size_t PollFdsLen = 0;
 static struct pollfd *PollFds;
 
+static int MonitorContextDescriptor = -1;
+
 struct MonitorInfo
 {
   short magic;
@@ -174,7 +177,7 @@ static void monitor_delete(struct Monitor *monitor)
 
 static int monitor_handle_ignore(int desc)
 {
-  int new_descr = -1;
+  int new_desc = -1;
   struct Monitor *iter = Monitor;
   struct stat sb;
 
@@ -185,7 +188,7 @@ static int monitor_handle_ignore(int desc)
   {
     if (iter->magic == MUTT_MH && stat(iter->mh_backup_path, &sb) == 0)
     {
-      if ((new_descr = inotify_add_watch(INotifyFd, iter->mh_backup_path,
+      if ((new_desc = inotify_add_watch(INotifyFd, iter->mh_backup_path,
                                          INOTIFY_MASK_FILE)) == -1)
       {
         mutt_debug(2, "inotify_add_watch failed for '%s', errno=%d %s\n",
@@ -196,7 +199,7 @@ static int monitor_handle_ignore(int desc)
         mutt_debug(3, "inotify_add_watch descriptor=%d for '%s'\n", desc, iter->mh_backup_path);
         iter->st_dev = sb.st_dev;
         iter->st_ino = sb.st_ino;
-        iter->desc = new_descr;
+        iter->desc = new_desc;
       }
     }
     else
@@ -204,14 +207,17 @@ static int monitor_handle_ignore(int desc)
       mutt_debug(3, "cleanup watch (implicitely removed) - descriptor=%d\n", desc);
     }
 
-    if (new_descr == -1)
+    if (MonitorContextDescriptor == desc)
+      MonitorContextDescriptor = new_desc;
+
+    if (new_desc == -1)
     {
       monitor_delete(iter);
       monitor_check_free();
     }
   }
 
-  return new_descr;
+  return new_desc;
 }
 
 #define EVENT_BUFLEN MAX(4096, sizeof(struct inotify_event) + NAME_MAX + 1)
@@ -285,6 +291,8 @@ int mutt_monitor_poll(void)
                            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;
               }
             }
@@ -384,7 +392,11 @@ int mutt_monitor_add(struct Mailbox *mailbox)
 
   desc = monitor_resolve(&info, mailbox);
   if (desc != RESOLVERES_OK_NOTEXISTING)
+  {
+    if (!mailbox && (desc == RESOLVERES_OK_EXISTING))
+      MonitorContextDescriptor = info.monitor->desc;
     return desc == RESOLVERES_OK_EXISTING ? 0 : -1;
+  }
 
   mask = info.isdir ? INOTIFY_MASK_DIR : INOTIFY_MASK_FILE;
   if ((INotifyFd == -1 && monitor_init() == -1) ||
@@ -396,6 +408,9 @@ int mutt_monitor_add(struct Mailbox *mailbox)
   }
 
   mutt_debug(3, "inotify_add_watch descriptor=%d for '%s'\n", desc, info.path);
+  if (!mailbox)
+    MonitorContextDescriptor = desc;
+
   monitor_create(&info, desc);
   return 0;
 }
@@ -433,6 +448,9 @@ int mutt_monitor_remove(struct Mailbox *mailbox)
   mutt_debug(3, "inotify_rm_watch for '%s' descriptor=%d\n", info.path,
              info.monitor->desc);
 
+  if (!mailbox && (MonitorContextDescriptor == info.monitor->desc))
+    MonitorContextDescriptor = -1;
+
   monitor_delete(info.monitor);
   monitor_check_free();
   return 0;
index 1159abe07badc9766b9fa7e9037ad7d81687ec1c..fb11feef825aa917fa941805a3d90ae9b4562505 100644 (file)
--- a/monitor.h
+++ b/monitor.h
@@ -24,6 +24,7 @@
 #define _MUTT_MONITOR_H
 
 extern int MonitorFilesChanged;
+extern int MonitorContextChanged;
 
 struct Mailbox;