patch 8.0.0702: an error in a timer can make Vim unusable

Problem:    An error in a timer can make Vim unusable.
Solution:   Don't set the error flag or exception from a timer.  Stop a timer
            if it causes an error 3 out of 3 times.  Discard an exception
            caused inside a timer.
diff --git a/src/ex_cmds2.c b/src/ex_cmds2.c
index 3efa8ca..76e62f7 100644
--- a/src/ex_cmds2.c
+++ b/src/ex_cmds2.c
@@ -1197,11 +1197,13 @@
     long	current_id = last_timer_id;
 # ifdef WIN3264
     LARGE_INTEGER   fr;
+# endif
 
-    /* Don't run any timers while exiting. */
-    if (exiting)
+    /* Don't run any timers while exiting or dealing with an error. */
+    if (exiting || aborting())
 	return next_due;
 
+# ifdef WIN3264
     QueryPerformanceFrequency(&fr);
 # endif
     profile_start(&now);
@@ -1216,9 +1218,13 @@
 	{
 	    int save_timer_busy = timer_busy;
 	    int save_vgetc_busy = vgetc_busy;
+	    int did_emsg_save = did_emsg;
+	    int called_emsg_save = called_emsg;
+	    int did_throw_save = did_throw;
 
 	    timer_busy = timer_busy > 0 || vgetc_busy > 0;
 	    vgetc_busy = 0;
+	    called_emsg = FALSE;
 	    timer->tr_firing = TRUE;
 	    timer_callback(timer);
 	    timer->tr_firing = FALSE;
@@ -1226,10 +1232,19 @@
 	    did_one = TRUE;
 	    timer_busy = save_timer_busy;
 	    vgetc_busy = save_vgetc_busy;
+	    if (called_emsg)
+	    {
+		++timer->tr_emsg_count;
+		if (!did_throw_save && current_exception != NULL)
+		    discard_current_exception();
+	    }
+	    did_emsg = did_emsg_save;
+	    called_emsg = called_emsg_save;
 
 	    /* Only fire the timer again if it repeats and stop_timer() wasn't
 	     * called while inside the callback (tr_id == -1). */
-	    if (timer->tr_repeat != 0 && timer->tr_id != -1)
+	    if (timer->tr_repeat != 0 && timer->tr_id != -1
+		    && timer->tr_emsg_count < 3)
 	    {
 		profile_setlimit(timer->tr_interval, &timer->tr_due);
 		this_due = GET_TIMEDIFF(timer, now);
diff --git a/src/structs.h b/src/structs.h
index 0fbc5a5..c3f1200 100644
--- a/src/structs.h
+++ b/src/structs.h
@@ -3243,6 +3243,7 @@
     long	tr_interval;	    /* msec */
     char_u	*tr_callback;	    /* allocated */
     partial_T	*tr_partial;
+    int		tr_emsg_count;
 #endif
 };
 
diff --git a/src/testdir/test_timers.vim b/src/testdir/test_timers.vim
index fdb74e7..d30325b 100644
--- a/src/testdir/test_timers.vim
+++ b/src/testdir/test_timers.vim
@@ -189,4 +189,22 @@
   call assert_equal('hello', g:val)
 endfunc
 
+func FuncWithError(timer)
+  let g:call_count += 1
+  if g:call_count == 4
+    return
+  endif
+  doesnotexist
+endfunc
+
+func Test_timer_errors()
+  let g:call_count = 0
+  let timer = timer_start(10, 'FuncWithError', {'repeat': -1})
+  " Timer will be stopped after failing 3 out of 3 times.
+  call WaitFor('g:call_count == 3')
+  sleep 50m
+  call assert_equal(3, g:call_count)
+endfunc
+
+
 " vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/version.c b/src/version.c
index 42fb71d..70de1d4 100644
--- a/src/version.c
+++ b/src/version.c
@@ -765,6 +765,8 @@
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    702,
+/**/
     701,
 /**/
     700,