@@ -1088,10 +1088,17 @@ profile_zero(proftime_T *tm)
10881088
10891089# if defined(FEAT_TIMERS ) || defined(PROTO )
10901090static timer_T * first_timer = NULL ;
1091- static int last_timer_id = 0 ;
1091+ static long last_timer_id = 0 ;
10921092
1093- static timer_T * current_timer = NULL ;
1094- static int free_current_timer = FALSE;
1093+ # ifdef WIN3264
1094+ # define GET_TIMEDIFF (timer , now ) \
1095+ (long)(((double)(timer->tr_due.QuadPart - now.QuadPart) \
1096+ / (double)fr.QuadPart) * 1000);
1097+ # else
1098+ # define GET_TIMEDIFF (timer , now ) \
1099+ (timer->tr_due.tv_sec - now.tv_sec) * 1000 \
1100+ + (timer->tr_due.tv_usec - now.tv_usec) / 1000;
1101+ # endif
10951102
10961103/*
10971104 * Insert a timer in the list of timers.
@@ -1124,13 +1131,8 @@ remove_timer(timer_T *timer)
11241131 static void
11251132free_timer (timer_T * timer )
11261133{
1127- if (timer == current_timer )
1128- free_current_timer = TRUE;
1129- else
1130- {
1131- free_callback (timer -> tr_callback , timer -> tr_partial );
1132- vim_free (timer );
1133- }
1134+ free_callback (timer -> tr_callback , timer -> tr_partial );
1135+ vim_free (timer );
11341136}
11351137
11361138/*
@@ -1144,7 +1146,10 @@ create_timer(long msec, int repeat)
11441146
11451147 if (timer == NULL )
11461148 return NULL ;
1147- timer -> tr_id = ++ last_timer_id ;
1149+ if (++ last_timer_id < 0 )
1150+ /* Overflow! Might cause duplicates... */
1151+ last_timer_id = 0 ;
1152+ timer -> tr_id = last_timer_id ;
11481153 insert_timer (timer );
11491154 if (repeat != 0 )
11501155 timer -> tr_repeat = repeat - 1 ;
@@ -1165,7 +1170,7 @@ timer_callback(timer_T *timer)
11651170 typval_T argv [2 ];
11661171
11671172 argv [0 ].v_type = VAR_NUMBER ;
1168- argv [0 ].vval .v_number = timer -> tr_id ;
1173+ argv [0 ].vval .v_number = ( varnumber_T ) timer -> tr_id ;
11691174 argv [1 ].v_type = VAR_UNKNOWN ;
11701175
11711176 call_func (timer -> tr_callback , (int )STRLEN (timer -> tr_callback ),
@@ -1182,77 +1187,76 @@ timer_callback(timer_T *timer)
11821187check_due_timer (void )
11831188{
11841189 timer_T * timer ;
1190+ timer_T * timer_next ;
11851191 long this_due ;
11861192 long next_due = -1 ;
11871193 proftime_T now ;
11881194 int did_one = FALSE;
1195+ long current_id = last_timer_id ;
11891196# ifdef WIN3264
11901197 LARGE_INTEGER fr ;
11911198
11921199 QueryPerformanceFrequency (& fr );
11931200# endif
1194- while (!got_int )
1201+ profile_start (& now );
1202+ for (timer = first_timer ; timer != NULL && !got_int ; timer = timer_next )
11951203 {
1196- profile_start (& now );
1197- next_due = -1 ;
1198- for (timer = first_timer ; timer != NULL ; timer = timer -> tr_next )
1204+ timer_next = timer -> tr_next ;
1205+
1206+ if (timer -> tr_id == -1 || timer -> tr_firing || timer -> tr_paused )
1207+ continue ;
1208+ this_due = GET_TIMEDIFF (timer , now );
1209+ if (this_due <= 1 )
11991210 {
1200- if (timer -> tr_paused )
1201- continue ;
1202- # ifdef WIN3264
1203- this_due = (long )(((double )(timer -> tr_due .QuadPart - now .QuadPart )
1204- / (double )fr .QuadPart ) * 1000 );
1205- # else
1206- this_due = (timer -> tr_due .tv_sec - now .tv_sec ) * 1000
1207- + (timer -> tr_due .tv_usec - now .tv_usec ) / 1000 ;
1208- # endif
1209- if (this_due <= 1 )
1211+ timer -> tr_firing = TRUE;
1212+ timer_callback (timer );
1213+ timer -> tr_firing = FALSE;
1214+ timer_next = timer -> tr_next ;
1215+ did_one = TRUE;
1216+
1217+ /* Only fire the timer again if it repeats and stop_timer() wasn't
1218+ * called while inside the callback (tr_id == -1). */
1219+ if (timer -> tr_repeat != 0 && timer -> tr_id != -1 )
12101220 {
1211- current_timer = timer ;
1212- free_current_timer = FALSE;
1213- timer_callback (timer );
1214- current_timer = NULL ;
1215-
1216- did_one = TRUE;
1217- if (timer -> tr_repeat != 0 && !free_current_timer )
1218- {
1219- profile_setlimit (timer -> tr_interval , & timer -> tr_due );
1220- if (timer -> tr_repeat > 0 )
1221- -- timer -> tr_repeat ;
1222- }
1223- else
1224- {
1225- remove_timer (timer );
1226- free_timer (timer );
1227- }
1228- /* the callback may do anything, start all over */
1229- break ;
1221+ profile_setlimit (timer -> tr_interval , & timer -> tr_due );
1222+ this_due = GET_TIMEDIFF (timer , now );
1223+ if (this_due < 1 )
1224+ this_due = 1 ;
1225+ if (timer -> tr_repeat > 0 )
1226+ -- timer -> tr_repeat ;
1227+ }
1228+ else
1229+ {
1230+ this_due = -1 ;
1231+ remove_timer (timer );
1232+ free_timer (timer );
12301233 }
1231- if (next_due == -1 || next_due > this_due )
1232- next_due = this_due ;
12331234 }
1234- if (timer == NULL )
1235- break ;
1235+ if (this_due > 0 && ( next_due == -1 || next_due > this_due ) )
1236+ next_due = this_due ;
12361237 }
12371238
12381239 if (did_one )
12391240 redraw_after_callback ();
12401241
1241- return next_due ;
1242+ return current_id != last_timer_id ? 1 : next_due ;
12421243}
12431244
12441245/*
12451246 * Find a timer by ID. Returns NULL if not found;
12461247 */
12471248 timer_T *
1248- find_timer (int id )
1249+ find_timer (long id )
12491250{
12501251 timer_T * timer ;
12511252
1252- for (timer = first_timer ; timer != NULL ; timer = timer -> tr_next )
1253- if (timer -> tr_id == id )
1254- break ;
1255- return timer ;
1253+ if (id >= 0 )
1254+ {
1255+ for (timer = first_timer ; timer != NULL ; timer = timer -> tr_next )
1256+ if (timer -> tr_id == id )
1257+ return timer ;
1258+ }
1259+ return NULL ;
12561260}
12571261
12581262
@@ -1262,15 +1266,27 @@ find_timer(int id)
12621266 void
12631267stop_timer (timer_T * timer )
12641268{
1265- remove_timer (timer );
1266- free_timer (timer );
1269+ if (timer -> tr_firing )
1270+ /* Free the timer after the callback returns. */
1271+ timer -> tr_id = -1 ;
1272+ else
1273+ {
1274+ remove_timer (timer );
1275+ free_timer (timer );
1276+ }
12671277}
12681278
12691279 void
12701280stop_all_timers (void )
12711281{
1272- while (first_timer != NULL )
1273- stop_timer (first_timer );
1282+ timer_T * timer ;
1283+ timer_T * timer_next ;
1284+
1285+ for (timer = first_timer ; timer != NULL ; timer = timer_next )
1286+ {
1287+ timer_next = timer -> tr_next ;
1288+ stop_timer (timer );
1289+ }
12741290}
12751291
12761292 void
@@ -1289,18 +1305,14 @@ add_timer_info(typval_T *rettv, timer_T *timer)
12891305 return ;
12901306 list_append_dict (list , dict );
12911307
1292- dict_add_nr_str (dict , "id" , ( long ) timer -> tr_id , NULL );
1308+ dict_add_nr_str (dict , "id" , timer -> tr_id , NULL );
12931309 dict_add_nr_str (dict , "time" , (long )timer -> tr_interval , NULL );
12941310
12951311 profile_start (& now );
12961312# ifdef WIN3264
12971313 QueryPerformanceFrequency (& fr );
1298- remaining = (long )(((double )(timer -> tr_due .QuadPart - now .QuadPart )
1299- / (double )fr .QuadPart ) * 1000 );
1300- # else
1301- remaining = (timer -> tr_due .tv_sec - now .tv_sec ) * 1000
1302- + (timer -> tr_due .tv_usec - now .tv_usec ) / 1000 ;
13031314# endif
1315+ remaining = GET_TIMEDIFF (timer , now );
13041316 dict_add_nr_str (dict , "remaining" , (long )remaining , NULL );
13051317
13061318 dict_add_nr_str (dict , "repeat" ,
@@ -1333,7 +1345,8 @@ add_timer_info_all(typval_T *rettv)
13331345 timer_T * timer ;
13341346
13351347 for (timer = first_timer ; timer != NULL ; timer = timer -> tr_next )
1336- add_timer_info (rettv , timer );
1348+ if (timer -> tr_id != -1 )
1349+ add_timer_info (rettv , timer );
13371350}
13381351
13391352/*
0 commit comments