]> granicus.if.org Git - vim/commitdiff
patch 8.2.3510: changes are only detected with one second accuracy v8.2.3510
authorLeah Neukirchen <leah@vuxu.org>
Thu, 14 Oct 2021 20:27:55 +0000 (21:27 +0100)
committerBram Moolenaar <Bram@vim.org>
Thu, 14 Oct 2021 20:27:55 +0000 (21:27 +0100)
Problem:    Changes are only detected with one second accuracy.
Solution:   Use the nanosecond time if possible.  (Leah Neukirchen,
            closes #8873, closes #8875)

13 files changed:
runtime/doc/eval.txt
src/auto/configure
src/bufwrite.c
src/config.h.in
src/configure.ac
src/evalfunc.c
src/fileio.c
src/memline.c
src/netbeans.c
src/proto/fileio.pro
src/structs.h
src/testdir/test_stat.vim
src/version.c

index b966fd9bbfd3372ba9668cfd9e2e3ffa33b0bd18..5a7e6ec31b1b985f36592b8f06338e81de67e0e4 100644 (file)
@@ -12236,6 +12236,7 @@ multi_byte_encoding     'encoding' is set to a multibyte encoding.
 multi_byte_ime         Compiled with support for IME input method.
 multi_lang             Compiled with support for multiple languages.
 mzscheme               Compiled with MzScheme interface |mzscheme|.
+nanotime               Compiled with sub-second time stamp checks.
 netbeans_enabled       Compiled with support for |netbeans| and connected.
 netbeans_intg          Compiled with support for |netbeans|.
 num64                  Compiled with 64-bit |Number| support.
index cab7bc9fcaae8aeb191132df475f0c5fc97c1200..cd5e59366eca88e2cf1a005d4b0608a0a4eedd13 100755 (executable)
@@ -13149,6 +13149,52 @@ if test "x$vim_cv_stat_ignores_slash" = "xyes" ; then
 
 fi
 
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for nanoseconds field of struct stat" >&5
+$as_echo_n "checking for nanoseconds field of struct stat... " >&6; }
+if ${ac_cv_struct_st_mtim_nsec+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_save_CPPFLAGS="$CPPFLAGS"
+   ac_cv_struct_st_mtim_nsec=no
+   # st_mtim.tv_nsec -- the usual case
+   # st_mtim._tv_nsec -- Solaris 2.6, if
+   #   (defined _XOPEN_SOURCE && _XOPEN_SOURCE_EXTENDED == 1
+   #    && !defined __EXTENSIONS__)
+   # st_mtim.st__tim.tv_nsec -- UnixWare 2.1.2
+   # st_mtime_n -- AIX 5.2 and above
+   # st_mtimespec.tv_nsec -- Darwin (Mac OSX)
+   for ac_val in st_mtim.tv_nsec st_mtim._tv_nsec st_mtim.st__tim.tv_nsec st_mtime_n st_mtimespec.tv_nsec; do
+     CPPFLAGS="$ac_save_CPPFLAGS -DST_MTIM_NSEC=$ac_val"
+     cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <sys/types.h>
+#include <sys/stat.h>
+int
+main ()
+{
+struct stat s; s.ST_MTIM_NSEC;
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_struct_st_mtim_nsec=$ac_val; break
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+   done
+   CPPFLAGS="$ac_save_CPPFLAGS"
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_struct_st_mtim_nsec" >&5
+$as_echo "$ac_cv_struct_st_mtim_nsec" >&6; }
+if test $ac_cv_struct_st_mtim_nsec != no; then
+
+cat >>confdefs.h <<_ACEOF
+#define ST_MTIM_NSEC $ac_cv_struct_st_mtim_nsec
+_ACEOF
+
+fi
+
 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for iconv_open()" >&5
 $as_echo_n "checking for iconv_open()... " >&6; }
 save_LIBS="$LIBS"
index a38fb1c0e86420f58722514ff7b8e01290847b59..772d707673a9ccff429454d756d1227c6dc6d94e 100644 (file)
@@ -527,7 +527,7 @@ buf_write_bytes(struct bw_info *ip)
 check_mtime(buf_T *buf, stat_T *st)
 {
     if (buf->b_mtime_read != 0
-           && time_differs((long)st->st_mtime, buf->b_mtime_read))
+                 && time_differs(st, buf->b_mtime_read, buf->b_mtime_read_ns))
     {
        msg_scroll = TRUE;          // don't overwrite messages here
        msg_silent = 0;             // must give this prompt
@@ -2558,6 +2558,7 @@ nofail:
            {
                buf_store_time(buf, &st_old, fname);
                buf->b_mtime_read = buf->b_mtime;
+               buf->b_mtime_read_ns = buf->b_mtime_ns;
            }
        }
     }
index 0808cc3587a19af04a7e4d652d37cb20d3861b40..61b8b76a540f8f2034b5b75993fecf0a4b63e791 100644 (file)
 /* Define if stat() ignores a trailing slash */
 #undef STAT_IGNORES_SLASH
 
+/* Define to nanoseconds field of struct stat */
+#undef ST_MTIM_NSEC
+
 /* Define if tgetstr() has a second argument that is (char *) */
 #undef TGETSTR_CHAR_P
 
index bb77485f31c530266e058aab918c8dfc6f0ff67d..3316f48242c6571167791ccd5743ef6c52f424cf 100644 (file)
@@ -3843,6 +3843,31 @@ main() {struct stat st;  exit(stat("configure/", &st) != 0); }
 if test "x$vim_cv_stat_ignores_slash" = "xyes" ; then
   AC_DEFINE(STAT_IGNORES_SLASH)
 fi
+
+dnl nanoseconds field of struct stat
+AC_CACHE_CHECK([for nanoseconds field of struct stat],
+  ac_cv_struct_st_mtim_nsec,
+  [ac_save_CPPFLAGS="$CPPFLAGS"
+   ac_cv_struct_st_mtim_nsec=no
+   # st_mtim.tv_nsec -- the usual case
+   # st_mtim._tv_nsec -- Solaris 2.6, if
+   #   (defined _XOPEN_SOURCE && _XOPEN_SOURCE_EXTENDED == 1
+   #    && !defined __EXTENSIONS__)
+   # st_mtim.st__tim.tv_nsec -- UnixWare 2.1.2
+   # st_mtime_n -- AIX 5.2 and above
+   # st_mtimespec.tv_nsec -- Darwin (Mac OSX)
+   for ac_val in st_mtim.tv_nsec st_mtim._tv_nsec st_mtim.st__tim.tv_nsec st_mtime_n st_mtimespec.tv_nsec; do
+     CPPFLAGS="$ac_save_CPPFLAGS -DST_MTIM_NSEC=$ac_val"
+     AC_TRY_COMPILE([#include <sys/types.h>
+#include <sys/stat.h>], [struct stat s; s.ST_MTIM_NSEC;],
+       [ac_cv_struct_st_mtim_nsec=$ac_val; break])
+   done
+   CPPFLAGS="$ac_save_CPPFLAGS"
+])
+if test $ac_cv_struct_st_mtim_nsec != no; then
+  AC_DEFINE_UNQUOTED([ST_MTIM_NSEC], [$ac_cv_struct_st_mtim_nsec],
+  [Define if struct stat contains a nanoseconds field])
+fi
   
 dnl Link with iconv for charset translation, if not found without library.
 dnl check for iconv() requires including iconv.h
index 8a06f757dfc2819743252cb77d62e7d5ba997058..4abbdb90f62953c85d81361e5b7104ab6b6d5a05 100644 (file)
@@ -5479,6 +5479,13 @@ f_has(typval_T *argvars, typval_T *rettv)
                0
 #endif
                },
+       {"nanotime",
+#ifdef ST_MTIM_NSEC
+               1
+#else
+               0
+#endif
+       },
        {"num64", 1},
        {"ole",
 #ifdef FEAT_OLE
index 1767e5e0912bb776789ea2738bbcce985e13c829..63d083e1592af616499b0bc8133e7acec9e1dc3d 100644 (file)
@@ -408,6 +408,7 @@ readfile(
        {
            buf_store_time(curbuf, &st, fname);
            curbuf->b_mtime_read = curbuf->b_mtime;
+           curbuf->b_mtime_read_ns = curbuf->b_mtime_ns;
            filesize_disk = st.st_size;
 #ifdef UNIX
            /*
@@ -432,7 +433,9 @@ readfile(
        else
        {
            curbuf->b_mtime = 0;
+           curbuf->b_mtime_ns = 0;
            curbuf->b_mtime_read = 0;
+           curbuf->b_mtime_read_ns = 0;
            curbuf->b_orig_size = 0;
            curbuf->b_orig_mode = 0;
        }
@@ -2569,6 +2572,7 @@ failed:
        {
            buf_store_time(curbuf, &st, fname);
            curbuf->b_mtime_read = curbuf->b_mtime;
+           curbuf->b_mtime_read_ns = curbuf->b_mtime_ns;
        }
 #endif
     }
@@ -3115,15 +3119,19 @@ msg_add_eol(void)
 }
 
     int
-time_differs(long t1, long t2)
+time_differs(stat_T *st, long mtime, long mtime_ns UNUSED)
 {
 #if defined(__linux__) || defined(MSWIN)
     // On a FAT filesystem, esp. under Linux, there are only 5 bits to store
     // the seconds.  Since the roundoff is done when flushing the inode, the
     // time may change unexpectedly by one second!!!
-    return (t1 - t2 > 1 || t2 - t1 > 1);
+    return (long)st->st_mtime - mtime > 1 || mtime - (long)st->st_mtime > 1
+# ifdef ST_MTIM_NSEC
+               || (long)st->ST_MTIM_NSEC != mtime_ns
+# endif
+               ;
 #else
-    return (t1 != t2);
+    return (long)st->st_mtime != mtime;
 #endif
 }
 
@@ -4072,7 +4080,7 @@ buf_check_timestamp(
     if (       !(buf->b_flags & BF_NOTEDITED)
            && buf->b_mtime != 0
            && ((stat_res = mch_stat((char *)buf->b_ffname, &st)) < 0
-               || time_differs((long)st.st_mtime, buf->b_mtime)
+               || time_differs(&st, buf->b_mtime, buf->b_mtime_ns)
                || st.st_size != buf->b_orig_size
 #ifdef HAVE_ST_MODE
                || (int)st.st_mode != buf->b_orig_mode
@@ -4187,9 +4195,12 @@ buf_check_timestamp(
                        mesg2 = _("See \":help W16\" for more info.");
                    }
                    else
+                   {
                        // Only timestamp changed, store it to avoid a warning
                        // in check_mtime() later.
                        buf->b_mtime_read = buf->b_mtime;
+                       buf->b_mtime_read_ns = buf->b_mtime_ns;
+                   }
                }
            }
        }
@@ -4468,6 +4479,11 @@ buf_reload(buf_T *buf, int orig_mode)
 buf_store_time(buf_T *buf, stat_T *st, char_u *fname UNUSED)
 {
     buf->b_mtime = (long)st->st_mtime;
+#ifdef ST_MTIM_NSEC
+    buf->b_mtime_ns = (long)st->ST_MTIM_NSEC;
+#else
+    buf->b_mtime_ns = 0;
+#endif
     buf->b_orig_size = st->st_size;
 #ifdef HAVE_ST_MODE
     buf->b_orig_mode = (int)st->st_mode;
index 6ea860d4fef002dc0a7e5e799a32219ede7d6914..bfbf4e28074de64deff45bd082bb24d5a35fa112 100644 (file)
@@ -1032,6 +1032,7 @@ set_b0_fname(ZERO_BL *b0p, buf_T *buf)
 #endif
            buf_store_time(buf, &st, buf->b_ffname);
            buf->b_mtime_read = buf->b_mtime;
+           buf->b_mtime_read_ns = buf->b_mtime_ns;
        }
        else
        {
@@ -1040,7 +1041,9 @@ set_b0_fname(ZERO_BL *b0p, buf_T *buf)
            long_to_char(0L, b0p->b0_ino);
 #endif
            buf->b_mtime = 0;
+           buf->b_mtime_ns = 0;
            buf->b_mtime_read = 0;
+           buf->b_mtime_read_ns = 0;
            buf->b_orig_size = 0;
            buf->b_orig_mode = 0;
        }
@@ -2436,6 +2439,9 @@ ml_sync_all(int check_file, int check_char)
             */
            if (mch_stat((char *)buf->b_ffname, &st) == -1
                    || st.st_mtime != buf->b_mtime_read
+#ifdef ST_MTIM_NSEC
+                   || st.ST_MTIM_NSEC != buf->b_mtime_read_ns
+#endif
                    || st.st_size != buf->b_orig_size)
            {
                ml_preserve(buf, FALSE);
index bf47df713c8aa135cb37e23093b9c06ac3f444e1..5bd36a4ddd9a53cd48d8750cc188dc53ee37f73d 100644 (file)
@@ -1760,7 +1760,10 @@ nb_do_cmd(
            if (buf == NULL || buf->bufp == NULL)
                nbdebug(("    invalid buffer identifier in setModtime\n"));
            else
+           {
                buf->bufp->b_mtime = atoi((char *)args);
+               buf->bufp->b_mtime_ns = 0;
+           }
 // =====================================================================
        }
        else if (streq((char *)cmd, "setReadOnly"))
index cdf92743b56ec9489935c76a90bfc12ae3ca1d05..da6054b50986928c58670c2978c35968a5524896 100644 (file)
@@ -12,7 +12,7 @@ void msg_add_fname(buf_T *buf, char_u *fname);
 int msg_add_fileformat(int eol_type);
 void msg_add_lines(int insert_space, long lnum, off_T nchars);
 void msg_add_eol(void);
-int time_differs(long t1, long t2);
+int time_differs(stat_T *st, long mtime, long mtime_ns);
 int need_conversion(char_u *fenc);
 int get_fio_flags(char_u *ptr);
 int get_win_fio_flags(char_u *ptr);
index 0715686f7ff4ab0f4beae6ef2a26b29bff9d4721..7dac95b30e74e17dd0e8d1f012dd0037e50cefc8 100644 (file)
@@ -2724,7 +2724,9 @@ struct file_buffer
     wininfo_T  *b_wininfo;     // list of last used info for each window
 
     long       b_mtime;        // last change time of original file
+    long       b_mtime_ns;     // nanoseconds of last change time
     long       b_mtime_read;   // last change time when reading
+    long       b_mtime_read_ns;  // nanoseconds of last read time
     off_T      b_orig_size;    // size of original file in bytes
     int                b_orig_mode;    // mode of original file
 #ifdef FEAT_VIMINFO
index 5cd82b8e2f41d25586737316c0a36c70305e69c5..b56528192aca483c17d8eb0e83cf46657c506061 100644 (file)
@@ -76,6 +76,39 @@ func Test_checktime()
   call delete(fname)
 endfunc
 
+func Test_checktime_fast()
+  CheckFeature nanotime
+
+  let fname = 'Xtest.tmp'
+
+  let fl = ['Hello World!']
+  call writefile(fl, fname)
+  set autoread
+  exec 'e' fname
+  let fl = readfile(fname)
+  let fl[0] .= ' - checktime'
+  call writefile(fl, fname)
+  checktime
+  call assert_equal(fl[0], getline(1))
+
+  call delete(fname)
+endfunc
+
+func Test_autoread_fast()
+  CheckFeature nanotime
+
+  new Xautoread
+  set autoread
+  call setline(1, 'foo')
+
+  w!
+  silent !echo bar > Xautoread
+  checktime
+
+  call assert_equal('bar', trim(getline(1)))
+  call delete('Xautoread')
+endfunc
+
 func Test_autoread_file_deleted()
   new Xautoread
   set autoread
index 31f00157b3c9939af0afe88d526289133e5ba556..d1f079cb280d0b40c05ee2e8f1ff5ae5a91cf4ef 100644 (file)
@@ -757,6 +757,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    3510,
 /**/
     3509,
 /**/