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

patch 8.2.5057: using gettimeofday() for timeout is very inefficient

Problem:    Using gettimeofday() for timeout is very inefficient.
Solution:   Set a platform dependent timer. (Paul Ollis, closes #10505)
This commit is contained in:
Paul Ollis 2022-06-05 16:55:54 +01:00 committed by Bram Moolenaar
parent 1d97db3d98
commit 6574577cac
29 changed files with 811 additions and 242 deletions

94
src/auto/configure vendored
View File

@ -762,7 +762,6 @@ infodir
docdir docdir
oldincludedir oldincludedir
includedir includedir
runstatedir
localstatedir localstatedir
sharedstatedir sharedstatedir
sysconfdir sysconfdir
@ -898,7 +897,6 @@ datadir='${datarootdir}'
sysconfdir='${prefix}/etc' sysconfdir='${prefix}/etc'
sharedstatedir='${prefix}/com' sharedstatedir='${prefix}/com'
localstatedir='${prefix}/var' localstatedir='${prefix}/var'
runstatedir='${localstatedir}/run'
includedir='${prefix}/include' includedir='${prefix}/include'
oldincludedir='/usr/include' oldincludedir='/usr/include'
docdir='${datarootdir}/doc/${PACKAGE}' docdir='${datarootdir}/doc/${PACKAGE}'
@ -1151,15 +1149,6 @@ do
| -silent | --silent | --silen | --sile | --sil) | -silent | --silent | --silen | --sile | --sil)
silent=yes ;; silent=yes ;;
-runstatedir | --runstatedir | --runstatedi | --runstated \
| --runstate | --runstat | --runsta | --runst | --runs \
| --run | --ru | --r)
ac_prev=runstatedir ;;
-runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \
| --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \
| --run=* | --ru=* | --r=*)
runstatedir=$ac_optarg ;;
-sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
ac_prev=sbindir ;; ac_prev=sbindir ;;
-sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
@ -1297,7 +1286,7 @@ fi
for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \
datadir sysconfdir sharedstatedir localstatedir includedir \ datadir sysconfdir sharedstatedir localstatedir includedir \
oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \
libdir localedir mandir runstatedir libdir localedir mandir
do do
eval ac_val=\$$ac_var eval ac_val=\$$ac_var
# Remove trailing slashes. # Remove trailing slashes.
@ -1450,7 +1439,6 @@ Fine tuning of the installation directories:
--sysconfdir=DIR read-only single-machine data [PREFIX/etc] --sysconfdir=DIR read-only single-machine data [PREFIX/etc]
--sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com]
--localstatedir=DIR modifiable single-machine data [PREFIX/var] --localstatedir=DIR modifiable single-machine data [PREFIX/var]
--runstatedir=DIR modifiable per-process data [LOCALSTATEDIR/run]
--libdir=DIR object code libraries [EPREFIX/lib] --libdir=DIR object code libraries [EPREFIX/lib]
--includedir=DIR C header files [PREFIX/include] --includedir=DIR C header files [PREFIX/include]
--oldincludedir=DIR C header files for non-gcc [/usr/include] --oldincludedir=DIR C header files for non-gcc [/usr/include]
@ -12737,7 +12725,7 @@ else
We can't simply define LARGE_OFF_T to be 9223372036854775807, We can't simply define LARGE_OFF_T to be 9223372036854775807,
since some C++ compilers masquerading as C compilers since some C++ compilers masquerading as C compilers
incorrectly reject 9223372036854775807. */ incorrectly reject 9223372036854775807. */
#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31)) #define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62))
int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721
&& LARGE_OFF_T % 2147483647 == 1) && LARGE_OFF_T % 2147483647 == 1)
? 1 : -1]; ? 1 : -1];
@ -12783,7 +12771,7 @@ else
We can't simply define LARGE_OFF_T to be 9223372036854775807, We can't simply define LARGE_OFF_T to be 9223372036854775807,
since some C++ compilers masquerading as C compilers since some C++ compilers masquerading as C compilers
incorrectly reject 9223372036854775807. */ incorrectly reject 9223372036854775807. */
#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31)) #define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62))
int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721
&& LARGE_OFF_T % 2147483647 == 1) && LARGE_OFF_T % 2147483647 == 1)
? 1 : -1]; ? 1 : -1];
@ -12807,7 +12795,7 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
We can't simply define LARGE_OFF_T to be 9223372036854775807, We can't simply define LARGE_OFF_T to be 9223372036854775807,
since some C++ compilers masquerading as C compilers since some C++ compilers masquerading as C compilers
incorrectly reject 9223372036854775807. */ incorrectly reject 9223372036854775807. */
#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31)) #define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62))
int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721
&& LARGE_OFF_T % 2147483647 == 1) && LARGE_OFF_T % 2147483647 == 1)
? 1 : -1]; ? 1 : -1];
@ -12852,7 +12840,7 @@ else
We can't simply define LARGE_OFF_T to be 9223372036854775807, We can't simply define LARGE_OFF_T to be 9223372036854775807,
since some C++ compilers masquerading as C compilers since some C++ compilers masquerading as C compilers
incorrectly reject 9223372036854775807. */ incorrectly reject 9223372036854775807. */
#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31)) #define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62))
int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721
&& LARGE_OFF_T % 2147483647 == 1) && LARGE_OFF_T % 2147483647 == 1)
? 1 : -1]; ? 1 : -1];
@ -12876,7 +12864,7 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
We can't simply define LARGE_OFF_T to be 9223372036854775807, We can't simply define LARGE_OFF_T to be 9223372036854775807,
since some C++ compilers masquerading as C compilers since some C++ compilers masquerading as C compilers
incorrectly reject 9223372036854775807. */ incorrectly reject 9223372036854775807. */
#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31)) #define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62))
int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721
&& LARGE_OFF_T % 2147483647 == 1) && LARGE_OFF_T % 2147483647 == 1)
? 1 : -1]; ? 1 : -1];
@ -13080,6 +13068,76 @@ $as_echo "no" >&6; }
fi fi
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for timer_create" >&5
$as_echo_n "checking for timer_create... " >&6; }
save_LIBS="$LIBS"
LIBS="$LIBS -lrt"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include<signal.h>
#include<time.h>
static void set_flag(union sigval) {}
int
main ()
{
struct timespec ts;
struct sigevent action = {0};
timer_t timer_id;
action.sigev_notify = SIGEV_THREAD;
action.sigev_notify_function = set_flag;
timer_create(CLOCK_REALTIME, &action, &timer_id);
;
return 0;
}
_ACEOF
if ac_fn_c_try_link "$LINENO"; then :
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes; with -lrt" >&5
$as_echo "yes; with -lrt" >&6; }; $as_echo "#define HAVE_TIMER_CREATE 1" >>confdefs.h
else
LIBS="$save_LIBS"
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include<signal.h>
#include<time.h>
static void set_flag(union sigval) {}
int
main ()
{
struct timespec ts;
struct sigevent action = {0};
timer_t timer_id;
action.sigev_notify = SIGEV_THREAD;
action.sigev_notify_function = set_flag;
timer_create(CLOCK_REALTIME, &action, &timer_id);
;
return 0;
}
_ACEOF
if ac_fn_c_try_link "$LINENO"; then :
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
$as_echo "yes" >&6; }; $as_echo "#define HAVE_TIMER_CREATE 1" >>confdefs.h
else
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
$as_echo "no" >&6; }
fi
rm -f core conftest.err conftest.$ac_objext \
conftest$ac_exeext conftest.$ac_ext
fi
rm -f core conftest.err conftest.$ac_objext \
conftest$ac_exeext conftest.$ac_ext
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether stat() ignores a trailing slash" >&5 { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether stat() ignores a trailing slash" >&5
$as_echo_n "checking whether stat() ignores a trailing slash... " >&6; } $as_echo_n "checking whether stat() ignores a trailing slash... " >&6; }
if ${vim_cv_stat_ignores_slash+:} false; then : if ${vim_cv_stat_ignores_slash+:} false; then :

View File

@ -231,6 +231,7 @@
#undef HAVE_UTIME #undef HAVE_UTIME
#undef HAVE_BIND_TEXTDOMAIN_CODESET #undef HAVE_BIND_TEXTDOMAIN_CODESET
#undef HAVE_MBLEN #undef HAVE_MBLEN
#undef HAVE_TIMER_CREATE
/* Define, if needed, for accessing large files. */ /* Define, if needed, for accessing large files. */
#undef _LARGE_FILES #undef _LARGE_FILES

View File

@ -1,7 +1,8 @@
dnl configure.ac: autoconf script for Vim dnl configure.ac: autoconf script for Vim
dnl Process this file with autoconf 2.12 or 2.13 to produce "configure". dnl Process this file with autoconf 2.69 to produce "configure".
dnl Should also work with autoconf 2.54 and later. dnl This should also work with other versions of autoconf, but 2.70 and later
dnl generate lots of hard to fix "obsolete" warnings.
AC_INIT(vim.h) AC_INIT(vim.h)
AC_CONFIG_HEADER(auto/config.h:config.h.in) AC_CONFIG_HEADER(auto/config.h:config.h.in)
@ -3812,6 +3813,41 @@ AC_TRY_COMPILE(
AC_MSG_RESULT(yes); AC_DEFINE(HAVE_ST_BLKSIZE), AC_MSG_RESULT(yes); AC_DEFINE(HAVE_ST_BLKSIZE),
AC_MSG_RESULT(no)) AC_MSG_RESULT(no))
dnl Check for timer_create. It probably requires the 'rt' library.
AC_MSG_CHECKING([for timer_create])
save_LIBS="$LIBS"
LIBS="$LIBS -lrt"
AC_TRY_LINK([
#include<signal.h>
#include<time.h>
static void set_flag(union sigval) {}
], [
struct timespec ts;
struct sigevent action = {0};
timer_t timer_id;
action.sigev_notify = SIGEV_THREAD;
action.sigev_notify_function = set_flag;
timer_create(CLOCK_REALTIME, &action, &timer_id);
],
AC_MSG_RESULT(yes; with -lrt); AC_DEFINE(HAVE_TIMER_CREATE),
LIBS="$save_LIBS"
AC_TRY_LINK([
#include<signal.h>
#include<time.h>
static void set_flag(union sigval) {}
], [
struct timespec ts;
struct sigevent action = {0};
timer_t timer_id;
action.sigev_notify = SIGEV_THREAD;
action.sigev_notify_function = set_flag;
timer_create(CLOCK_REALTIME, &action, &timer_id);
],
AC_MSG_RESULT(yes); AC_DEFINE(HAVE_TIMER_CREATE),
AC_MSG_RESULT(no)))
AC_CACHE_CHECK([whether stat() ignores a trailing slash], [vim_cv_stat_ignores_slash], AC_CACHE_CHECK([whether stat() ignores a trailing slash], [vim_cv_stat_ignores_slash],
[ [
AC_RUN_IFELSE([AC_LANG_SOURCE([[ AC_RUN_IFELSE([AC_LANG_SOURCE([[

View File

@ -1474,9 +1474,6 @@ win_update(win_T *wp)
#if defined(FEAT_SYN_HL) || defined(FEAT_SEARCH_EXTRA) #if defined(FEAT_SYN_HL) || defined(FEAT_SEARCH_EXTRA)
int save_got_int; int save_got_int;
#endif #endif
#ifdef SYN_TIME_LIMIT
proftime_T syntax_tm;
#endif
#if defined(FEAT_SEARCH_EXTRA) || defined(FEAT_CLIPBOARD) #if defined(FEAT_SEARCH_EXTRA) || defined(FEAT_CLIPBOARD)
// This needs to be done only for the first window when update_screen() is // This needs to be done only for the first window when update_screen() is
@ -2182,8 +2179,7 @@ win_update(win_T *wp)
#endif #endif
#ifdef SYN_TIME_LIMIT #ifdef SYN_TIME_LIMIT
// Set the time limit to 'redrawtime'. // Set the time limit to 'redrawtime'.
profile_setlimit(p_rdt, &syntax_tm); init_regexp_timeout(p_rdt);
syn_set_timeout(&syntax_tm);
#endif #endif
#ifdef FEAT_FOLDING #ifdef FEAT_FOLDING
win_foldinfo.fi_level = 0; win_foldinfo.fi_level = 0;
@ -2695,7 +2691,7 @@ win_update(win_T *wp)
} }
#ifdef SYN_TIME_LIMIT #ifdef SYN_TIME_LIMIT
syn_set_timeout(NULL); disable_regexp_timeout();
#endif #endif
// Reset the type of redrawing required, the window has been updated. // Reset the type of redrawing required, the window has been updated.

View File

@ -3288,3 +3288,15 @@ EXTERN char e_bitshift_ops_must_be_postive[]
EXTERN char e_argument_1_list_item_nr_dictionary_required[] EXTERN char e_argument_1_list_item_nr_dictionary_required[]
INIT(= N_("E1284: Argument 1, list item %d: Dictionary required")); INIT(= N_("E1284: Argument 1, list item %d: Dictionary required"));
#endif #endif
#ifdef FEAT_RELTIME
EXTERN char e_could_not_clear_timeout_str[]
INIT(= N_("E1285: Could not clear timeout: %s"));
EXTERN char e_could_not_set_timeout_str[]
INIT(= N_("E1286: Could not set timeout: %s"));
EXTERN char e_could_not_set_handler_for_timeout_str[]
INIT(= N_("E1287: Could not set handler for timeout: %s"));
EXTERN char e_could_not_reset_handler_for_timeout_str[]
INIT(= N_("E1288: Could not reset handler for timeout: %s"));
EXTERN char e_could_not_check_for_pending_sigalrm_str[]
INIT(= N_("E1289: Could not check for pending SIGALRM: %s"));
#endif

View File

@ -8439,7 +8439,6 @@ search_cmn(typval_T *argvars, pos_T *match_pos, int *flagsp)
int retval = 0; // default: FAIL int retval = 0; // default: FAIL
long lnum_stop = 0; long lnum_stop = 0;
#ifdef FEAT_RELTIME #ifdef FEAT_RELTIME
proftime_T tm;
long time_limit = 0; long time_limit = 0;
#endif #endif
int options = SEARCH_KEEP; int options = SEARCH_KEEP;
@ -8486,11 +8485,6 @@ search_cmn(typval_T *argvars, pos_T *match_pos, int *flagsp)
} }
} }
#ifdef FEAT_RELTIME
// Set the time limit, if there is one.
profile_setlimit(time_limit, &tm);
#endif
/* /*
* This function does not accept SP_REPEAT and SP_RETCOUNT flags. * This function does not accept SP_REPEAT and SP_RETCOUNT flags.
* Check to make sure only those flags are set. * Check to make sure only those flags are set.
@ -8509,7 +8503,7 @@ search_cmn(typval_T *argvars, pos_T *match_pos, int *flagsp)
CLEAR_FIELD(sia); CLEAR_FIELD(sia);
sia.sa_stop_lnum = (linenr_T)lnum_stop; sia.sa_stop_lnum = (linenr_T)lnum_stop;
#ifdef FEAT_RELTIME #ifdef FEAT_RELTIME
sia.sa_tm = &tm; sia.sa_tm = time_limit;
#endif #endif
// Repeat until {skip} returns FALSE. // Repeat until {skip} returns FALSE.
@ -8955,19 +8949,11 @@ do_searchpair(
int use_skip = FALSE; int use_skip = FALSE;
int err; int err;
int options = SEARCH_KEEP; int options = SEARCH_KEEP;
#ifdef FEAT_RELTIME
proftime_T tm;
#endif
// Make 'cpoptions' empty, the 'l' flag should not be used here. // Make 'cpoptions' empty, the 'l' flag should not be used here.
save_cpo = p_cpo; save_cpo = p_cpo;
p_cpo = empty_option; p_cpo = empty_option;
#ifdef FEAT_RELTIME
// Set the time limit, if there is one.
profile_setlimit(time_limit, &tm);
#endif
// Make two search patterns: start/end (pat2, for in nested pairs) and // Make two search patterns: start/end (pat2, for in nested pairs) and
// start/middle/end (pat3, for the top pair). // start/middle/end (pat3, for the top pair).
pat2 = alloc(STRLEN(spat) + STRLEN(epat) + 17); pat2 = alloc(STRLEN(spat) + STRLEN(epat) + 17);
@ -8998,7 +8984,7 @@ do_searchpair(
CLEAR_FIELD(sia); CLEAR_FIELD(sia);
sia.sa_stop_lnum = lnum_stop; sia.sa_stop_lnum = lnum_stop;
#ifdef FEAT_RELTIME #ifdef FEAT_RELTIME
sia.sa_tm = &tm; sia.sa_tm = time_limit;
#endif #endif
n = searchit(curwin, curbuf, &pos, NULL, dir, pat, 1L, n = searchit(curwin, curbuf, &pos, NULL, dir, pat, 1L,
options, RE_SEARCH, &sia); options, RE_SEARCH, &sia);

View File

@ -4006,7 +4006,7 @@ ex_substitute(exarg_T *eap)
); ++lnum) ); ++lnum)
{ {
nmatch = vim_regexec_multi(&regmatch, curwin, curbuf, lnum, nmatch = vim_regexec_multi(&regmatch, curwin, curbuf, lnum,
(colnr_T)0, NULL, NULL); (colnr_T)0, NULL);
if (nmatch) if (nmatch)
{ {
colnr_T copycol; colnr_T copycol;
@ -4663,7 +4663,7 @@ skip:
|| nmatch_tl > 0 || nmatch_tl > 0
|| (nmatch = vim_regexec_multi(&regmatch, curwin, || (nmatch = vim_regexec_multi(&regmatch, curwin,
curbuf, sub_firstlnum, curbuf, sub_firstlnum,
matchcol, NULL, NULL)) == 0 matchcol, NULL)) == 0
|| regmatch.startpos[0].lnum > 0) || regmatch.startpos[0].lnum > 0)
{ {
if (new_start != NULL) if (new_start != NULL)
@ -4728,7 +4728,7 @@ skip:
} }
if (nmatch == -1 && !lastone) if (nmatch == -1 && !lastone)
nmatch = vim_regexec_multi(&regmatch, curwin, curbuf, nmatch = vim_regexec_multi(&regmatch, curwin, curbuf,
sub_firstlnum, matchcol, NULL, NULL); sub_firstlnum, matchcol, NULL);
/* /*
* 5. break if there isn't another match in this line * 5. break if there isn't another match in this line
@ -4992,7 +4992,7 @@ ex_global(exarg_T *eap)
{ {
lnum = curwin->w_cursor.lnum; lnum = curwin->w_cursor.lnum;
match = vim_regexec_multi(&regmatch, curwin, curbuf, lnum, match = vim_regexec_multi(&regmatch, curwin, curbuf, lnum,
(colnr_T)0, NULL, NULL); (colnr_T)0, NULL);
if ((type == 'g' && match) || (type == 'v' && !match)) if ((type == 'g' && match) || (type == 'v' && !match))
global_exe_one(cmd, lnum); global_exe_one(cmd, lnum);
} }
@ -5005,7 +5005,7 @@ ex_global(exarg_T *eap)
{ {
// a match on this line? // a match on this line?
match = vim_regexec_multi(&regmatch, curwin, curbuf, lnum, match = vim_regexec_multi(&regmatch, curwin, curbuf, lnum,
(colnr_T)0, NULL, NULL); (colnr_T)0, NULL);
if (regmatch.regprog == NULL) if (regmatch.regprog == NULL)
break; // re-compiling regprog failed break; // re-compiling regprog failed
if ((type == 'g' && match) || (type == 'v' && !match)) if ((type == 'g' && match) || (type == 'v' && !match))

View File

@ -417,7 +417,6 @@ may_do_incsearch_highlighting(
int found; // do_search() result int found; // do_search() result
pos_T end_pos; pos_T end_pos;
#ifdef FEAT_RELTIME #ifdef FEAT_RELTIME
proftime_T tm;
searchit_arg_T sia; searchit_arg_T sia;
#endif #endif
int next_char; int next_char;
@ -484,10 +483,6 @@ may_do_incsearch_highlighting(
cursor_off(); // so the user knows we're busy cursor_off(); // so the user knows we're busy
out_flush(); out_flush();
++emsg_off; // so it doesn't beep if bad expr ++emsg_off; // so it doesn't beep if bad expr
#ifdef FEAT_RELTIME
// Set the time limit to half a second.
profile_setlimit(500L, &tm);
#endif
if (!p_hls) if (!p_hls)
search_flags += SEARCH_KEEP; search_flags += SEARCH_KEEP;
if (search_first_line != 0) if (search_first_line != 0)
@ -495,7 +490,8 @@ may_do_incsearch_highlighting(
ccline.cmdbuff[skiplen + patlen] = NUL; ccline.cmdbuff[skiplen + patlen] = NUL;
#ifdef FEAT_RELTIME #ifdef FEAT_RELTIME
CLEAR_FIELD(sia); CLEAR_FIELD(sia);
sia.sa_tm = &tm; // Set the time limit to half a second.
sia.sa_tm = 500;
#endif #endif
found = do_search(NULL, firstc == ':' ? '/' : firstc, search_delim, found = do_search(NULL, firstc == ':' ? '/' : firstc, search_delim,
ccline.cmdbuff + skiplen, count, search_flags, ccline.cmdbuff + skiplen, count, search_flags,

View File

@ -330,10 +330,6 @@ init_search_hl(win_T *wp, match_T *search_hl)
cur->hl.buf = wp->w_buffer; cur->hl.buf = wp->w_buffer;
cur->hl.lnum = 0; cur->hl.lnum = 0;
cur->hl.first_lnum = 0; cur->hl.first_lnum = 0;
# ifdef FEAT_RELTIME
// Set the time limit to 'redrawtime'.
profile_setlimit(p_rdt, &(cur->hl.tm));
# endif
cur = cur->next; cur = cur->next;
} }
search_hl->buf = wp->w_buffer; search_hl->buf = wp->w_buffer;
@ -424,6 +420,7 @@ next_search_hl(
colnr_T matchcol; colnr_T matchcol;
long nmatched; long nmatched;
int called_emsg_before = called_emsg; int called_emsg_before = called_emsg;
int timed_out = FALSE;
// for :{range}s/pat only highlight inside the range // for :{range}s/pat only highlight inside the range
if ((lnum < search_first_line || lnum > search_last_line) && cur == NULL) if ((lnum < search_first_line || lnum > search_last_line) && cur == NULL)
@ -451,7 +448,7 @@ next_search_hl(
{ {
# ifdef FEAT_RELTIME # ifdef FEAT_RELTIME
// Stop searching after passing the time limit. // Stop searching after passing the time limit.
if (profile_passed_limit(&(shl->tm))) if (timed_out)
{ {
shl->lnum = 0; // no match found in time shl->lnum = 0; // no match found in time
break; break;
@ -494,16 +491,9 @@ next_search_hl(
int regprog_is_copy = (shl != search_hl && cur != NULL int regprog_is_copy = (shl != search_hl && cur != NULL
&& shl == &cur->hl && shl == &cur->hl
&& cur->match.regprog == cur->hl.rm.regprog); && cur->match.regprog == cur->hl.rm.regprog);
int timed_out = FALSE;
nmatched = vim_regexec_multi(&shl->rm, win, shl->buf, lnum, nmatched = vim_regexec_multi(&shl->rm, win, shl->buf, lnum,
matchcol, matchcol, &timed_out);
#ifdef FEAT_RELTIME
&(shl->tm), &timed_out
#else
NULL, NULL
#endif
);
// Copy the regprog, in case it got freed and recompiled. // Copy the regprog, in case it got freed and recompiled.
if (regprog_is_copy) if (regprog_is_copy)
cur->match.regprog = cur->hl.rm.regprog; cur->match.regprog = cur->hl.rm.regprog;

View File

@ -6,6 +6,9 @@
* Do ":help credits" in Vim to see a list of people who contributed. * Do ":help credits" in Vim to see a list of people who contributed.
*/ */
#ifndef OS_MAC__H
#define OS_MAC__H
// Before Including the MacOS specific files, // Before Including the MacOS specific files,
// let's set the OPAQUE_TOOLBOX_STRUCTS to 0 so we // let's set the OPAQUE_TOOLBOX_STRUCTS to 0 so we
// can access the internal structures. // can access the internal structures.
@ -266,3 +269,52 @@
// A Mac constant causing big problem to syntax highlighting // A Mac constant causing big problem to syntax highlighting
#define UNKNOWN_CREATOR '\?\?\?\?' #define UNKNOWN_CREATOR '\?\?\?\?'
#ifdef FEAT_RELTIME
# include <dispatch/dispatch.h>
# if !defined(MAC_OS_X_VERSION_10_12) || \
(MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_12)
typedef int clockid_t;
# endif
# ifndef CLOCK_REALTIME
# define CLOCK_REALTIME 0
# endif
# ifndef CLOCK_MONOTONIC
# define CLOCK_MONOTONIC 1
# endif
struct itimerspec
{
struct timespec it_interval; // timer period
struct timespec it_value; // initial expiration
};
struct sigevent;
struct macos_timer
{
dispatch_queue_t tim_queue;
dispatch_source_t tim_timer;
void (*tim_func)(union sigval);
void *tim_arg;
};
typedef struct macos_timer *timer_t;
extern int timer_create(
clockid_t clockid,
struct sigevent *sevp,
timer_t *timerid);
extern int timer_delete(timer_t timerid);
extern int timer_settime(
timer_t timerid, int flags,
const struct itimerspec *new_value,
struct itimerspec *unused);
#endif // FEAT_RELTIME
#endif // OS_MAC__H

View File

@ -23,6 +23,13 @@
* X11 header files. */ * X11 header files. */
#define NO_X11_INCLUDES #define NO_X11_INCLUDES
#include <stdbool.h>
#include <mach/boolean.h>
#include <sys/errno.h>
#include <stdlib.h>
#include <dispatch/dispatch.h>
#include "vim.h" #include "vim.h"
#import <AppKit/AppKit.h> #import <AppKit/AppKit.h>
@ -208,6 +215,175 @@ releasepool:
#endif /* FEAT_CLIPBOARD */ #endif /* FEAT_CLIPBOARD */
#ifdef FEAT_RELTIME
/*
* The following timer code is based on a Gist by Jorgen Lundman:
*
* https://gist.github.com/lundman
*/
typedef struct macos_timer macos_timer_T;
static void
_timer_cancel(void *arg UNUSED)
{
// This is not currently used, but it might be useful in the future and
// it is non-trivial enough to provide as usable implementation.
# if 0
macos_timer_T *timerid = (macos_timer_T *)arg;
dispatch_release(timerid->tim_timer);
dispatch_release(timerid->tim_queue);
timerid->tim_timer = NULL;
timerid->tim_queue = NULL;
free(timerid);
# endif
}
static void
_timer_handler(void *arg)
{
macos_timer_T *timerid = (macos_timer_T *)arg;
union sigval sv;
sv.sival_ptr = timerid->tim_arg;
if (timerid->tim_func != NULL)
timerid->tim_func(sv);
}
static uint64_t
itime_to_ns(const struct timespec *it)
{
time_t sec = it->tv_sec;
long nsec = it->tv_nsec;
uint64_t ns = NSEC_PER_SEC * sec + nsec;
return ns == 0 ? DISPATCH_TIME_FOREVER : ns;
}
/*
* A partial emulation of the POSIX timer_create function.
*
* The limitations and differences include:
*
* - Only CLOCK_REALTIME and CLOCK_MONOTONIC are supported as clockid
* values.
* - Even if CLOCK_REALTIME is specified, internally the mach_absolute_time
* source is used internally.
* - The only notification method supported is SIGEV_THREAD.
*/
inline int
timer_create(clockid_t clockid, struct sigevent *sevp, timer_t *timerid)
{
macos_timer_T *timer = NULL;
// We only support real time and monotonic clocks; and SIGEV_THREAD
// notification. In practice, there is no difference between the two
// types of clocks on MacOS - we always use the mach_machine_time
// source.
if ( (clockid != CLOCK_REALTIME && clockid != CLOCK_MONOTONIC)
|| sevp->sigev_notify != SIGEV_THREAD)
{
semsg("clockid: %d %d", clockid, CLOCK_REALTIME);
semsg("notify: %d %d", sevp->sigev_notify, SIGEV_THREAD);
errno = ENOTSUP;
return -1;
}
timer = (macos_timer_T *)malloc(sizeof(macos_timer_T));
if (timer == NULL)
{
errno = ENOMEM;
return -1;
}
*timerid = timer;
timer->tim_queue = dispatch_queue_create(
"org.vim.timerqueue", NULL);
if (timer->tim_queue == NULL)
{
errno = ENOMEM;
return -1;
}
timer->tim_timer = dispatch_source_create(
DISPATCH_SOURCE_TYPE_TIMER, 0, 0, timer->tim_queue);
if (timer->tim_timer == NULL)
{
errno = ENOMEM;
return -1;
}
timer->tim_func = sevp->sigev_notify_function;
timer->tim_arg = sevp->sigev_value.sival_ptr;
dispatch_set_context(timer->tim_timer, timer);
dispatch_source_set_event_handler_f(timer->tim_timer, _timer_handler);
dispatch_source_set_cancel_handler_f(timer->tim_timer, _timer_cancel);
dispatch_resume(timer->tim_timer);
return 0;
}
/*
* A partial emulation of the POSIX timer_settime function.
*
* The limitations and differences include:
*
* - The flags argument is ignored. The supplied new_value is therfore
* always treated as a relative time.
* - The old_value argument is ignored.
*/
int
timer_settime(
timer_t timerid,
int unused_flags UNUSED,
const struct itimerspec *new_value,
struct itimerspec *old_value UNUSED)
{
uint64_t first_shot = itime_to_ns(&new_value->it_value);
if (timerid == NULL)
return 0;
if (first_shot == DISPATCH_TIME_FOREVER)
{
dispatch_source_set_timer(
timerid->tim_timer, first_shot, first_shot, 0);
}
else
{
uint64_t interval = itime_to_ns(&new_value->it_interval);
dispatch_time_t start = dispatch_time(DISPATCH_TIME_NOW, first_shot);
dispatch_source_set_timer(timerid->tim_timer, start, interval, 0);
}
return 0;
}
/*
* An emulation of the POSIX timer_delete function.
*
* Disabled because it is not currently used, but an implemented provided
* for completeness and possible future use.
*/
#if 0
int
timer_delete(timer_t timerid)
{
/* Calls _timer_cancel() */
if (timerid != NULL)
dispatch_source_cancel(timerid->tim_timer);
return 0;
}
#endif
#endif /* FEAT_RELTIME */
/* Lift the compiler warning suppression. */ /* Lift the compiler warning suppression. */
#if defined(__clang__) && defined(__STRICT_ANSI__) #if defined(__clang__) && defined(__STRICT_ANSI__)
# pragma clang diagnostic pop # pragma clang diagnostic pop

View File

@ -8256,3 +8256,217 @@ xsmp_close(void)
} }
} }
#endif // USE_XSMP #endif // USE_XSMP
#if defined(FEAT_RELTIME) || defined(PROTO)
# if defined(HAVE_TIMER_CREATE) || defined(MACOS_X)
/*
* Implement timeout with timer_create() and timer_settime().
*/
static int timeout_flag = FALSE;
static timer_t timer_id;
static int timer_created = FALSE;
/*
* Callback for when the timer expires.
*/
static void
set_flag(union sigval _unused UNUSED)
{
timeout_flag = TRUE;
}
/*
* Stop any active timeout.
*/
void
stop_timeout(void)
{
static struct itimerspec disarm = {{0, 0}, {0, 0}};
if (timer_created)
{
int ret = timer_settime(timer_id, 0, &disarm, NULL);
if (ret < 0)
semsg(_(e_could_not_clear_timeout_str), strerror(errno));
}
// Clear the current timeout flag; any previous timeout should be
// considered _not_ triggered.
timeout_flag = FALSE;
}
/*
* Start the timeout timer.
*
* The return value is a pointer to a flag that is initialised to FALSE. If the
* timeout expires, the flag is set to TRUE. This will only return pointers to
* static memory; i.e. any pointer returned by this function may always be
* safely dereferenced.
*
* This function is not expected to fail, but if it does it will still return a
* valid flag pointer; the flag will remain stuck as FALSE .
*/
const int *
start_timeout(long msec)
{
struct itimerspec interval = {
{0, 0}, // Do not repeat.
{msec / 1000, (msec % 1000) * 1000000}}; // Timeout interval
int ret;
// This is really the caller's responsibility, but let's make sure the
// previous timer has been stopped.
stop_timeout();
timeout_flag = FALSE;
if (!timer_created)
{
struct sigevent action = {0};
action.sigev_notify = SIGEV_THREAD;
action.sigev_notify_function = set_flag;
ret = timer_create(CLOCK_MONOTONIC, &action, &timer_id);
if (ret < 0)
{
semsg(_(e_could_not_set_timeout_str), strerror(errno));
return &timeout_flag;
}
timer_created = TRUE;
}
ret = timer_settime(timer_id, 0, &interval, NULL);
if (ret < 0)
semsg(_(e_could_not_set_timeout_str), strerror(errno));
return &timeout_flag;
}
# else
/*
* Implement timeout with setitimer()
*/
static struct itimerval prev_interval;
static struct sigaction prev_sigaction;
static int timeout_flag = FALSE;
static int timer_active = FALSE;
static int timer_handler_active = FALSE;
static int alarm_pending = FALSE;
/*
* Handle SIGALRM for a timeout.
*/
static RETSIGTYPE
set_flag SIGDEFARG(sigarg)
{
if (alarm_pending)
alarm_pending = FALSE;
else
timeout_flag = TRUE;
}
/*
* Stop any active timeout.
*/
void
stop_timeout(void)
{
static struct itimerval disarm = {{0, 0}, {0, 0}};
int ret;
if (timer_active)
{
timer_active = FALSE;
ret = setitimer(ITIMER_REAL, &disarm, &prev_interval);
if (ret < 0)
// Should only get here as a result of coding errors.
semsg(_(e_could_not_clear_timeout_str), strerror(errno));
}
if (timer_handler_active)
{
timer_handler_active = FALSE;
ret = sigaction(SIGALRM, &prev_sigaction, NULL);
if (ret < 0)
// Should only get here as a result of coding errors.
semsg(_(e_could_not_reset_handler_for_timeout_str),
strerror(errno));
}
timeout_flag = 0;
}
/*
* Start the timeout timer.
*
* The return value is a pointer to a flag that is initialised to FALSE. If the
* timeout expires, the flag is set to TRUE. This will only return pointers to
* static memory; i.e. any pointer returned by this function may always be
* safely dereferenced.
*
* This function is not expected to fail, but if it does it will still return a
* valid flag pointer; the flag will remain stuck as FALSE .
*/
const int *
start_timeout(long msec)
{
struct itimerval interval = {
{0, 0}, // Do not repeat.
{msec / 1000, (msec % 1000) * 1000}}; // Timeout interval
struct sigaction handle_alarm;
int ret;
sigset_t sigs;
sigset_t saved_sigs;
// This is really the caller's responsibility, but let's make sure the
// previous timer has been stopped.
stop_timeout();
// There is a small chance that SIGALRM is pending and so the handler must
// ignore it on the first call.
alarm_pending = FALSE;
ret = sigemptyset(&sigs);
ret = ret == 0 ? sigaddset(&sigs, SIGALRM) : ret;
ret = ret == 0 ? sigprocmask(SIG_BLOCK, &sigs, &saved_sigs) : ret;
timeout_flag = FALSE;
ret = ret == 0 ? sigpending(&sigs) : ret;
if (ret == 0)
{
alarm_pending = sigismember(&sigs, SIGALRM);
ret = ret == 0 ? sigprocmask(SIG_SETMASK, &saved_sigs, NULL) : ret;
}
if (unlikely(ret != 0 || alarm_pending < 0))
{
// Just catching coding errors. Write an error message, but carry on.
semsg(_(e_could_not_check_for_pending_sigalrm_str), strerror(errno));
alarm_pending = FALSE;
}
// Set up the alarm handler first.
ret = sigemptyset(&handle_alarm.sa_mask);
handle_alarm.sa_handler = set_flag;
handle_alarm.sa_flags = 0;
ret = ret == 0 ? sigaction(SIGALRM, &handle_alarm, &prev_sigaction) : ret;
if (ret < 0)
{
// Should only get here as a result of coding errors.
semsg(_(e_could_not_set_handler_for_timeout_str), strerror(errno));
return &timeout_flag;
}
timer_handler_active = TRUE;
// Set up the interval timer once the alarm handler is in place.
ret = setitimer(ITIMER_REAL, &interval, &prev_interval);
if (ret < 0)
{
// Should only get here as a result of coding errors.
semsg(_(e_could_not_set_timeout_str), strerror(errno));
stop_timeout();
return &timeout_flag;
}
timer_active = TRUE;
return &timeout_flag;
}
# endif // HAVE_TIMER_CREATE
#endif // FEAT_RELTIME

View File

@ -100,6 +100,8 @@ typedef char * LPCSTR;
typedef char * LPWSTR; typedef char * LPWSTR;
typedef int ACCESS_MASK; typedef int ACCESS_MASK;
typedef int BOOL; typedef int BOOL;
typedef int BOOLEAN;
typedef int CALLBACK;
typedef int COLORREF; typedef int COLORREF;
typedef int CONSOLE_CURSOR_INFO; typedef int CONSOLE_CURSOR_INFO;
typedef int COORD; typedef int COORD;
@ -7327,6 +7329,7 @@ typedef struct _FILE_EA_INFORMATION_ {
ULONG EaSize; ULONG EaSize;
} FILE_EA_INFORMATION_, *PFILE_EA_INFORMATION_; } FILE_EA_INFORMATION_, *PFILE_EA_INFORMATION_;
#ifndef PROTO
typedef NTSTATUS (NTAPI *PfnNtOpenFile)( typedef NTSTATUS (NTAPI *PfnNtOpenFile)(
PHANDLE FileHandle, PHANDLE FileHandle,
ACCESS_MASK DesiredAccess, ACCESS_MASK DesiredAccess,
@ -7367,6 +7370,7 @@ PfnNtSetEaFile pNtSetEaFile = NULL;
PfnNtQueryEaFile pNtQueryEaFile = NULL; PfnNtQueryEaFile pNtQueryEaFile = NULL;
PfnNtQueryInformationFile pNtQueryInformationFile = NULL; PfnNtQueryInformationFile pNtQueryInformationFile = NULL;
PfnRtlInitUnicodeString pRtlInitUnicodeString = NULL; PfnRtlInitUnicodeString pRtlInitUnicodeString = NULL;
#endif
/* /*
* Load ntdll.dll functions. * Load ntdll.dll functions.
@ -8315,3 +8319,85 @@ GetWin32Error(void)
} }
return msg; return msg;
} }
#if defined(FEAT_RELTIME) || defined(PROTO)
static HANDLE timer_handle;
static int timer_active = FALSE;
/*
* Calls to start_timeout alternate the return value pointer between the two
* entries in timeout_flags. If the previously active timeout is very close to
* expiring when start_timeout() is called then a race condition means that the
* set_flag() function may still be invoked after the previous timer is
* deleted. Ping-ponging between the two flags prevents this causing 'fake'
* timeouts.
*/
static int timeout_flags[2];
static int flag_idx = 0;
static int *timeout_flag = &timeout_flags[0];
static void CALLBACK
set_flag(void *param, BOOLEAN unused2)
{
int *timeout_flag = (int *)param;
*timeout_flag = TRUE;
}
/*
* Stop any active timeout.
*/
void
stop_timeout(void)
{
if (timer_active)
{
BOOL ret = DeleteTimerQueueTimer(NULL, timer_handle, NULL);
timer_active = FALSE;
if (!ret && GetLastError() != ERROR_IO_PENDING)
{
semsg(_(e_could_not_clear_timeout_str), GetWin32Error());
}
}
*timeout_flag = FALSE;
}
/*
* Start the timeout timer.
*
* The period is defined in milliseconds.
*
* The return value is a pointer to a flag that is initialised to 0. If the
* timeout expires, the flag is set to 1. This will only return pointers to
* static memory; i.e. any pointer returned by this function may always be
* safely dereferenced.
*
* This function is not expected to fail, but if it does it still returns a
* valid flag pointer; the flag will remain stuck at zero.
*/
const int *
start_timeout(long msec)
{
UINT interval = (UINT)msec;
BOOL ret;
timeout_flag = &timeout_flags[flag_idx];
stop_timeout();
ret = CreateTimerQueueTimer(
&timer_handle, NULL, set_flag, timeout_flag,
(DWORD)msec, 0, WT_EXECUTEDEFAULT);
if (!ret)
{
semsg(_(e_could_not_set_timeout_str), GetWin32Error());
}
else
{
flag_idx = (flag_idx + 1) % 2;
timer_active = TRUE;
*timeout_flag = FALSE;
}
return timeout_flag;
}
#endif

View File

@ -72,6 +72,7 @@ int mch_expand_wildcards(int num_pat, char_u **pat, int *num_file, char_u ***fil
int mch_has_exp_wildcard(char_u *p); int mch_has_exp_wildcard(char_u *p);
int mch_has_wildcard(char_u *p); int mch_has_wildcard(char_u *p);
int mch_rename(const char *src, const char *dest); int mch_rename(const char *src, const char *dest);
int gpm_available(void);
int gpm_enabled(void); int gpm_enabled(void);
int mch_libcall(char_u *libname, char_u *funcname, char_u *argstring, int argint, char_u **string_result, int *number_result); int mch_libcall(char_u *libname, char_u *funcname, char_u *argstring, int argint, char_u **string_result, int *number_result);
void setup_term_clip(void); void setup_term_clip(void);
@ -85,5 +86,6 @@ void clip_xterm_set_selection(Clipboard_T *cbd);
int xsmp_handle_requests(void); int xsmp_handle_requests(void);
void xsmp_init(void); void xsmp_init(void);
void xsmp_close(void); void xsmp_close(void);
int gpm_available(void); void stop_timeout(void);
const int *start_timeout(long msec);
/* vim: set ft=c : */ /* vim: set ft=c : */

View File

@ -83,5 +83,7 @@ int get_conpty_type(void);
int is_conpty_stable(void); int is_conpty_stable(void);
int get_conpty_fix_type(void); int get_conpty_fix_type(void);
void resize_console_buf(void); void resize_console_buf(void);
char * GetWin32Error(void); char *GetWin32Error(void);
void stop_timeout(void);
const int *start_timeout(long msec);
/* vim: set ft=c : */ /* vim: set ft=c : */

View File

@ -1,4 +1,6 @@
/* regexp.c */ /* regexp.c */
void init_regexp_timeout(long msec);
void disable_regexp_timeout(void);
int re_multiline(regprog_T *prog); int re_multiline(regprog_T *prog);
char_u *skip_regexp(char_u *startp, int delim, int magic); char_u *skip_regexp(char_u *startp, int delim, int magic);
char_u *skip_regexp_err(char_u *startp, int delim, int magic); char_u *skip_regexp_err(char_u *startp, int delim, int magic);
@ -18,5 +20,5 @@ int regprog_in_use(regprog_T *prog);
int vim_regexec_prog(regprog_T **prog, int ignore_case, char_u *line, colnr_T col); int vim_regexec_prog(regprog_T **prog, int ignore_case, char_u *line, colnr_T col);
int vim_regexec(regmatch_T *rmp, char_u *line, colnr_T col); int vim_regexec(regmatch_T *rmp, char_u *line, colnr_T col);
int vim_regexec_nl(regmatch_T *rmp, char_u *line, colnr_T col); int vim_regexec_nl(regmatch_T *rmp, char_u *line, colnr_T col);
long vim_regexec_multi(regmmatch_T *rmp, win_T *win, buf_T *buf, linenr_T lnum, colnr_T col, proftime_T *tm, int *timed_out); long vim_regexec_multi(regmmatch_T *rmp, win_T *win, buf_T *buf, linenr_T lnum, colnr_T col, int *timed_out);
/* vim: set ft=c : */ /* vim: set ft=c : */

View File

@ -5990,7 +5990,7 @@ vgr_match_buflines(
{ {
// Regular expression match // Regular expression match
while (vim_regexec_multi(regmatch, curwin, buf, lnum, while (vim_regexec_multi(regmatch, curwin, buf, lnum,
col, NULL, NULL) > 0) col, NULL) > 0)
{ {
// Pass the buffer number so that it gets used even for a // Pass the buffer number so that it gets used even for a
// dummy buffer, unless duplicate_name is set, then the // dummy buffer, unless duplicate_name is set, then the

View File

@ -20,6 +20,11 @@
# define BT_REGEXP_DEBUG_LOG_NAME "bt_regexp_debug.log" # define BT_REGEXP_DEBUG_LOG_NAME "bt_regexp_debug.log"
#endif #endif
#ifdef FEAT_RELTIME
static int dummy_timeout_flag = 0;
static const int *timeout_flag = &dummy_timeout_flag;
#endif
/* /*
* Magic characters have a special meaning, they don't match literally. * Magic characters have a special meaning, they don't match literally.
* Magic characters are negative. This separates them from literal characters * Magic characters are negative. This separates them from literal characters
@ -45,6 +50,20 @@ toggle_Magic(int x)
return Magic(x); return Magic(x);
} }
#ifdef FEAT_RELTIME
void
init_regexp_timeout(long msec)
{
timeout_flag = start_timeout(msec);
}
void
disable_regexp_timeout(void)
{
stop_timeout();
}
#endif
/* /*
* The first byte of the BT regexp internal "program" is actually this magic * The first byte of the BT regexp internal "program" is actually this magic
* number; the start node begins in the second byte. It's used to catch the * number; the start node begins in the second byte. It's used to catch the
@ -1944,8 +1963,9 @@ vim_regsub_both(
#ifdef FEAT_EVAL #ifdef FEAT_EVAL
// To make sure that the length doesn't change between checking the // To make sure that the length doesn't change between checking the
// length and copying the string, and to speed up things, the // length and copying the string, and to speed up things, the
// resulting string is saved from the call with "flags & REGSUB_COPY" // resulting string is saved from the call with
// == 0 to the // call with "flags & REGSUB_COPY" != 0. // "flags & REGSUB_COPY" == 0 to the call with
// "flags & REGSUB_COPY" != 0.
if (copy) if (copy)
{ {
if (eval_result != NULL) if (eval_result != NULL)
@ -1960,7 +1980,7 @@ vim_regsub_both(
int prev_can_f_submatch = can_f_submatch; int prev_can_f_submatch = can_f_submatch;
regsubmatch_T rsm_save; regsubmatch_T rsm_save;
vim_free(eval_result); VIM_CLEAR(eval_result);
// The expression may contain substitute(), which calls us // The expression may contain substitute(), which calls us
// recursively. Make sure submatch() gets the text from the first // recursively. Make sure submatch() gets the text from the first
@ -2905,7 +2925,6 @@ vim_regexec_multi(
buf_T *buf, // buffer in which to search buf_T *buf, // buffer in which to search
linenr_T lnum, // nr of line to start looking for match linenr_T lnum, // nr of line to start looking for match
colnr_T col, // column to start looking for match colnr_T col, // column to start looking for match
proftime_T *tm, // timeout limit or NULL
int *timed_out) // flag is set when timeout limit reached int *timed_out) // flag is set when timeout limit reached
{ {
int result; int result;
@ -2926,7 +2945,7 @@ vim_regexec_multi(
rex_in_use = TRUE; rex_in_use = TRUE;
result = rmp->regprog->engine->regexec_multi( result = rmp->regprog->engine->regexec_multi(
rmp, win, buf, lnum, col, tm, timed_out); rmp, win, buf, lnum, col, timed_out);
rmp->regprog->re_in_use = FALSE; rmp->regprog->re_in_use = FALSE;
// NFA engine aborted because it's very slow. // NFA engine aborted because it's very slow.
@ -2966,7 +2985,7 @@ vim_regexec_multi(
rmp->regprog->re_in_use = TRUE; rmp->regprog->re_in_use = TRUE;
result = rmp->regprog->engine->regexec_multi( result = rmp->regprog->engine->regexec_multi(
rmp, win, buf, lnum, col, tm, timed_out); rmp, win, buf, lnum, col, timed_out);
rmp->regprog->re_in_use = FALSE; rmp->regprog->re_in_use = FALSE;
} }
vim_free(pat); vim_free(pat);

View File

@ -173,7 +173,7 @@ struct regengine
// bt_regexec_nl or nfa_regexec_nl // bt_regexec_nl or nfa_regexec_nl
int (*regexec_nl)(regmatch_T *, char_u *, colnr_T, int); int (*regexec_nl)(regmatch_T *, char_u *, colnr_T, int);
// bt_regexec_mult or nfa_regexec_mult // bt_regexec_mult or nfa_regexec_mult
long (*regexec_multi)(regmmatch_T *, win_T *, buf_T *, linenr_T, colnr_T, proftime_T *, int *); long (*regexec_multi)(regmmatch_T *, win_T *, buf_T *, linenr_T, colnr_T, int *);
//char_u *expr; //char_u *expr;
}; };

View File

@ -3228,7 +3228,6 @@ restore_subexpr(regbehind_T *bp)
static int static int
regmatch( regmatch(
char_u *scan, // Current node. char_u *scan, // Current node.
proftime_T *tm UNUSED, // timeout limit or NULL
int *timed_out UNUSED) // flag set on timeout or NULL int *timed_out UNUSED) // flag set on timeout or NULL
{ {
char_u *next; // Next node. char_u *next; // Next node.
@ -3237,9 +3236,6 @@ regmatch(
regitem_T *rp; regitem_T *rp;
int no; int no;
int status; // one of the RA_ values: int status; // one of the RA_ values:
#ifdef FEAT_RELTIME
int tm_count = 0;
#endif
// Make "regstack" and "backpos" empty. They are allocated and freed in // Make "regstack" and "backpos" empty. They are allocated and freed in
// bt_regexec_both() to reduce malloc()/free() calls. // bt_regexec_both() to reduce malloc()/free() calls.
@ -3271,19 +3267,12 @@ regmatch(
break; break;
} }
#ifdef FEAT_RELTIME #ifdef FEAT_RELTIME
// Check for timeout once in 250 times to avoid excessive overhead from if (*timeout_flag)
// reading the clock. The value has been picked to check about once
// per msec on a modern CPU.
if (tm != NULL && ++tm_count == 250)
{ {
tm_count = 0; if (timed_out != NULL)
if (profile_passed_limit(tm)) *timed_out = TRUE;
{ status = RA_FAIL;
if (timed_out != NULL) break;
*timed_out = TRUE;
status = RA_FAIL;
break;
}
} }
#endif #endif
status = RA_CONT; status = RA_CONT;
@ -3315,7 +3304,7 @@ regmatch(
op = OP(scan); op = OP(scan);
// Check for character class with NL added. // Check for character class with NL added.
if (!rex.reg_line_lbr && WITH_NL(op) && REG_MULTI if (!rex.reg_line_lbr && WITH_NL(op) && REG_MULTI
&& *rex.input == NUL && rex.lnum <= rex.reg_maxline) && *rex.input == NUL && rex.lnum <= rex.reg_maxline)
{ {
reg_nextline(); reg_nextline();
} }
@ -4732,7 +4721,6 @@ regmatch(
regtry( regtry(
bt_regprog_T *prog, bt_regprog_T *prog,
colnr_T col, colnr_T col,
proftime_T *tm, // timeout limit or NULL
int *timed_out) // flag set on timeout or NULL int *timed_out) // flag set on timeout or NULL
{ {
rex.input = rex.line + col; rex.input = rex.line + col;
@ -4742,7 +4730,7 @@ regtry(
rex.need_clear_zsubexpr = (prog->reghasz == REX_SET); rex.need_clear_zsubexpr = (prog->reghasz == REX_SET);
#endif #endif
if (regmatch(prog->program + 1, tm, timed_out) == 0) if (regmatch(prog->program + 1, timed_out) == 0)
return 0; return 0;
cleanup_subexpr(); cleanup_subexpr();
@ -4817,7 +4805,6 @@ regtry(
bt_regexec_both( bt_regexec_both(
char_u *line, char_u *line,
colnr_T col, // column to start looking for match colnr_T col, // column to start looking for match
proftime_T *tm, // timeout limit or NULL
int *timed_out) // flag set on timeout or NULL int *timed_out) // flag set on timeout or NULL
{ {
bt_regprog_T *prog; bt_regprog_T *prog;
@ -4940,15 +4927,12 @@ bt_regexec_both(
&& (((enc_utf8 && utf_fold(prog->regstart) == utf_fold(c))) && (((enc_utf8 && utf_fold(prog->regstart) == utf_fold(c)))
|| (c < 255 && prog->regstart < 255 && || (c < 255 && prog->regstart < 255 &&
MB_TOLOWER(prog->regstart) == MB_TOLOWER(c))))) MB_TOLOWER(prog->regstart) == MB_TOLOWER(c)))))
retval = regtry(prog, col, tm, timed_out); retval = regtry(prog, col, timed_out);
else else
retval = 0; retval = 0;
} }
else else
{ {
#ifdef FEAT_RELTIME
int tm_count = 0;
#endif
// Messy cases: unanchored match. // Messy cases: unanchored match.
while (!got_int) while (!got_int)
{ {
@ -4975,7 +4959,7 @@ bt_regexec_both(
break; break;
} }
retval = regtry(prog, col, tm, timed_out); retval = regtry(prog, col, timed_out);
if (retval > 0) if (retval > 0)
break; break;
@ -4992,18 +4976,11 @@ bt_regexec_both(
else else
++col; ++col;
#ifdef FEAT_RELTIME #ifdef FEAT_RELTIME
// Check for timeout once in 500 times to avoid excessive overhead if (*timeout_flag)
// from reading the clock. The value has been picked to check
// about once per msec on a modern CPU.
if (tm != NULL && ++tm_count == 500)
{ {
tm_count = 0; if (timed_out != NULL)
if (profile_passed_limit(tm)) *timed_out = TRUE;
{ break;
if (timed_out != NULL)
*timed_out = TRUE;
break;
}
} }
#endif #endif
} }
@ -5067,7 +5044,7 @@ bt_regexec_nl(
rex.reg_icombine = FALSE; rex.reg_icombine = FALSE;
rex.reg_maxcol = 0; rex.reg_maxcol = 0;
return bt_regexec_both(line, col, NULL, NULL); return bt_regexec_both(line, col, NULL);
} }
/* /*
@ -5085,11 +5062,10 @@ bt_regexec_multi(
buf_T *buf, // buffer in which to search buf_T *buf, // buffer in which to search
linenr_T lnum, // nr of line to start looking for match linenr_T lnum, // nr of line to start looking for match
colnr_T col, // column to start looking for match colnr_T col, // column to start looking for match
proftime_T *tm, // timeout limit or NULL
int *timed_out) // flag set on timeout or NULL int *timed_out) // flag set on timeout or NULL
{ {
init_regexec_multi(rmp, win, buf, lnum); init_regexec_multi(rmp, win, buf, lnum);
return bt_regexec_both(NULL, col, tm, timed_out); return bt_regexec_both(NULL, col, timed_out);
} }
/* /*

View File

@ -4051,7 +4051,6 @@ pim_info(nfa_pim_T *pim)
// Used during execution: whether a match has been found. // Used during execution: whether a match has been found.
static int nfa_match; static int nfa_match;
#ifdef FEAT_RELTIME #ifdef FEAT_RELTIME
static proftime_T *nfa_time_limit;
static int *nfa_timed_out; static int *nfa_timed_out;
#endif #endif
@ -5650,29 +5649,13 @@ find_match_text(colnr_T startcol, int regstart, char_u *match_text)
* To reduce overhead, only check one in "count" times. * To reduce overhead, only check one in "count" times.
*/ */
static int static int
nfa_did_time_out(int count) nfa_did_time_out(void)
{ {
static int tm_count = 0; if (*timeout_flag)
// Check for timeout once in "count" times to avoid excessive overhead from
// reading the clock.
if (nfa_time_limit != NULL)
{ {
if (tm_count >= count) if (nfa_timed_out != NULL)
{ *nfa_timed_out = TRUE;
if (profile_passed_limit(nfa_time_limit)) return TRUE;
{
if (nfa_timed_out != NULL)
*nfa_timed_out = TRUE;
tm_count = 99999;
return TRUE;
}
// Only reset the count when not timed out, so that when it did
// timeout it keeps timing out until the time limit is changed.
tm_count = 0;
}
else
++tm_count;
} }
return FALSE; return FALSE;
} }
@ -5726,7 +5709,7 @@ nfa_regmatch(
return FALSE; return FALSE;
#ifdef FEAT_RELTIME #ifdef FEAT_RELTIME
// Check relatively often here, since this is the toplevel matching. // Check relatively often here, since this is the toplevel matching.
if (nfa_did_time_out(100)) if (nfa_did_time_out())
return FALSE; return FALSE;
#endif #endif
@ -5880,8 +5863,7 @@ nfa_regmatch(
if (got_int) if (got_int)
break; break;
#ifdef FEAT_RELTIME #ifdef FEAT_RELTIME
// do not check very often here, since this is a loop in a loop if (nfa_did_time_out())
if (nfa_did_time_out(2000))
break; break;
#endif #endif
t = &thislist->t[listidx]; t = &thislist->t[listidx];
@ -7127,8 +7109,8 @@ nextchar:
if (got_int) if (got_int)
break; break;
#ifdef FEAT_RELTIME #ifdef FEAT_RELTIME
// check regularly but not too often here // Check for timeout once in a twenty times to avoid overhead.
if (nfa_did_time_out(800)) if (nfa_did_time_out())
break; break;
#endif #endif
} }
@ -7160,7 +7142,6 @@ theend:
nfa_regtry( nfa_regtry(
nfa_regprog_T *prog, nfa_regprog_T *prog,
colnr_T col, colnr_T col,
proftime_T *tm UNUSED, // timeout limit or NULL
int *timed_out UNUSED) // flag set on timeout or NULL int *timed_out UNUSED) // flag set on timeout or NULL
{ {
int i; int i;
@ -7173,7 +7154,6 @@ nfa_regtry(
rex.input = rex.line + col; rex.input = rex.line + col;
#ifdef FEAT_RELTIME #ifdef FEAT_RELTIME
nfa_time_limit = tm;
nfa_timed_out = timed_out; nfa_timed_out = timed_out;
#endif #endif
@ -7301,7 +7281,6 @@ nfa_regtry(
nfa_regexec_both( nfa_regexec_both(
char_u *line, char_u *line,
colnr_T startcol, // column to start looking for match colnr_T startcol, // column to start looking for match
proftime_T *tm, // timeout limit or NULL
int *timed_out) // flag set on timeout or NULL int *timed_out) // flag set on timeout or NULL
{ {
nfa_regprog_T *prog; nfa_regprog_T *prog;
@ -7397,7 +7376,7 @@ nfa_regexec_both(
prog->state[i].lastlist[1] = 0; prog->state[i].lastlist[1] = 0;
} }
retval = nfa_regtry(prog, col, tm, timed_out); retval = nfa_regtry(prog, col, timed_out);
#ifdef DEBUG #ifdef DEBUG
nfa_regengine.expr = NULL; nfa_regengine.expr = NULL;
@ -7577,7 +7556,7 @@ nfa_regexec_nl(
rex.reg_ic = rmp->rm_ic; rex.reg_ic = rmp->rm_ic;
rex.reg_icombine = FALSE; rex.reg_icombine = FALSE;
rex.reg_maxcol = 0; rex.reg_maxcol = 0;
return nfa_regexec_both(line, col, NULL, NULL); return nfa_regexec_both(line, col, NULL);
} }
@ -7613,11 +7592,10 @@ nfa_regexec_multi(
buf_T *buf, // buffer in which to search buf_T *buf, // buffer in which to search
linenr_T lnum, // nr of line to start looking for match linenr_T lnum, // nr of line to start looking for match
colnr_T col, // column to start looking for match colnr_T col, // column to start looking for match
proftime_T *tm, // timeout limit or NULL
int *timed_out) // flag set on timeout or NULL int *timed_out) // flag set on timeout or NULL
{ {
init_regexec_multi(rmp, win, buf, lnum); init_regexec_multi(rmp, win, buf, lnum);
return nfa_regexec_both(NULL, col, tm, timed_out); return nfa_regexec_both(NULL, col, timed_out);
} }
#ifdef DEBUG #ifdef DEBUG

View File

@ -1760,10 +1760,6 @@ start_search_hl(void)
end_search_hl(); // just in case it wasn't called before end_search_hl(); // just in case it wasn't called before
last_pat_prog(&screen_search_hl.rm); last_pat_prog(&screen_search_hl.rm);
screen_search_hl.attr = HL_ATTR(HLF_L); screen_search_hl.attr = HL_ATTR(HLF_L);
# ifdef FEAT_RELTIME
// Set the time limit to 'redrawtime'.
profile_setlimit(p_rdt, &screen_search_hl.tm);
# endif
} }
} }
@ -5029,4 +5025,3 @@ set_chars_option(win_T *wp, char_u **varp)
return NULL; // no error return NULL; // no error
} }

View File

@ -658,19 +658,8 @@ searchit(
int break_loop = FALSE; int break_loop = FALSE;
#endif #endif
linenr_T stop_lnum = 0; // stop after this line number when != 0 linenr_T stop_lnum = 0; // stop after this line number when != 0
#ifdef FEAT_RELTIME int unused_timeout_flag = FALSE;
proftime_T *tm = NULL; // timeout limit or NULL int *timed_out = &unused_timeout_flag; // set when timed out.
int *timed_out = NULL; // set when timed out or NULL
#endif
if (extra_arg != NULL)
{
stop_lnum = extra_arg->sa_stop_lnum;
#ifdef FEAT_RELTIME
tm = extra_arg->sa_tm;
timed_out = &extra_arg->sa_timed_out;
#endif
}
if (search_regcomp(pat, RE_SEARCH, pat_use, if (search_regcomp(pat, RE_SEARCH, pat_use,
(options & (SEARCH_HIS + SEARCH_KEEP)), &regmatch) == FAIL) (options & (SEARCH_HIS + SEARCH_KEEP)), &regmatch) == FAIL)
@ -680,6 +669,18 @@ searchit(
return FAIL; return FAIL;
} }
if (extra_arg != NULL)
{
stop_lnum = extra_arg->sa_stop_lnum;
#ifdef FEAT_RELTIME
if (extra_arg->sa_tm > 0)
{
init_regexp_timeout(extra_arg->sa_tm);
timed_out = &extra_arg->sa_timed_out;
}
#endif
}
/* /*
* find the string * find the string
*/ */
@ -753,11 +754,9 @@ searchit(
if (stop_lnum != 0 && (dir == FORWARD if (stop_lnum != 0 && (dir == FORWARD
? lnum > stop_lnum : lnum < stop_lnum)) ? lnum > stop_lnum : lnum < stop_lnum))
break; break;
#ifdef FEAT_RELTIME // Stop after passing the time limit.
// Stop after passing the "tm" time limit. if (*timed_out)
if (tm != NULL && profile_passed_limit(tm))
break; break;
#endif
/* /*
* Look for a match somewhere in line "lnum". * Look for a match somewhere in line "lnum".
@ -765,22 +764,12 @@ searchit(
col = at_first_line && (options & SEARCH_COL) ? pos->col col = at_first_line && (options & SEARCH_COL) ? pos->col
: (colnr_T)0; : (colnr_T)0;
nmatched = vim_regexec_multi(&regmatch, win, buf, nmatched = vim_regexec_multi(&regmatch, win, buf,
lnum, col, lnum, col, timed_out);
#ifdef FEAT_RELTIME
tm, timed_out
#else
NULL, NULL
#endif
);
// vim_regexec_multi() may clear "regprog" // vim_regexec_multi() may clear "regprog"
if (regmatch.regprog == NULL) if (regmatch.regprog == NULL)
break; break;
// Abort searching on an error (e.g., out of stack). // Abort searching on an error (e.g., out of stack).
if (called_emsg > called_emsg_before if (called_emsg > called_emsg_before || *timed_out)
#ifdef FEAT_RELTIME
|| (timed_out != NULL && *timed_out)
#endif
)
break; break;
if (nmatched > 0) if (nmatched > 0)
{ {
@ -863,13 +852,7 @@ searchit(
if (ptr[matchcol] == NUL if (ptr[matchcol] == NUL
|| (nmatched = vim_regexec_multi(&regmatch, || (nmatched = vim_regexec_multi(&regmatch,
win, buf, lnum + matchpos.lnum, win, buf, lnum + matchpos.lnum,
matchcol, matchcol, timed_out)) == 0)
#ifdef FEAT_RELTIME
tm, timed_out
#else
NULL, NULL
#endif
)) == 0)
{ {
match_ok = FALSE; match_ok = FALSE;
break; break;
@ -974,21 +957,13 @@ searchit(
if (ptr[matchcol] == NUL if (ptr[matchcol] == NUL
|| (nmatched = vim_regexec_multi(&regmatch, || (nmatched = vim_regexec_multi(&regmatch,
win, buf, lnum + matchpos.lnum, win, buf, lnum + matchpos.lnum,
matchcol, matchcol, timed_out)) == 0)
#ifdef FEAT_RELTIME
tm, timed_out
#else
NULL, NULL
#endif
)) == 0)
{ {
#ifdef FEAT_RELTIME
// If the search timed out, we did find a match // If the search timed out, we did find a match
// but it might be the wrong one, so that's not // but it might be the wrong one, so that's not
// OK. // OK.
if (timed_out != NULL && *timed_out) if (*timed_out)
match_ok = FALSE; match_ok = FALSE;
#endif
break; break;
} }
// vim_regexec_multi() may clear "regprog" // vim_regexec_multi() may clear "regprog"
@ -1097,10 +1072,7 @@ searchit(
* twice. * twice.
*/ */
if (!p_ws || stop_lnum != 0 || got_int if (!p_ws || stop_lnum != 0 || got_int
|| called_emsg > called_emsg_before || called_emsg > called_emsg_before || *timed_out
#ifdef FEAT_RELTIME
|| (timed_out != NULL && *timed_out)
#endif
#ifdef FEAT_SEARCH_EXTRA #ifdef FEAT_SEARCH_EXTRA
|| break_loop || break_loop
#endif #endif
@ -1124,10 +1096,7 @@ searchit(
if (extra_arg != NULL) if (extra_arg != NULL)
extra_arg->sa_wrapped = TRUE; extra_arg->sa_wrapped = TRUE;
} }
if (got_int || called_emsg > called_emsg_before if (got_int || called_emsg > called_emsg_before || *timed_out
#ifdef FEAT_RELTIME
|| (timed_out != NULL && *timed_out)
#endif
#ifdef FEAT_SEARCH_EXTRA #ifdef FEAT_SEARCH_EXTRA
|| break_loop || break_loop
#endif #endif
@ -1136,6 +1105,9 @@ searchit(
} }
while (--count > 0 && found); // stop after count matches or no match while (--count > 0 && found); // stop after count matches or no match
# ifdef FEAT_RELTIME
disable_regexp_timeout();
# endif
vim_regfree(regmatch.regprog); vim_regfree(regmatch.regprog);
if (!found) // did not find it if (!found) // did not find it
@ -2915,7 +2887,7 @@ is_zero_width(char_u *pattern, int move, pos_T *cur, int direction)
{ {
regmatch.startpos[0].col++; regmatch.startpos[0].col++;
nmatched = vim_regexec_multi(&regmatch, curwin, curbuf, nmatched = vim_regexec_multi(&regmatch, curwin, curbuf,
pos.lnum, regmatch.startpos[0].col, NULL, NULL); pos.lnum, regmatch.startpos[0].col, NULL);
if (nmatched != 0) if (nmatched != 0)
break; break;
} while (regmatch.regprog != NULL } while (regmatch.regprog != NULL

View File

@ -3329,9 +3329,6 @@ typedef struct
// matchaddpos(). TRUE/FALSE // matchaddpos(). TRUE/FALSE
char has_cursor; // TRUE if the cursor is inside the match, used for char has_cursor; // TRUE if the cursor is inside the match, used for
// CurSearch // CurSearch
#ifdef FEAT_RELTIME
proftime_T tm; // for a time limit
#endif
} match_T; } match_T;
// number of positions supported by matchaddpos() // number of positions supported by matchaddpos()
@ -4419,7 +4416,7 @@ typedef struct
{ {
linenr_T sa_stop_lnum; // stop after this line number when != 0 linenr_T sa_stop_lnum; // stop after this line number when != 0
#ifdef FEAT_RELTIME #ifdef FEAT_RELTIME
proftime_T *sa_tm; // timeout limit or NULL long sa_tm; // timeout limit or zero
int sa_timed_out; // set when timed out int sa_timed_out; // set when timed out
#endif #endif
int sa_wrapped; // search wrapped around int sa_wrapped; // search wrapped around

View File

@ -266,9 +266,6 @@ static reg_extmatch_T *next_match_extmatch = NULL;
static win_T *syn_win; // current window for highlighting static win_T *syn_win; // current window for highlighting
static buf_T *syn_buf; // current buffer for highlighting static buf_T *syn_buf; // current buffer for highlighting
static synblock_T *syn_block; // current buffer for highlighting static synblock_T *syn_block; // current buffer for highlighting
#ifdef FEAT_RELTIME
static proftime_T *syn_tm; // timeout limit
#endif
static linenr_T current_lnum = 0; // lnum of current state static linenr_T current_lnum = 0; // lnum of current state
static colnr_T current_col = 0; // column of current state static colnr_T current_col = 0; // column of current state
static int current_state_stored = 0; // TRUE if stored current state static int current_state_stored = 0; // TRUE if stored current state
@ -350,18 +347,6 @@ static char_u *get_syn_pattern(char_u *arg, synpat_T *ci);
static int get_id_list(char_u **arg, int keylen, short **list, int skip); static int get_id_list(char_u **arg, int keylen, short **list, int skip);
static void syn_combine_list(short **clstr1, short **clstr2, int list_op); static void syn_combine_list(short **clstr1, short **clstr2, int list_op);
#if defined(FEAT_RELTIME) || defined(PROTO)
/*
* Set the timeout used for syntax highlighting.
* Use NULL to reset, no timeout.
*/
void
syn_set_timeout(proftime_T *tm)
{
syn_tm = tm;
}
#endif
/* /*
* Start the syntax recognition for a line. This function is normally called * Start the syntax recognition for a line. This function is normally called
* from the screen updating, once for each displayed line. * from the screen updating, once for each displayed line.
@ -3166,9 +3151,7 @@ syn_regexec(
syn_time_T *st UNUSED) syn_time_T *st UNUSED)
{ {
int r; int r;
#ifdef FEAT_RELTIME
int timed_out = FALSE; int timed_out = FALSE;
#endif
#ifdef FEAT_PROFILE #ifdef FEAT_PROFILE
proftime_T pt; proftime_T pt;
@ -3183,13 +3166,7 @@ syn_regexec(
return FALSE; return FALSE;
rmp->rmm_maxcol = syn_buf->b_p_smc; rmp->rmm_maxcol = syn_buf->b_p_smc;
r = vim_regexec_multi(rmp, syn_win, syn_buf, lnum, col, r = vim_regexec_multi(rmp, syn_win, syn_buf, lnum, col, &timed_out);
#ifdef FEAT_RELTIME
syn_tm, &timed_out
#else
NULL, NULL
#endif
);
#ifdef FEAT_PROFILE #ifdef FEAT_PROFILE
if (syn_time_on) if (syn_time_on)

View File

@ -37,6 +37,15 @@ endfunc
func Test_hlsearch_hangs() func Test_hlsearch_hangs()
CheckFunction reltimefloat CheckFunction reltimefloat
" So, it turns out the Windows 7 implements TimerQueue timers differently
" and they can expire *before* the requested time has elapsed. So allow for
" the timeout occurring after 80 ms (5 * 16 (the typical clock tick)).
if has("win32")
let min_timeout = 0.08
else
let min_timeout = 0.1
endif
" This pattern takes a long time to match, it should timeout. " This pattern takes a long time to match, it should timeout.
new new
call setline(1, ['aaa', repeat('abc ', 1000), 'ccc']) call setline(1, ['aaa', repeat('abc ', 1000), 'ccc'])
@ -45,7 +54,7 @@ func Test_hlsearch_hangs()
let @/ = '\%#=1a*.*X\@<=b*' let @/ = '\%#=1a*.*X\@<=b*'
redraw redraw
let elapsed = reltimefloat(reltime(start)) let elapsed = reltimefloat(reltime(start))
call assert_true(elapsed > 0.1) call assert_true(elapsed > min_timeout)
call assert_true(elapsed < 1.0) call assert_true(elapsed < 1.0)
set nohlsearch redrawtime& set nohlsearch redrawtime&
bwipe! bwipe!

View File

@ -1550,6 +1550,32 @@ func Test_search_errors()
bwipe! bwipe!
endfunc endfunc
func Test_search_timeout()
new
let pattern = '\%#=1a*.*X\@<=b*'
let search_timeout = 0.02
let slow_target_timeout = search_timeout * 15.0
for n in range(40, 400, 30)
call setline(1, ['aaa', repeat('abc ', n), 'ccc'])
let start = reltime()
call search(pattern, '', 0)
let elapsed = reltimefloat(reltime(start))
if elapsed > slow_target_timeout
break
endif
endfor
call assert_true(elapsed > slow_target_timeout)
let max_time = elapsed / 2.0
let start = reltime()
call search(pattern, '', 0, float2nr(search_timeout * 1000))
let elapsed = reltimefloat(reltime(start))
call assert_true(elapsed < max_time)
bwipe!
endfunc
func Test_search_display_pattern() func Test_search_display_pattern()
new new
call setline(1, ['foo', 'bar', 'foobar']) call setline(1, ['foo', 'bar', 'foobar'])

View File

@ -527,6 +527,15 @@ func Test_syntax_hangs()
CheckFunction reltimefloat CheckFunction reltimefloat
CheckFeature syntax CheckFeature syntax
" So, it turns out the Windows 7 implements TimerQueue timers differently
" and they can expire *before* the requested time has elapsed. So allow for
" the timeout occurring after 80 ms (5 * 16 (the typical clock tick)).
if has("win32")
let min_timeout = 0.08
else
let min_timeout = 0.1
endif
" This pattern takes a long time to match, it should timeout. " This pattern takes a long time to match, it should timeout.
new new
call setline(1, ['aaa', repeat('abc ', 1000), 'ccc']) call setline(1, ['aaa', repeat('abc ', 1000), 'ccc'])
@ -535,7 +544,7 @@ func Test_syntax_hangs()
syn match Error /\%#=1a*.*X\@<=b*/ syn match Error /\%#=1a*.*X\@<=b*/
redraw redraw
let elapsed = reltimefloat(reltime(start)) let elapsed = reltimefloat(reltime(start))
call assert_true(elapsed > 0.1) call assert_true(elapsed > min_timeout)
call assert_true(elapsed < 1.0) call assert_true(elapsed < 1.0)
" second time syntax HL is disabled " second time syntax HL is disabled
@ -549,7 +558,7 @@ func Test_syntax_hangs()
exe "normal \<C-L>" exe "normal \<C-L>"
redraw redraw
let elapsed = reltimefloat(reltime(start)) let elapsed = reltimefloat(reltime(start))
call assert_true(elapsed > 0.1) call assert_true(elapsed > min_timeout)
call assert_true(elapsed < 1.0) call assert_true(elapsed < 1.0)
set redrawtime& set redrawtime&
@ -642,7 +651,7 @@ func Test_syntax_c()
\ "\tNote: asdf", \ "\tNote: asdf",
\ '}', \ '}',
\ ], 'Xtest.c') \ ], 'Xtest.c')
" This makes the default for 'background' use "dark", check that the " This makes the default for 'background' use "dark", check that the
" response to t_RB corrects it to "light". " response to t_RB corrects it to "light".
let $COLORFGBG = '15;0' let $COLORFGBG = '15;0'

View File

@ -734,6 +734,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 */
/**/
5057,
/**/ /**/
5056, 5056,
/**/ /**/