changeset 10066:dc1610dc910f v7.4.2304

commit https://github.com/vim/vim/commit/417ccd7138d4d230d328de8b0d3892dd82ff1bee Author: Bram Moolenaar <Bram@vim.org> Date: Thu Sep 1 21:26:20 2016 +0200 patch 7.4.2304 Problem: In a timer callback the timer itself can't be found or stopped. (Thinca) Solution: Do not remove the timer from the list, remember whether it was freed.
author Christian Brabandt <cb@256bit.org>
date Thu, 01 Sep 2016 21:30:05 +0200
parents e22dde82d394
children 4d790349eb7d
files src/ex_cmds2.c src/testdir/test_timers.vim src/version.c
diffstat 3 files changed, 35 insertions(+), 5 deletions(-) [+]
line wrap: on
line diff
--- a/src/ex_cmds2.c
+++ b/src/ex_cmds2.c
@@ -1090,6 +1090,9 @@ profile_zero(proftime_T *tm)
 static timer_T	*first_timer = NULL;
 static int	last_timer_id = 0;
 
+static timer_T	*current_timer = NULL;
+static int	free_current_timer = FALSE;
+
 /*
  * Insert a timer in the list of timers.
  */
@@ -1121,8 +1124,13 @@ remove_timer(timer_T *timer)
     static void
 free_timer(timer_T *timer)
 {
-    free_callback(timer->tr_callback, timer->tr_partial);
-    vim_free(timer);
+    if (timer == current_timer)
+	free_current_timer = TRUE;
+    else
+    {
+	free_callback(timer->tr_callback, timer->tr_partial);
+	vim_free(timer);
+    }
 }
 
 /*
@@ -1200,18 +1208,23 @@ check_due_timer(void)
 # endif
 	    if (this_due <= 1)
 	    {
-		remove_timer(timer);
+		current_timer = timer;
+		free_current_timer = FALSE;
 		timer_callback(timer);
+		current_timer = NULL;
+
 		did_one = TRUE;
-		if (timer->tr_repeat != 0)
+		if (timer->tr_repeat != 0 && !free_current_timer)
 		{
 		    profile_setlimit(timer->tr_interval, &timer->tr_due);
 		    if (timer->tr_repeat > 0)
 			--timer->tr_repeat;
-		    insert_timer(timer);
 		}
 		else
+		{
 		    free_timer(timer);
+		    remove_timer(timer);
+		}
 		/* the callback may do anything, start all over */
 		break;
 	    }
--- a/src/testdir/test_timers.vim
+++ b/src/testdir/test_timers.vim
@@ -128,4 +128,19 @@ func Test_paused()
   endif
 endfunc
 
+func StopMyself(timer)
+  let g:called += 1
+  if g:called == 2
+    call timer_stop(a:timer)
+  endif
+endfunc
+
+func Test_delete_myself()
+  let g:called = 0
+  let t = timer_start(10, 'StopMyself', {'repeat': -1})
+  call WaitFor('g:called == 2')
+  call assert_equal(2, g:called)
+  call assert_equal([], timer_info(t))
+endfunc
+
 " vim: shiftwidth=2 sts=2 expandtab
--- a/src/version.c
+++ b/src/version.c
@@ -764,6 +764,8 @@ static char *(features[]) =
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    2304,
+/**/
     2303,
 /**/
     2302,