Patch 8.2.5057
Problem:    Using gettimeofday() for timeout is very inefficient.
Solution:   Set a platform dependent timer. (Paul Ollis, closes #10505)
Files:      src/auto/configure, src/config.h.in, src/configure.ac,
            src/drawscreen.c, src/errors.h, src/evalfunc.c, src/ex_cmds.c,
            src/ex_getln.c, src/match.c, src/os_mac.h, src/os_macosx.m,
            src/os_unix.c, src/os_win32.c, src/proto/os_unix.pro,
            src/proto/os_win32.pro, src/proto/regexp.pro, src/quickfix.c,
            src/regexp.c, src/regexp.h, src/regexp_bt.c, src/regexp_nfa.c,
            src/screen.c, src/search.c, src/structs.h, src/syntax.c,
            src/testdir/test_hlsearch.vim, src/testdir/test_search.vim,
            src/testdir/test_syntax.vim


*** ../vim-8.2.5056/src/auto/configure  2022-04-04 17:19:57.139569576 +0100
--- src/auto/configure  2022-06-05 16:45:10.470696162 +0100
***************
*** 762,768 ****
  docdir
  oldincludedir
  includedir
- runstatedir
  localstatedir
  sharedstatedir
  sysconfdir
--- 762,767 ----
***************
*** 898,904 ****
  sysconfdir='${prefix}/etc'
  sharedstatedir='${prefix}/com'
  localstatedir='${prefix}/var'
- runstatedir='${localstatedir}/run'
  includedir='${prefix}/include'
  oldincludedir='/usr/include'
  docdir='${datarootdir}/doc/${PACKAGE}'
--- 897,902 ----
***************
*** 1151,1165 ****
    | -silent | --silent | --silen | --sile | --sil)
      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)
      ac_prev=sbindir ;;
    -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
--- 1149,1154 ----
***************
*** 1297,1303 ****
  for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \
                datadir sysconfdir sharedstatedir localstatedir includedir \
                oldincludedir docdir infodir htmldir dvidir pdfdir psdir \
!               libdir localedir mandir runstatedir
  do
    eval ac_val=\$$ac_var
    # Remove trailing slashes.
--- 1286,1292 ----
  for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \
                datadir sysconfdir sharedstatedir localstatedir includedir \
                oldincludedir docdir infodir htmldir dvidir pdfdir psdir \
!               libdir localedir mandir
  do
    eval ac_val=\$$ac_var
    # Remove trailing slashes.
***************
*** 1450,1456 ****
    --sysconfdir=DIR        read-only single-machine data [PREFIX/etc]
    --sharedstatedir=DIR    modifiable architecture-independent data 
[PREFIX/com]
    --localstatedir=DIR     modifiable single-machine data [PREFIX/var]
-   --runstatedir=DIR       modifiable per-process data [LOCALSTATEDIR/run]
    --libdir=DIR            object code libraries [EPREFIX/lib]
    --includedir=DIR        C header files [PREFIX/include]
    --oldincludedir=DIR     C header files for non-gcc [/usr/include]
--- 1439,1444 ----
***************
*** 12737,12743 ****
      We can't simply define LARGE_OFF_T to be 9223372036854775807,
      since some C++ compilers masquerading as C compilers
      incorrectly reject 9223372036854775807.  */
! #define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 
31))
    int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721
                       && LARGE_OFF_T % 2147483647 == 1)
                      ? 1 : -1];
--- 12725,12731 ----
      We can't simply define LARGE_OFF_T to be 9223372036854775807,
      since some C++ compilers masquerading as C compilers
      incorrectly reject 9223372036854775807.  */
! #define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62))
    int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721
                       && LARGE_OFF_T % 2147483647 == 1)
                      ? 1 : -1];
***************
*** 12783,12789 ****
      We can't simply define LARGE_OFF_T to be 9223372036854775807,
      since some C++ compilers masquerading as C compilers
      incorrectly reject 9223372036854775807.  */
! #define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 
31))
    int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721
                       && LARGE_OFF_T % 2147483647 == 1)
                      ? 1 : -1];
--- 12771,12777 ----
      We can't simply define LARGE_OFF_T to be 9223372036854775807,
      since some C++ compilers masquerading as C compilers
      incorrectly reject 9223372036854775807.  */
! #define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62))
    int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721
                       && LARGE_OFF_T % 2147483647 == 1)
                      ? 1 : -1];
***************
*** 12807,12813 ****
      We can't simply define LARGE_OFF_T to be 9223372036854775807,
      since some C++ compilers masquerading as C compilers
      incorrectly reject 9223372036854775807.  */
! #define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 
31))
    int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721
                       && LARGE_OFF_T % 2147483647 == 1)
                      ? 1 : -1];
--- 12795,12801 ----
      We can't simply define LARGE_OFF_T to be 9223372036854775807,
      since some C++ compilers masquerading as C compilers
      incorrectly reject 9223372036854775807.  */
! #define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62))
    int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721
                       && LARGE_OFF_T % 2147483647 == 1)
                      ? 1 : -1];
***************
*** 12852,12858 ****
      We can't simply define LARGE_OFF_T to be 9223372036854775807,
      since some C++ compilers masquerading as C compilers
      incorrectly reject 9223372036854775807.  */
! #define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 
31))
    int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721
                       && LARGE_OFF_T % 2147483647 == 1)
                      ? 1 : -1];
--- 12840,12846 ----
      We can't simply define LARGE_OFF_T to be 9223372036854775807,
      since some C++ compilers masquerading as C compilers
      incorrectly reject 9223372036854775807.  */
! #define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62))
    int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721
                       && LARGE_OFF_T % 2147483647 == 1)
                      ? 1 : -1];
***************
*** 12876,12882 ****
      We can't simply define LARGE_OFF_T to be 9223372036854775807,
      since some C++ compilers masquerading as C compilers
      incorrectly reject 9223372036854775807.  */
! #define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 
31))
    int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721
                       && LARGE_OFF_T % 2147483647 == 1)
                      ? 1 : -1];
--- 12864,12870 ----
      We can't simply define LARGE_OFF_T to be 9223372036854775807,
      since some C++ compilers masquerading as C compilers
      incorrectly reject 9223372036854775807.  */
! #define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62))
    int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721
                       && LARGE_OFF_T % 2147483647 == 1)
                      ? 1 : -1];
***************
*** 13080,13085 ****
--- 13068,13143 ----
  fi
  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_n "checking whether stat() ignores a trailing slash... " >&6; }
  if ${vim_cv_stat_ignores_slash+:} false; then :
*** ../vim-8.2.5056/src/config.h.in     2022-02-23 18:07:34.361914993 +0000
--- src/config.h.in     2022-06-05 16:55:18.730774478 +0100
***************
*** 231,236 ****
--- 231,237 ----
  #undef HAVE_UTIME
  #undef HAVE_BIND_TEXTDOMAIN_CODESET
  #undef HAVE_MBLEN
+ #undef HAVE_TIMER_CREATE
  
  /* Define, if needed, for accessing large files. */
  #undef _LARGE_FILES
*** ../vim-8.2.5056/src/configure.ac    2022-04-04 17:19:57.135569573 +0100
--- src/configure.ac    2022-06-05 16:48:36.646745138 +0100
***************
*** 1,7 ****
  dnl configure.ac: autoconf script for Vim
  
! dnl Process this file with autoconf 2.12 or 2.13 to produce "configure".
! dnl Should also work with autoconf 2.54 and later.
  
  AC_INIT(vim.h)
  AC_CONFIG_HEADER(auto/config.h:config.h.in)
--- 1,8 ----
  dnl configure.ac: autoconf script for Vim
  
! dnl Process this file with autoconf 2.69 to produce "configure".
! 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_CONFIG_HEADER(auto/config.h:config.h.in)
***************
*** 3812,3817 ****
--- 3813,3853 ----
        AC_MSG_RESULT(yes); AC_DEFINE(HAVE_ST_BLKSIZE),
        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_RUN_IFELSE([AC_LANG_SOURCE([[
*** ../vim-8.2.5056/src/drawscreen.c    2022-05-31 13:42:54.830788849 +0100
--- src/drawscreen.c    2022-06-05 13:46:55.624445077 +0100
***************
*** 1474,1482 ****
  #if defined(FEAT_SYN_HL) || defined(FEAT_SEARCH_EXTRA)
      int               save_got_int;
  #endif
- #ifdef SYN_TIME_LIMIT
-     proftime_T        syntax_tm;
- #endif
  
  #if defined(FEAT_SEARCH_EXTRA) || defined(FEAT_CLIPBOARD)
      // This needs to be done only for the first window when update_screen() is
--- 1474,1479 ----
***************
*** 2182,2189 ****
  #endif
  #ifdef SYN_TIME_LIMIT
      // Set the time limit to 'redrawtime'.
!     profile_setlimit(p_rdt, &syntax_tm);
!     syn_set_timeout(&syntax_tm);
  #endif
  #ifdef FEAT_FOLDING
      win_foldinfo.fi_level = 0;
--- 2179,2185 ----
  #endif
  #ifdef SYN_TIME_LIMIT
      // Set the time limit to 'redrawtime'.
!     init_regexp_timeout(p_rdt);
  #endif
  #ifdef FEAT_FOLDING
      win_foldinfo.fi_level = 0;
***************
*** 2695,2701 ****
      }
  
  #ifdef SYN_TIME_LIMIT
!     syn_set_timeout(NULL);
  #endif
  
      // Reset the type of redrawing required, the window has been updated.
--- 2691,2697 ----
      }
  
  #ifdef SYN_TIME_LIMIT
!     disable_regexp_timeout();
  #endif
  
      // Reset the type of redrawing required, the window has been updated.
*** ../vim-8.2.5056/src/errors.h        2022-05-29 17:13:15.779819248 +0100
--- src/errors.h        2022-06-05 14:10:19.863972241 +0100
***************
*** 3288,3290 ****
--- 3288,3302 ----
  EXTERN char e_argument_1_list_item_nr_dictionary_required[]
        INIT(= N_("E1284: Argument 1, list item %d: Dictionary required"));
  #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
*** ../vim-8.2.5056/src/evalfunc.c      2022-05-27 21:57:51.943739826 +0100
--- src/evalfunc.c      2022-06-05 13:46:55.624445077 +0100
***************
*** 8439,8445 ****
      int               retval = 0;     // default: FAIL
      long      lnum_stop = 0;
  #ifdef FEAT_RELTIME
-     proftime_T        tm;
      long      time_limit = 0;
  #endif
      int               options = SEARCH_KEEP;
--- 8439,8444 ----
***************
*** 8486,8496 ****
        }
      }
  
- #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.
       * Check to make sure only those flags are set.
--- 8485,8490 ----
***************
*** 8509,8515 ****
      CLEAR_FIELD(sia);
      sia.sa_stop_lnum = (linenr_T)lnum_stop;
  #ifdef FEAT_RELTIME
!     sia.sa_tm = &tm;
  #endif
  
      // Repeat until {skip} returns FALSE.
--- 8503,8509 ----
      CLEAR_FIELD(sia);
      sia.sa_stop_lnum = (linenr_T)lnum_stop;
  #ifdef FEAT_RELTIME
!     sia.sa_tm = time_limit;
  #endif
  
      // Repeat until {skip} returns FALSE.
***************
*** 8955,8973 ****
      int               use_skip = FALSE;
      int               err;
      int               options = SEARCH_KEEP;
- #ifdef FEAT_RELTIME
-     proftime_T        tm;
- #endif
  
      // Make 'cpoptions' empty, the 'l' flag should not be used here.
      save_cpo = p_cpo;
      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
      // start/middle/end (pat3, for the top pair).
      pat2 = alloc(STRLEN(spat) + STRLEN(epat) + 17);
--- 8949,8959 ----
***************
*** 8998,9004 ****
        CLEAR_FIELD(sia);
        sia.sa_stop_lnum = lnum_stop;
  #ifdef FEAT_RELTIME
!       sia.sa_tm = &tm;
  #endif
        n = searchit(curwin, curbuf, &pos, NULL, dir, pat, 1L,
                                                     options, RE_SEARCH, &sia);
--- 8984,8990 ----
        CLEAR_FIELD(sia);
        sia.sa_stop_lnum = lnum_stop;
  #ifdef FEAT_RELTIME
!       sia.sa_tm = time_limit;
  #endif
        n = searchit(curwin, curbuf, &pos, NULL, dir, pat, 1L,
                                                     options, RE_SEARCH, &sia);
*** ../vim-8.2.5056/src/ex_cmds.c       2022-05-30 20:58:48.914049575 +0100
--- src/ex_cmds.c       2022-06-05 13:46:55.624445077 +0100
***************
*** 4006,4012 ****
                ); ++lnum)
      {
        nmatch = vim_regexec_multi(&regmatch, curwin, curbuf, lnum,
!                                                      (colnr_T)0, NULL, NULL);
        if (nmatch)
        {
            colnr_T     copycol;
--- 4006,4012 ----
                ); ++lnum)
      {
        nmatch = vim_regexec_multi(&regmatch, curwin, curbuf, lnum,
!                                                      (colnr_T)0, NULL);
        if (nmatch)
        {
            colnr_T     copycol;
***************
*** 4663,4669 ****
                        || nmatch_tl > 0
                        || (nmatch = vim_regexec_multi(&regmatch, curwin,
                                                        curbuf, sub_firstlnum,
!                                                   matchcol, NULL, NULL)) == 0
                        || regmatch.startpos[0].lnum > 0)
                {
                    if (new_start != NULL)
--- 4663,4669 ----
                        || nmatch_tl > 0
                        || (nmatch = vim_regexec_multi(&regmatch, curwin,
                                                        curbuf, sub_firstlnum,
!                                                   matchcol, NULL)) == 0
                        || regmatch.startpos[0].lnum > 0)
                {
                    if (new_start != NULL)
***************
*** 4728,4734 ****
                    }
                    if (nmatch == -1 && !lastone)
                        nmatch = vim_regexec_multi(&regmatch, curwin, curbuf,
!                                         sub_firstlnum, matchcol, NULL, NULL);
  
                    /*
                     * 5. break if there isn't another match in this line
--- 4728,4734 ----
                    }
                    if (nmatch == -1 && !lastone)
                        nmatch = vim_regexec_multi(&regmatch, curwin, curbuf,
!                                         sub_firstlnum, matchcol, NULL);
  
                    /*
                     * 5. break if there isn't another match in this line
***************
*** 4992,4998 ****
      {
        lnum = curwin->w_cursor.lnum;
        match = vim_regexec_multi(&regmatch, curwin, curbuf, lnum,
!                                                      (colnr_T)0, NULL, NULL);
        if ((type == 'g' && match) || (type == 'v' && !match))
            global_exe_one(cmd, lnum);
      }
--- 4992,4998 ----
      {
        lnum = curwin->w_cursor.lnum;
        match = vim_regexec_multi(&regmatch, curwin, curbuf, lnum,
!                                                      (colnr_T)0, NULL);
        if ((type == 'g' && match) || (type == 'v' && !match))
            global_exe_one(cmd, lnum);
      }
***************
*** 5005,5011 ****
        {
            // a match on this line?
            match = vim_regexec_multi(&regmatch, curwin, curbuf, lnum,
!                                                      (colnr_T)0, NULL, NULL);
            if (regmatch.regprog == NULL)
                break;  // re-compiling regprog failed
            if ((type == 'g' && match) || (type == 'v' && !match))
--- 5005,5011 ----
        {
            // a match on this line?
            match = vim_regexec_multi(&regmatch, curwin, curbuf, lnum,
!                                                      (colnr_T)0, NULL);
            if (regmatch.regprog == NULL)
                break;  // re-compiling regprog failed
            if ((type == 'g' && match) || (type == 'v' && !match))
*** ../vim-8.2.5056/src/ex_getln.c      2022-05-30 16:01:38.999629604 +0100
--- src/ex_getln.c      2022-06-05 13:46:55.624445077 +0100
***************
*** 417,423 ****
      int               found;  // do_search() result
      pos_T     end_pos;
  #ifdef FEAT_RELTIME
-     proftime_T        tm;
      searchit_arg_T sia;
  #endif
      int               next_char;
--- 417,422 ----
***************
*** 484,493 ****
        cursor_off();   // so the user knows we're busy
        out_flush();
        ++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)
            search_flags += SEARCH_KEEP;
        if (search_first_line != 0)
--- 483,488 ----
***************
*** 495,501 ****
        ccline.cmdbuff[skiplen + patlen] = NUL;
  #ifdef FEAT_RELTIME
        CLEAR_FIELD(sia);
!       sia.sa_tm = &tm;
  #endif
        found = do_search(NULL, firstc == ':' ? '/' : firstc, search_delim,
                                 ccline.cmdbuff + skiplen, count, search_flags,
--- 490,497 ----
        ccline.cmdbuff[skiplen + patlen] = NUL;
  #ifdef FEAT_RELTIME
        CLEAR_FIELD(sia);
!       // Set the time limit to half a second.
!       sia.sa_tm = 500;
  #endif
        found = do_search(NULL, firstc == ':' ? '/' : firstc, search_delim,
                                 ccline.cmdbuff + skiplen, count, search_flags,
*** ../vim-8.2.5056/src/match.c 2022-05-31 13:42:54.830788849 +0100
--- src/match.c 2022-06-05 14:24:09.667674692 +0100
***************
*** 330,339 ****
        cur->hl.buf = wp->w_buffer;
        cur->hl.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;
      }
      search_hl->buf = wp->w_buffer;
--- 330,335 ----
***************
*** 424,429 ****
--- 420,426 ----
      colnr_T   matchcol;
      long      nmatched;
      int               called_emsg_before = called_emsg;
+     int         timed_out = FALSE;
  
      // for :{range}s/pat only highlight inside the range
      if ((lnum < search_first_line || lnum > search_last_line) && cur == NULL)
***************
*** 451,457 ****
      {
  # ifdef FEAT_RELTIME
        // Stop searching after passing the time limit.
!       if (profile_passed_limit(&(shl->tm)))
        {
            shl->lnum = 0;              // no match found in time
            break;
--- 448,454 ----
      {
  # ifdef FEAT_RELTIME
        // Stop searching after passing the time limit.
!       if (timed_out)
        {
            shl->lnum = 0;              // no match found in time
            break;
***************
*** 494,509 ****
            int regprog_is_copy = (shl != search_hl && cur != NULL
                                && shl == &cur->hl
                                && cur->match.regprog == cur->hl.rm.regprog);
-           int timed_out = FALSE;
  
            nmatched = vim_regexec_multi(&shl->rm, win, shl->buf, lnum,
!                   matchcol,
! #ifdef FEAT_RELTIME
!                   &(shl->tm), &timed_out
! #else
!                   NULL, NULL
! #endif
!                   );
            // Copy the regprog, in case it got freed and recompiled.
            if (regprog_is_copy)
                cur->match.regprog = cur->hl.rm.regprog;
--- 491,499 ----
            int regprog_is_copy = (shl != search_hl && cur != NULL
                                && shl == &cur->hl
                                && cur->match.regprog == cur->hl.rm.regprog);
  
            nmatched = vim_regexec_multi(&shl->rm, win, shl->buf, lnum,
!                                                        matchcol, &timed_out);
            // Copy the regprog, in case it got freed and recompiled.
            if (regprog_is_copy)
                cur->match.regprog = cur->hl.rm.regprog;
*** ../vim-8.2.5056/src/os_mac.h        2021-12-27 17:21:38.016449116 +0000
--- src/os_mac.h        2022-06-05 14:26:39.915661365 +0100
***************
*** 6,11 ****
--- 6,14 ----
   * 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,
  // let's set the OPAQUE_TOOLBOX_STRUCTS to 0 so we
  // can access the internal structures.
***************
*** 266,268 ****
--- 269,320 ----
  
  // A Mac constant causing big problem to syntax highlighting
  #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
*** ../vim-8.2.5056/src/os_macosx.m     2020-08-13 20:05:31.785361610 +0100
--- src/os_macosx.m     2022-06-05 13:46:55.624445077 +0100
***************
*** 23,28 ****
--- 23,35 ----
   * X11 header files. */
  #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"
  #import <AppKit/AppKit.h>
  
***************
*** 208,213 ****
--- 215,389 ----
  
  #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. */
  #if defined(__clang__) && defined(__STRICT_ANSI__)
  # pragma clang diagnostic pop
*** ../vim-8.2.5056/src/os_unix.c       2022-05-09 20:09:19.298641424 +0100
--- src/os_unix.c       2022-06-05 14:31:49.187705964 +0100
***************
*** 8256,8258 ****
--- 8256,8472 ----
      }
  }
  #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
*** ../vim-8.2.5056/src/os_win32.c      2022-05-12 20:35:32.327574779 +0100
--- src/os_win32.c      2022-06-05 14:31:32.163705399 +0100
***************
*** 100,105 ****
--- 100,107 ----
  typedef char * LPWSTR;
  typedef int ACCESS_MASK;
  typedef int BOOL;
+ typedef int BOOLEAN;
+ typedef int CALLBACK;
  typedef int COLORREF;
  typedef int CONSOLE_CURSOR_INFO;
  typedef int COORD;
***************
*** 7327,7332 ****
--- 7329,7335 ----
      ULONG EaSize;
  } FILE_EA_INFORMATION_, *PFILE_EA_INFORMATION_;
  
+ #ifndef PROTO
  typedef NTSTATUS (NTAPI *PfnNtOpenFile)(
        PHANDLE FileHandle,
        ACCESS_MASK DesiredAccess,
***************
*** 7367,7372 ****
--- 7370,7376 ----
  PfnNtQueryEaFile pNtQueryEaFile = NULL;
  PfnNtQueryInformationFile pNtQueryInformationFile = NULL;
  PfnRtlInitUnicodeString pRtlInitUnicodeString = NULL;
+ #endif
  
  /*
   * Load ntdll.dll functions.
***************
*** 8315,8317 ****
--- 8319,8403 ----
      }
      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
*** ../vim-8.2.5056/src/proto/os_unix.pro       2022-02-23 18:07:34.365914989 
+0000
--- src/proto/os_unix.pro       2022-06-05 14:31:56.243706148 +0100
***************
*** 72,77 ****
--- 72,78 ----
  int mch_has_exp_wildcard(char_u *p);
  int mch_has_wildcard(char_u *p);
  int mch_rename(const char *src, const char *dest);
+ int gpm_available(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);
  void setup_term_clip(void);
***************
*** 85,89 ****
  int xsmp_handle_requests(void);
  void xsmp_init(void);
  void xsmp_close(void);
! int gpm_available(void);
  /* vim: set ft=c : */
--- 86,91 ----
  int xsmp_handle_requests(void);
  void xsmp_init(void);
  void xsmp_close(void);
! void stop_timeout(void);
! const int *start_timeout(long msec);
  /* vim: set ft=c : */
*** ../vim-8.2.5056/src/proto/os_win32.pro      2022-02-12 11:18:32.318462415 
+0000
--- src/proto/os_win32.pro      2022-06-05 14:30:36.131702212 +0100
***************
*** 83,87 ****
  int is_conpty_stable(void);
  int get_conpty_fix_type(void);
  void resize_console_buf(void);
! char * GetWin32Error(void);
  /* vim: set ft=c : */
--- 83,89 ----
  int is_conpty_stable(void);
  int get_conpty_fix_type(void);
  void resize_console_buf(void);
! char *GetWin32Error(void);
! void stop_timeout(void);
! const int *start_timeout(long msec);
  /* vim: set ft=c : */
*** ../vim-8.2.5056/src/proto/regexp.pro        2022-05-30 20:58:48.914049575 
+0100
--- src/proto/regexp.pro        2022-06-05 14:22:48.399703980 +0100
***************
*** 1,4 ****
--- 1,6 ----
  /* regexp.c */
+ void init_regexp_timeout(long msec);
+ void disable_regexp_timeout(void);
  int re_multiline(regprog_T *prog);
  char_u *skip_regexp(char_u *startp, int delim, int magic);
  char_u *skip_regexp_err(char_u *startp, int delim, int magic);
***************
*** 18,22 ****
  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_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);
  /* vim: set ft=c : */
--- 20,24 ----
  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_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, int *timed_out);
  /* vim: set ft=c : */
*** ../vim-8.2.5056/src/quickfix.c      2022-05-15 13:59:08.704167482 +0100
--- src/quickfix.c      2022-06-05 13:46:55.628445075 +0100
***************
*** 5990,5996 ****
        {
            // Regular expression match
            while (vim_regexec_multi(regmatch, curwin, buf, lnum,
!                       col, NULL, NULL) > 0)
            {
                // Pass the buffer number so that it gets used even for a
                // dummy buffer, unless duplicate_name is set, then the
--- 5990,5996 ----
        {
            // Regular expression match
            while (vim_regexec_multi(regmatch, curwin, buf, lnum,
!                       col, NULL) > 0)
            {
                // Pass the buffer number so that it gets used even for a
                // dummy buffer, unless duplicate_name is set, then the
*** ../vim-8.2.5056/src/regexp.c        2022-05-30 20:58:48.914049575 +0100
--- src/regexp.c        2022-06-05 13:46:55.628445075 +0100
***************
*** 20,25 ****
--- 20,30 ----
  # define BT_REGEXP_DEBUG_LOG_NAME     "bt_regexp_debug.log"
  #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 are negative.  This separates them from literal characters
***************
*** 45,50 ****
--- 50,69 ----
      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
   * number; the start node begins in the second byte.  It's used to catch the
***************
*** 1944,1951 ****
  #ifdef FEAT_EVAL
        // To make sure that the length doesn't change between checking the
        // length and copying the string, and to speed up things, the
!       // resulting string is saved from the call with "flags & REGSUB_COPY"
!       // == 0 to the // call with "flags & REGSUB_COPY" != 0.
        if (copy)
        {
            if (eval_result != NULL)
--- 1963,1971 ----
  #ifdef FEAT_EVAL
        // To make sure that the length doesn't change between checking the
        // length and copying the string, and to speed up things, the
!       // resulting string is saved from the call with
!       // "flags & REGSUB_COPY" == 0 to the call with
!       // "flags & REGSUB_COPY" != 0.
        if (copy)
        {
            if (eval_result != NULL)
***************
*** 1960,1966 ****
            int             prev_can_f_submatch = can_f_submatch;
            regsubmatch_T   rsm_save;
  
!           vim_free(eval_result);
  
            // The expression may contain substitute(), which calls us
            // recursively.  Make sure submatch() gets the text from the first
--- 1980,1986 ----
            int             prev_can_f_submatch = can_f_submatch;
            regsubmatch_T   rsm_save;
  
!           VIM_CLEAR(eval_result);
  
            // The expression may contain substitute(), which calls us
            // recursively.  Make sure submatch() gets the text from the first
***************
*** 2905,2911 ****
      buf_T       *buf,         // buffer in which to search
      linenr_T  lnum,           // nr of line 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               result;
--- 2925,2930 ----
***************
*** 2926,2932 ****
      rex_in_use = TRUE;
  
      result = rmp->regprog->engine->regexec_multi(
!                                     rmp, win, buf, lnum, col, tm, timed_out);
      rmp->regprog->re_in_use = FALSE;
  
      // NFA engine aborted because it's very slow.
--- 2945,2951 ----
      rex_in_use = TRUE;
  
      result = rmp->regprog->engine->regexec_multi(
!                                     rmp, win, buf, lnum, col, timed_out);
      rmp->regprog->re_in_use = FALSE;
  
      // NFA engine aborted because it's very slow.
***************
*** 2966,2972 ****
  
                rmp->regprog->re_in_use = TRUE;
                result = rmp->regprog->engine->regexec_multi(
!                                     rmp, win, buf, lnum, col, tm, timed_out);
                rmp->regprog->re_in_use = FALSE;
            }
            vim_free(pat);
--- 2985,2991 ----
  
                rmp->regprog->re_in_use = TRUE;
                result = rmp->regprog->engine->regexec_multi(
!                                     rmp, win, buf, lnum, col, timed_out);
                rmp->regprog->re_in_use = FALSE;
            }
            vim_free(pat);
*** ../vim-8.2.5056/src/regexp.h        2022-05-30 20:58:48.910049580 +0100
--- src/regexp.h        2022-06-05 13:46:55.628445075 +0100
***************
*** 173,179 ****
      // bt_regexec_nl or nfa_regexec_nl
      int               (*regexec_nl)(regmatch_T *, char_u *, colnr_T, int);
      // bt_regexec_mult or nfa_regexec_mult
!     long      (*regexec_multi)(regmmatch_T *, win_T *, buf_T *, linenr_T, 
colnr_T, proftime_T *, int *);
      //char_u  *expr;
  };
  
--- 173,179 ----
      // bt_regexec_nl or nfa_regexec_nl
      int               (*regexec_nl)(regmatch_T *, char_u *, colnr_T, int);
      // bt_regexec_mult or nfa_regexec_mult
!     long      (*regexec_multi)(regmmatch_T *, win_T *, buf_T *, linenr_T, 
colnr_T, int *);
      //char_u  *expr;
  };
  
*** ../vim-8.2.5056/src/regexp_bt.c     2022-05-27 15:35:23.846892913 +0100
--- src/regexp_bt.c     2022-06-05 13:46:55.628445075 +0100
***************
*** 3228,3234 ****
      static int
  regmatch(
      char_u    *scan,              // Current node.
-     proftime_T        *tm UNUSED,         // timeout limit or NULL
      int               *timed_out UNUSED)  // flag set on timeout or NULL
  {
    char_u      *next;          // Next node.
--- 3228,3233 ----
***************
*** 3237,3245 ****
    regitem_T   *rp;
    int         no;
    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
    // bt_regexec_both() to reduce malloc()/free() calls.
--- 3236,3241 ----
***************
*** 3271,3289 ****
            break;
        }
  #ifdef FEAT_RELTIME
!       // Check for timeout once in 250 times to avoid excessive overhead from
!       // 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 (profile_passed_limit(tm))
!           {
!               if (timed_out != NULL)
!                   *timed_out = TRUE;
!               status = RA_FAIL;
!               break;
!           }
        }
  #endif
        status = RA_CONT;
--- 3267,3278 ----
            break;
        }
  #ifdef FEAT_RELTIME
!       if (*timeout_flag)
        {
!           if (timed_out != NULL)
!               *timed_out = TRUE;
!           status = RA_FAIL;
!           break;
        }
  #endif
        status = RA_CONT;
***************
*** 3315,3321 ****
        op = OP(scan);
        // Check for character class with NL added.
        if (!rex.reg_line_lbr && WITH_NL(op) && REG_MULTI
!                          && *rex.input == NUL && rex.lnum <= rex.reg_maxline)
        {
            reg_nextline();
        }
--- 3304,3310 ----
        op = OP(scan);
        // Check for character class with NL added.
        if (!rex.reg_line_lbr && WITH_NL(op) && REG_MULTI
!                            && *rex.input == NUL && rex.lnum <= 
rex.reg_maxline)
        {
            reg_nextline();
        }
***************
*** 4732,4738 ****
  regtry(
      bt_regprog_T      *prog,
      colnr_T           col,
-     proftime_T                *tm,            // timeout limit or NULL
      int                       *timed_out)     // flag set on timeout or NULL
  {
      rex.input = rex.line + col;
--- 4721,4726 ----
***************
*** 4742,4748 ****
      rex.need_clear_zsubexpr = (prog->reghasz == REX_SET);
  #endif
  
!     if (regmatch(prog->program + 1, tm, timed_out) == 0)
        return 0;
  
      cleanup_subexpr();
--- 4730,4736 ----
      rex.need_clear_zsubexpr = (prog->reghasz == REX_SET);
  #endif
  
!     if (regmatch(prog->program + 1, timed_out) == 0)
        return 0;
  
      cleanup_subexpr();
***************
*** 4817,4823 ****
  bt_regexec_both(
      char_u    *line,
      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
  {
      bt_regprog_T    *prog;
--- 4805,4810 ----
***************
*** 4940,4954 ****
                    && (((enc_utf8 && utf_fold(prog->regstart) == utf_fold(c)))
                        || (c < 255 && prog->regstart < 255 &&
                            MB_TOLOWER(prog->regstart) == MB_TOLOWER(c)))))
!           retval = regtry(prog, col, tm, timed_out);
        else
            retval = 0;
      }
      else
      {
- #ifdef FEAT_RELTIME
-       int tm_count = 0;
- #endif
        // Messy cases:  unanchored match.
        while (!got_int)
        {
--- 4927,4938 ----
                    && (((enc_utf8 && utf_fold(prog->regstart) == utf_fold(c)))
                        || (c < 255 && prog->regstart < 255 &&
                            MB_TOLOWER(prog->regstart) == MB_TOLOWER(c)))))
!           retval = regtry(prog, col, timed_out);
        else
            retval = 0;
      }
      else
      {
        // Messy cases:  unanchored match.
        while (!got_int)
        {
***************
*** 4975,4981 ****
                break;
            }
  
!           retval = regtry(prog, col, tm, timed_out);
            if (retval > 0)
                break;
  
--- 4959,4965 ----
                break;
            }
  
!           retval = regtry(prog, col, timed_out);
            if (retval > 0)
                break;
  
***************
*** 4992,5009 ****
            else
                ++col;
  #ifdef FEAT_RELTIME
!           // Check for timeout once in 500 times to avoid excessive overhead
!           // 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 (profile_passed_limit(tm))
!               {
!                   if (timed_out != NULL)
!                       *timed_out = TRUE;
!                   break;
!               }
            }
  #endif
        }
--- 4976,4986 ----
            else
                ++col;
  #ifdef FEAT_RELTIME
!           if (*timeout_flag)
            {
!               if (timed_out != NULL)
!                   *timed_out = TRUE;
!               break;
            }
  #endif
        }
***************
*** 5067,5073 ****
      rex.reg_icombine = FALSE;
      rex.reg_maxcol = 0;
  
!     return bt_regexec_both(line, col, NULL, NULL);
  }
  
  /*
--- 5044,5050 ----
      rex.reg_icombine = FALSE;
      rex.reg_maxcol = 0;
  
!     return bt_regexec_both(line, col, NULL);
  }
  
  /*
***************
*** 5085,5095 ****
      buf_T     *buf,           // buffer in which to search
      linenr_T  lnum,           // nr of line 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
  {
      init_regexec_multi(rmp, win, buf, lnum);
!     return bt_regexec_both(NULL, col, tm, timed_out);
  }
  
  /*
--- 5062,5071 ----
      buf_T     *buf,           // buffer in which to search
      linenr_T  lnum,           // nr of line to start looking for match
      colnr_T   col,            // column to start looking for match
      int               *timed_out)     // flag set on timeout or NULL
  {
      init_regexec_multi(rmp, win, buf, lnum);
!     return bt_regexec_both(NULL, col, timed_out);
  }
  
  /*
*** ../vim-8.2.5056/src/regexp_nfa.c    2022-05-28 11:08:36.341330145 +0100
--- src/regexp_nfa.c    2022-06-05 13:46:55.628445075 +0100
***************
*** 4051,4057 ****
  // Used during execution: whether a match has been found.
  static int        nfa_match;
  #ifdef FEAT_RELTIME
- static proftime_T  *nfa_time_limit;
  static int       *nfa_timed_out;
  #endif
  
--- 4051,4056 ----
***************
*** 5650,5678 ****
   * To reduce overhead, only check one in "count" times.
   */
      static int
! nfa_did_time_out(int count)
  {
!     static int tm_count = 0;
! 
!     // 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 (profile_passed_limit(nfa_time_limit))
!           {
!               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;
  }
--- 5649,5661 ----
   * To reduce overhead, only check one in "count" times.
   */
      static int
! nfa_did_time_out(void)
  {
!     if (*timeout_flag)
      {
!       if (nfa_timed_out != NULL)
!           *nfa_timed_out = TRUE;
!       return TRUE;
      }
      return FALSE;
  }
***************
*** 5726,5732 ****
        return FALSE;
  #ifdef FEAT_RELTIME
      // Check relatively often here, since this is the toplevel matching.
!     if (nfa_did_time_out(100))
        return FALSE;
  #endif
  
--- 5709,5715 ----
        return FALSE;
  #ifdef FEAT_RELTIME
      // Check relatively often here, since this is the toplevel matching.
!     if (nfa_did_time_out())
        return FALSE;
  #endif
  
***************
*** 5880,5887 ****
            if (got_int)
                break;
  #ifdef FEAT_RELTIME
!           // do not check very often here, since this is a loop in a loop
!           if (nfa_did_time_out(2000))
                break;
  #endif
            t = &thislist->t[listidx];
--- 5863,5869 ----
            if (got_int)
                break;
  #ifdef FEAT_RELTIME
!           if (nfa_did_time_out())
                break;
  #endif
            t = &thislist->t[listidx];
***************
*** 7127,7134 ****
        if (got_int)
            break;
  #ifdef FEAT_RELTIME
!       // check regularly but not too often here
!       if (nfa_did_time_out(800))
            break;
  #endif
      }
--- 7109,7116 ----
        if (got_int)
            break;
  #ifdef FEAT_RELTIME
!       // Check for timeout once in a twenty times to avoid overhead.
!       if (nfa_did_time_out())
            break;
  #endif
      }
***************
*** 7160,7166 ****
  nfa_regtry(
      nfa_regprog_T   *prog,
      colnr_T       col,
-     proftime_T            *tm UNUSED, // timeout limit or NULL
      int                   *timed_out UNUSED)  // flag set on timeout or NULL
  {
      int               i;
--- 7142,7147 ----
***************
*** 7173,7179 ****
  
      rex.input = rex.line + col;
  #ifdef FEAT_RELTIME
-     nfa_time_limit = tm;
      nfa_timed_out = timed_out;
  #endif
  
--- 7154,7159 ----
***************
*** 7301,7307 ****
  nfa_regexec_both(
      char_u    *line,
      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
  {
      nfa_regprog_T   *prog;
--- 7281,7286 ----
***************
*** 7397,7403 ****
        prog->state[i].lastlist[1] = 0;
      }
  
!     retval = nfa_regtry(prog, col, tm, timed_out);
  
  #ifdef DEBUG
      nfa_regengine.expr = NULL;
--- 7376,7382 ----
        prog->state[i].lastlist[1] = 0;
      }
  
!     retval = nfa_regtry(prog, col, timed_out);
  
  #ifdef DEBUG
      nfa_regengine.expr = NULL;
***************
*** 7577,7583 ****
      rex.reg_ic = rmp->rm_ic;
      rex.reg_icombine = FALSE;
      rex.reg_maxcol = 0;
!     return nfa_regexec_both(line, col, NULL, NULL);
  }
  
  
--- 7556,7562 ----
      rex.reg_ic = rmp->rm_ic;
      rex.reg_icombine = FALSE;
      rex.reg_maxcol = 0;
!     return nfa_regexec_both(line, col, NULL);
  }
  
  
***************
*** 7613,7623 ****
      buf_T     *buf,           // buffer in which to search
      linenr_T  lnum,           // nr of line 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
  {
      init_regexec_multi(rmp, win, buf, lnum);
!     return nfa_regexec_both(NULL, col, tm, timed_out);
  }
  
  #ifdef DEBUG
--- 7592,7601 ----
      buf_T     *buf,           // buffer in which to search
      linenr_T  lnum,           // nr of line to start looking for match
      colnr_T   col,            // column to start looking for match
      int               *timed_out)     // flag set on timeout or NULL
  {
      init_regexec_multi(rmp, win, buf, lnum);
!     return nfa_regexec_both(NULL, col, timed_out);
  }
  
  #ifdef DEBUG
*** ../vim-8.2.5056/src/screen.c        2022-05-07 20:01:10.066731684 +0100
--- src/screen.c        2022-06-05 13:46:55.628445075 +0100
***************
*** 1760,1769 ****
        end_search_hl();  // just in case it wasn't called before
        last_pat_prog(&screen_search_hl.rm);
        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
      }
  }
  
--- 1760,1765 ----
***************
*** 5029,5032 ****
  
      return NULL;      // no error
  }
- 
--- 5025,5027 ----
*** ../vim-8.2.5056/src/search.c        2022-06-01 15:23:07.826491258 +0100
--- src/search.c        2022-06-05 13:46:55.628445075 +0100
***************
*** 658,676 ****
      int               break_loop = FALSE;
  #endif
      linenr_T  stop_lnum = 0;  // stop after this line number when != 0
! #ifdef FEAT_RELTIME
!     proftime_T        *tm = NULL;     // timeout limit or NULL
!     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,
                   (options & (SEARCH_HIS + SEARCH_KEEP)), &regmatch) == FAIL)
--- 658,665 ----
      int               break_loop = FALSE;
  #endif
      linenr_T  stop_lnum = 0;  // stop after this line number when != 0
!     int               unused_timeout_flag = FALSE;
!     int               *timed_out = &unused_timeout_flag;  // set when timed 
out.
  
      if (search_regcomp(pat, RE_SEARCH, pat_use,
                   (options & (SEARCH_HIS + SEARCH_KEEP)), &regmatch) == FAIL)
***************
*** 680,685 ****
--- 669,686 ----
        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
       */
***************
*** 753,763 ****
                if (stop_lnum != 0 && (dir == FORWARD
                                       ? lnum > stop_lnum : lnum < stop_lnum))
                    break;
! #ifdef FEAT_RELTIME
!               // Stop after passing the "tm" time limit.
!               if (tm != NULL && profile_passed_limit(tm))
                    break;
- #endif
  
                /*
                 * Look for a match somewhere in line "lnum".
--- 754,762 ----
                if (stop_lnum != 0 && (dir == FORWARD
                                       ? lnum > stop_lnum : lnum < stop_lnum))
                    break;
!               // Stop after passing the time limit.
!               if (*timed_out)
                    break;
  
                /*
                 * Look for a match somewhere in line "lnum".
***************
*** 765,786 ****
                col = at_first_line && (options & SEARCH_COL) ? pos->col
                                                                 : (colnr_T)0;
                nmatched = vim_regexec_multi(&regmatch, win, buf,
!                                            lnum, col,
! #ifdef FEAT_RELTIME
!                                            tm, timed_out
! #else
!                                            NULL, NULL
! #endif
!                                                     );
                // vim_regexec_multi() may clear "regprog"
                if (regmatch.regprog == NULL)
                    break;
                // Abort searching on an error (e.g., out of stack).
!               if (called_emsg > called_emsg_before
! #ifdef FEAT_RELTIME
!                       || (timed_out != NULL && *timed_out)
! #endif
!                       )
                    break;
                if (nmatched > 0)
                {
--- 764,775 ----
                col = at_first_line && (options & SEARCH_COL) ? pos->col
                                                                 : (colnr_T)0;
                nmatched = vim_regexec_multi(&regmatch, win, buf,
!                                            lnum, col, timed_out);
                // vim_regexec_multi() may clear "regprog"
                if (regmatch.regprog == NULL)
                    break;
                // Abort searching on an error (e.g., out of stack).
!               if (called_emsg > called_emsg_before || *timed_out)
                    break;
                if (nmatched > 0)
                {
***************
*** 863,875 ****
                            if (ptr[matchcol] == NUL
                                    || (nmatched = vim_regexec_multi(&regmatch,
                                              win, buf, lnum + matchpos.lnum,
!                                             matchcol,
! #ifdef FEAT_RELTIME
!                                             tm, timed_out
! #else
!                                             NULL, NULL
! #endif
!                                             )) == 0)
                            {
                                match_ok = FALSE;
                                break;
--- 852,858 ----
                            if (ptr[matchcol] == NUL
                                    || (nmatched = vim_regexec_multi(&regmatch,
                                              win, buf, lnum + matchpos.lnum,
!                                             matchcol, timed_out)) == 0)
                            {
                                match_ok = FALSE;
                                break;
***************
*** 974,994 ****
                            if (ptr[matchcol] == NUL
                                    || (nmatched = vim_regexec_multi(&regmatch,
                                              win, buf, lnum + matchpos.lnum,
!                                             matchcol,
! #ifdef FEAT_RELTIME
!                                             tm, timed_out
! #else
!                                             NULL, NULL
! #endif
!                                           )) == 0)
                            {
- #ifdef FEAT_RELTIME
                                // If the search timed out, we did find a match
                                // but it might be the wrong one, so that's not
                                // OK.
!                               if (timed_out != NULL && *timed_out)
                                    match_ok = FALSE;
- #endif
                                break;
                            }
                            // vim_regexec_multi() may clear "regprog"
--- 957,969 ----
                            if (ptr[matchcol] == NUL
                                    || (nmatched = vim_regexec_multi(&regmatch,
                                              win, buf, lnum + matchpos.lnum,
!                                             matchcol, timed_out)) == 0)
                            {
                                // If the search timed out, we did find a match
                                // but it might be the wrong one, so that's not
                                // OK.
!                               if (*timed_out)
                                    match_ok = FALSE;
                                break;
                            }
                            // vim_regexec_multi() may clear "regprog"
***************
*** 1097,1106 ****
             * twice.
             */
            if (!p_ws || stop_lnum != 0 || got_int
!                                           || called_emsg > called_emsg_before
! #ifdef FEAT_RELTIME
!                               || (timed_out != NULL && *timed_out)
! #endif
  #ifdef FEAT_SEARCH_EXTRA
                                || break_loop
  #endif
--- 1072,1078 ----
             * twice.
             */
            if (!p_ws || stop_lnum != 0 || got_int
!                               || called_emsg > called_emsg_before || 
*timed_out
  #ifdef FEAT_SEARCH_EXTRA
                                || break_loop
  #endif
***************
*** 1124,1133 ****
            if (extra_arg != NULL)
                extra_arg->sa_wrapped = TRUE;
        }
!       if (got_int || called_emsg > called_emsg_before
! #ifdef FEAT_RELTIME
!               || (timed_out != NULL && *timed_out)
! #endif
  #ifdef FEAT_SEARCH_EXTRA
                || break_loop
  #endif
--- 1096,1102 ----
            if (extra_arg != NULL)
                extra_arg->sa_wrapped = TRUE;
        }
!       if (got_int || called_emsg > called_emsg_before || *timed_out
  #ifdef FEAT_SEARCH_EXTRA
                || break_loop
  #endif
***************
*** 1136,1141 ****
--- 1105,1113 ----
      }
      while (--count > 0 && found);   // stop after count matches or no match
  
+ #   ifdef FEAT_RELTIME
+     disable_regexp_timeout();
+ #   endif
      vim_regfree(regmatch.regprog);
  
      if (!found)                   // did not find it
***************
*** 2915,2921 ****
        {
            regmatch.startpos[0].col++;
            nmatched = vim_regexec_multi(&regmatch, curwin, curbuf,
!                              pos.lnum, regmatch.startpos[0].col, NULL, NULL);
            if (nmatched != 0)
                break;
        } while (regmatch.regprog != NULL
--- 2887,2893 ----
        {
            regmatch.startpos[0].col++;
            nmatched = vim_regexec_multi(&regmatch, curwin, curbuf,
!                              pos.lnum, regmatch.startpos[0].col, NULL);
            if (nmatched != 0)
                break;
        } while (regmatch.regprog != NULL
*** ../vim-8.2.5056/src/structs.h       2022-05-22 19:13:45.496327034 +0100
--- src/structs.h       2022-06-05 13:46:55.628445075 +0100
***************
*** 3329,3337 ****
                            // matchaddpos(). TRUE/FALSE
      char      has_cursor; // TRUE if the cursor is inside the match, used for
                            // CurSearch
- #ifdef FEAT_RELTIME
-     proftime_T        tm;         // for a time limit
- #endif
  } match_T;
  
  // number of positions supported by matchaddpos()
--- 3329,3334 ----
***************
*** 4419,4425 ****
  {
      linenr_T  sa_stop_lnum;   // stop after this line number when != 0
  #ifdef FEAT_RELTIME
!     proftime_T        *sa_tm;         // timeout limit or NULL
      int               sa_timed_out;   // set when timed out
  #endif
      int               sa_wrapped;     // search wrapped around
--- 4416,4422 ----
  {
      linenr_T  sa_stop_lnum;   // stop after this line number when != 0
  #ifdef FEAT_RELTIME
!     long      sa_tm;          // timeout limit or zero
      int               sa_timed_out;   // set when timed out
  #endif
      int               sa_wrapped;     // search wrapped around
*** ../vim-8.2.5056/src/syntax.c        2022-04-16 16:49:20.370662695 +0100
--- src/syntax.c        2022-06-05 13:46:55.628445075 +0100
***************
*** 266,274 ****
  static win_T  *syn_win;               // current window for highlighting
  static buf_T  *syn_buf;               // 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 colnr_T        current_col = 0;        // column of current state
  static int    current_state_stored = 0; // TRUE if stored current state
--- 266,271 ----
***************
*** 350,367 ****
  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);
  
- #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
   * from the screen updating, once for each displayed line.
--- 347,352 ----
***************
*** 3166,3174 ****
      syn_time_T  *st UNUSED)
  {
      int r;
- #ifdef FEAT_RELTIME
      int timed_out = FALSE;
- #endif
  #ifdef FEAT_PROFILE
      proftime_T        pt;
  
--- 3151,3157 ----
***************
*** 3183,3195 ****
        return FALSE;
  
      rmp->rmm_maxcol = syn_buf->b_p_smc;
!     r = vim_regexec_multi(rmp, syn_win, syn_buf, lnum, col,
! #ifdef FEAT_RELTIME
!           syn_tm, &timed_out
! #else
!           NULL, NULL
! #endif
!           );
  
  #ifdef FEAT_PROFILE
      if (syn_time_on)
--- 3166,3172 ----
        return FALSE;
  
      rmp->rmm_maxcol = syn_buf->b_p_smc;
!     r = vim_regexec_multi(rmp, syn_win, syn_buf, lnum, col, &timed_out);
  
  #ifdef FEAT_PROFILE
      if (syn_time_on)
*** ../vim-8.2.5056/src/testdir/test_hlsearch.vim       2020-09-04 
20:18:40.484161926 +0100
--- src/testdir/test_hlsearch.vim       2022-06-05 13:46:55.628445075 +0100
***************
*** 37,42 ****
--- 37,51 ----
  func Test_hlsearch_hangs()
    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.
    new
    call setline(1, ['aaa', repeat('abc ', 1000), 'ccc'])
***************
*** 45,51 ****
    let @/ = '\%#=1a*.*X\@<=b*'
    redraw
    let elapsed = reltimefloat(reltime(start))
!   call assert_true(elapsed > 0.1)
    call assert_true(elapsed < 1.0)
    set nohlsearch redrawtime&
    bwipe!
--- 54,60 ----
    let @/ = '\%#=1a*.*X\@<=b*'
    redraw
    let elapsed = reltimefloat(reltime(start))
!   call assert_true(elapsed > min_timeout)
    call assert_true(elapsed < 1.0)
    set nohlsearch redrawtime&
    bwipe!
*** ../vim-8.2.5056/src/testdir/test_search.vim 2022-05-31 13:42:54.834788844 
+0100
--- src/testdir/test_search.vim 2022-06-05 13:46:55.628445075 +0100
***************
*** 1550,1555 ****
--- 1550,1581 ----
    bwipe!
  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()
    new
    call setline(1, ['foo', 'bar', 'foobar'])
*** ../vim-8.2.5056/src/testdir/test_syntax.vim 2022-04-16 16:49:20.370662695 
+0100
--- src/testdir/test_syntax.vim 2022-06-05 13:46:55.632445073 +0100
***************
*** 527,532 ****
--- 527,541 ----
    CheckFunction reltimefloat
    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.
    new
    call setline(1, ['aaa', repeat('abc ', 1000), 'ccc'])
***************
*** 535,541 ****
    syn match Error /\%#=1a*.*X\@<=b*/
    redraw
    let elapsed = reltimefloat(reltime(start))
!   call assert_true(elapsed > 0.1)
    call assert_true(elapsed < 1.0)
  
    " second time syntax HL is disabled
--- 544,550 ----
    syn match Error /\%#=1a*.*X\@<=b*/
    redraw
    let elapsed = reltimefloat(reltime(start))
!   call assert_true(elapsed > min_timeout)
    call assert_true(elapsed < 1.0)
  
    " second time syntax HL is disabled
***************
*** 549,555 ****
    exe "normal \<C-L>"
    redraw
    let elapsed = reltimefloat(reltime(start))
!   call assert_true(elapsed > 0.1)
    call assert_true(elapsed < 1.0)
  
    set redrawtime&
--- 558,564 ----
    exe "normal \<C-L>"
    redraw
    let elapsed = reltimefloat(reltime(start))
!   call assert_true(elapsed > min_timeout)
    call assert_true(elapsed < 1.0)
  
    set redrawtime&
***************
*** 642,648 ****
        \ "\tNote: asdf",
        \ '}',
        \ ], 'Xtest.c')
!  
    " This makes the default for 'background' use "dark", check that the
    " response to t_RB corrects it to "light".
    let $COLORFGBG = '15;0'
--- 651,657 ----
        \ "\tNote: asdf",
        \ '}',
        \ ], 'Xtest.c')
! 
    " This makes the default for 'background' use "dark", check that the
    " response to t_RB corrects it to "light".
    let $COLORFGBG = '15;0'
*** ../vim-8.2.5056/src/version.c       2022-06-04 22:15:48.792982835 +0100
--- src/version.c       2022-06-05 14:38:52.279675769 +0100
***************
*** 736,737 ****
--- 736,739 ----
  {   /* Add new patch number below this line */
+ /**/
+     5057,
  /**/

-- 
FATHER:    You only killed the bride's father - that's all -
LAUNCELOT: Oh dear, I didn't really mean to...
FATHER:    Didn't mean to?  You put your sword right through his head!
LAUNCELOT: Gosh - Is he all right?
                 "Monty Python and the Holy Grail" PYTHON (MONTY) PICTURES LTD

 /// Bram Moolenaar -- [email protected] -- http://www.Moolenaar.net   \\\
///                                                                      \\\
\\\        sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ ///
 \\\            help me help AIDS victims -- http://ICCF-Holland.org    ///

-- 
-- 
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php

--- 
You received this message because you are subscribed to the Google Groups 
"vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/vim_dev/20220605155624.8D9601C291C%40moolenaar.net.

Raspunde prin e-mail lui