0
0
mirror of https://github.com/vim/vim.git synced 2025-09-26 04:04:07 -04:00

patch 8.2.3510: changes are only detected with one second accuracy

Problem:    Changes are only detected with one second accuracy.
Solution:   Use the nanosecond time if possible.  (Leah Neukirchen,
            closes #8873, closes #8875)
This commit is contained in:
Leah Neukirchen
2021-10-14 21:27:55 +01:00
committed by Bram Moolenaar
parent 340dd0fbe4
commit 0a7984af56
13 changed files with 151 additions and 6 deletions

View 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_byte_ime Compiled with support for IME input method.
multi_lang Compiled with support for multiple languages. multi_lang Compiled with support for multiple languages.
mzscheme Compiled with MzScheme interface |mzscheme|. mzscheme Compiled with MzScheme interface |mzscheme|.
nanotime Compiled with sub-second time stamp checks.
netbeans_enabled Compiled with support for |netbeans| and connected. netbeans_enabled Compiled with support for |netbeans| and connected.
netbeans_intg Compiled with support for |netbeans|. netbeans_intg Compiled with support for |netbeans|.
num64 Compiled with 64-bit |Number| support. num64 Compiled with 64-bit |Number| support.

46
src/auto/configure vendored
View File

@@ -13149,6 +13149,52 @@ if test "x$vim_cv_stat_ignores_slash" = "xyes" ; then
fi 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 "$as_me:${as_lineno-$LINENO}: checking for iconv_open()" >&5
$as_echo_n "checking for iconv_open()... " >&6; } $as_echo_n "checking for iconv_open()... " >&6; }
save_LIBS="$LIBS" save_LIBS="$LIBS"

View File

@@ -527,7 +527,7 @@ buf_write_bytes(struct bw_info *ip)
check_mtime(buf_T *buf, stat_T *st) check_mtime(buf_T *buf, stat_T *st)
{ {
if (buf->b_mtime_read != 0 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_scroll = TRUE; // don't overwrite messages here
msg_silent = 0; // must give this prompt msg_silent = 0; // must give this prompt
@@ -2558,6 +2558,7 @@ nofail:
{ {
buf_store_time(buf, &st_old, fname); buf_store_time(buf, &st_old, fname);
buf->b_mtime_read = buf->b_mtime; buf->b_mtime_read = buf->b_mtime;
buf->b_mtime_read_ns = buf->b_mtime_ns;
} }
} }
} }

View File

@@ -144,6 +144,9 @@
/* Define if stat() ignores a trailing slash */ /* Define if stat() ignores a trailing slash */
#undef STAT_IGNORES_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 *) */ /* Define if tgetstr() has a second argument that is (char *) */
#undef TGETSTR_CHAR_P #undef TGETSTR_CHAR_P

View File

@@ -3843,6 +3843,31 @@ main() {struct stat st; exit(stat("configure/", &st) != 0); }
if test "x$vim_cv_stat_ignores_slash" = "xyes" ; then if test "x$vim_cv_stat_ignores_slash" = "xyes" ; then
AC_DEFINE(STAT_IGNORES_SLASH) AC_DEFINE(STAT_IGNORES_SLASH)
fi 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 Link with iconv for charset translation, if not found without library.
dnl check for iconv() requires including iconv.h dnl check for iconv() requires including iconv.h

View File

@@ -5479,6 +5479,13 @@ f_has(typval_T *argvars, typval_T *rettv)
0 0
#endif #endif
}, },
{"nanotime",
#ifdef ST_MTIM_NSEC
1
#else
0
#endif
},
{"num64", 1}, {"num64", 1},
{"ole", {"ole",
#ifdef FEAT_OLE #ifdef FEAT_OLE

View File

@@ -408,6 +408,7 @@ readfile(
{ {
buf_store_time(curbuf, &st, fname); buf_store_time(curbuf, &st, fname);
curbuf->b_mtime_read = curbuf->b_mtime; curbuf->b_mtime_read = curbuf->b_mtime;
curbuf->b_mtime_read_ns = curbuf->b_mtime_ns;
filesize_disk = st.st_size; filesize_disk = st.st_size;
#ifdef UNIX #ifdef UNIX
/* /*
@@ -432,7 +433,9 @@ readfile(
else else
{ {
curbuf->b_mtime = 0; curbuf->b_mtime = 0;
curbuf->b_mtime_ns = 0;
curbuf->b_mtime_read = 0; curbuf->b_mtime_read = 0;
curbuf->b_mtime_read_ns = 0;
curbuf->b_orig_size = 0; curbuf->b_orig_size = 0;
curbuf->b_orig_mode = 0; curbuf->b_orig_mode = 0;
} }
@@ -2569,6 +2572,7 @@ failed:
{ {
buf_store_time(curbuf, &st, fname); buf_store_time(curbuf, &st, fname);
curbuf->b_mtime_read = curbuf->b_mtime; curbuf->b_mtime_read = curbuf->b_mtime;
curbuf->b_mtime_read_ns = curbuf->b_mtime_ns;
} }
#endif #endif
} }
@@ -3115,15 +3119,19 @@ msg_add_eol(void)
} }
int int
time_differs(long t1, long t2) time_differs(stat_T *st, long mtime, long mtime_ns UNUSED)
{ {
#if defined(__linux__) || defined(MSWIN) #if defined(__linux__) || defined(MSWIN)
// On a FAT filesystem, esp. under Linux, there are only 5 bits to store // 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 // the seconds. Since the roundoff is done when flushing the inode, the
// time may change unexpectedly by one second!!! // 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 #else
return (t1 != t2); return (long)st->st_mtime != mtime;
#endif #endif
} }
@@ -4072,7 +4080,7 @@ buf_check_timestamp(
if ( !(buf->b_flags & BF_NOTEDITED) if ( !(buf->b_flags & BF_NOTEDITED)
&& buf->b_mtime != 0 && buf->b_mtime != 0
&& ((stat_res = mch_stat((char *)buf->b_ffname, &st)) < 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 || st.st_size != buf->b_orig_size
#ifdef HAVE_ST_MODE #ifdef HAVE_ST_MODE
|| (int)st.st_mode != buf->b_orig_mode || (int)st.st_mode != buf->b_orig_mode
@@ -4187,9 +4195,12 @@ buf_check_timestamp(
mesg2 = _("See \":help W16\" for more info."); mesg2 = _("See \":help W16\" for more info.");
} }
else else
{
// Only timestamp changed, store it to avoid a warning // Only timestamp changed, store it to avoid a warning
// in check_mtime() later. // in check_mtime() later.
buf->b_mtime_read = buf->b_mtime; 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_store_time(buf_T *buf, stat_T *st, char_u *fname UNUSED)
{ {
buf->b_mtime = (long)st->st_mtime; 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; buf->b_orig_size = st->st_size;
#ifdef HAVE_ST_MODE #ifdef HAVE_ST_MODE
buf->b_orig_mode = (int)st->st_mode; buf->b_orig_mode = (int)st->st_mode;

View File

@@ -1032,6 +1032,7 @@ set_b0_fname(ZERO_BL *b0p, buf_T *buf)
#endif #endif
buf_store_time(buf, &st, buf->b_ffname); buf_store_time(buf, &st, buf->b_ffname);
buf->b_mtime_read = buf->b_mtime; buf->b_mtime_read = buf->b_mtime;
buf->b_mtime_read_ns = buf->b_mtime_ns;
} }
else else
{ {
@@ -1040,7 +1041,9 @@ set_b0_fname(ZERO_BL *b0p, buf_T *buf)
long_to_char(0L, b0p->b0_ino); long_to_char(0L, b0p->b0_ino);
#endif #endif
buf->b_mtime = 0; buf->b_mtime = 0;
buf->b_mtime_ns = 0;
buf->b_mtime_read = 0; buf->b_mtime_read = 0;
buf->b_mtime_read_ns = 0;
buf->b_orig_size = 0; buf->b_orig_size = 0;
buf->b_orig_mode = 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 if (mch_stat((char *)buf->b_ffname, &st) == -1
|| st.st_mtime != buf->b_mtime_read || 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) || st.st_size != buf->b_orig_size)
{ {
ml_preserve(buf, FALSE); ml_preserve(buf, FALSE);

View File

@@ -1760,7 +1760,10 @@ nb_do_cmd(
if (buf == NULL || buf->bufp == NULL) if (buf == NULL || buf->bufp == NULL)
nbdebug((" invalid buffer identifier in setModtime\n")); nbdebug((" invalid buffer identifier in setModtime\n"));
else else
{
buf->bufp->b_mtime = atoi((char *)args); buf->bufp->b_mtime = atoi((char *)args);
buf->bufp->b_mtime_ns = 0;
}
// ===================================================================== // =====================================================================
} }
else if (streq((char *)cmd, "setReadOnly")) else if (streq((char *)cmd, "setReadOnly"))

View File

@@ -12,7 +12,7 @@ void msg_add_fname(buf_T *buf, char_u *fname);
int msg_add_fileformat(int eol_type); int msg_add_fileformat(int eol_type);
void msg_add_lines(int insert_space, long lnum, off_T nchars); void msg_add_lines(int insert_space, long lnum, off_T nchars);
void msg_add_eol(void); 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 need_conversion(char_u *fenc);
int get_fio_flags(char_u *ptr); int get_fio_flags(char_u *ptr);
int get_win_fio_flags(char_u *ptr); int get_win_fio_flags(char_u *ptr);

View File

@@ -2724,7 +2724,9 @@ struct file_buffer
wininfo_T *b_wininfo; // list of last used info for each window wininfo_T *b_wininfo; // list of last used info for each window
long b_mtime; // last change time of original file 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; // 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 off_T b_orig_size; // size of original file in bytes
int b_orig_mode; // mode of original file int b_orig_mode; // mode of original file
#ifdef FEAT_VIMINFO #ifdef FEAT_VIMINFO

View File

@@ -76,6 +76,39 @@ func Test_checktime()
call delete(fname) call delete(fname)
endfunc 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() func Test_autoread_file_deleted()
new Xautoread new Xautoread
set autoread set autoread

View File

@@ -757,6 +757,8 @@ static char *(features[]) =
static int included_patches[] = static int included_patches[] =
{ /* Add new patch number below this line */ { /* Add new patch number below this line */
/**/
3510,
/**/ /**/
3509, 3509,
/**/ /**/