@@ -36,6 +36,7 @@ typedef struct timeout_params
3636
3737 TimestampTz start_time ; /* time that timeout was last activated */
3838 TimestampTz fin_time ; /* time it is, or was last, due to fire */
39+ int interval_in_ms ; /* time between firings, or 0 if just once */
3940} timeout_params ;
4041
4142/*
@@ -153,7 +154,8 @@ remove_timeout_index(int index)
153154 * Enable the specified timeout reason
154155 */
155156static void
156- enable_timeout (TimeoutId id , TimestampTz now , TimestampTz fin_time )
157+ enable_timeout (TimeoutId id , TimestampTz now , TimestampTz fin_time ,
158+ int interval_in_ms )
157159{
158160 int i ;
159161
@@ -188,6 +190,7 @@ enable_timeout(TimeoutId id, TimestampTz now, TimestampTz fin_time)
188190 all_timeouts [id ].indicator = false;
189191 all_timeouts [id ].start_time = now ;
190192 all_timeouts [id ].fin_time = fin_time ;
193+ all_timeouts [id ].interval_in_ms = interval_in_ms ;
191194
192195 insert_timeout (id , i );
193196}
@@ -399,6 +402,29 @@ handle_sig_alarm(SIGNAL_ARGS)
399402 /* And call its handler function */
400403 this_timeout -> timeout_handler ();
401404
405+ /* If it should fire repeatedly, re-enable it. */
406+ if (this_timeout -> interval_in_ms > 0 )
407+ {
408+ TimestampTz new_fin_time ;
409+
410+ /*
411+ * To guard against drift, schedule the next instance of
412+ * the timeout based on the intended firing time rather
413+ * than the actual firing time. But if the timeout was so
414+ * late that we missed an entire cycle, fall back to
415+ * scheduling based on the actual firing time.
416+ */
417+ new_fin_time =
418+ TimestampTzPlusMilliseconds (this_timeout -> fin_time ,
419+ this_timeout -> interval_in_ms );
420+ if (new_fin_time < now )
421+ new_fin_time =
422+ TimestampTzPlusMilliseconds (now ,
423+ this_timeout -> interval_in_ms );
424+ enable_timeout (this_timeout -> index , now , new_fin_time ,
425+ this_timeout -> interval_in_ms );
426+ }
427+
402428 /*
403429 * The handler might not take negligible time (CheckDeadLock
404430 * for instance isn't too cheap), so let's update our idea of
@@ -449,6 +475,7 @@ InitializeTimeouts(void)
449475 all_timeouts [i ].timeout_handler = NULL ;
450476 all_timeouts [i ].start_time = 0 ;
451477 all_timeouts [i ].fin_time = 0 ;
478+ all_timeouts [i ].interval_in_ms = 0 ;
452479 }
453480
454481 all_timeouts_initialized = true;
@@ -532,7 +559,29 @@ enable_timeout_after(TimeoutId id, int delay_ms)
532559 /* Queue the timeout at the appropriate time. */
533560 now = GetCurrentTimestamp ();
534561 fin_time = TimestampTzPlusMilliseconds (now , delay_ms );
535- enable_timeout (id , now , fin_time );
562+ enable_timeout (id , now , fin_time , 0 );
563+
564+ /* Set the timer interrupt. */
565+ schedule_alarm (now );
566+ }
567+
568+ /*
569+ * Enable the specified timeout to fire periodically, with the specified
570+ * delay as the time between firings.
571+ *
572+ * Delay is given in milliseconds.
573+ */
574+ void
575+ enable_timeout_every (TimeoutId id , TimestampTz fin_time , int delay_ms )
576+ {
577+ TimestampTz now ;
578+
579+ /* Disable timeout interrupts for safety. */
580+ disable_alarm ();
581+
582+ /* Queue the timeout at the appropriate time. */
583+ now = GetCurrentTimestamp ();
584+ enable_timeout (id , now , fin_time , delay_ms );
536585
537586 /* Set the timer interrupt. */
538587 schedule_alarm (now );
@@ -555,7 +604,7 @@ enable_timeout_at(TimeoutId id, TimestampTz fin_time)
555604
556605 /* Queue the timeout at the appropriate time. */
557606 now = GetCurrentTimestamp ();
558- enable_timeout (id , now , fin_time );
607+ enable_timeout (id , now , fin_time , 0 );
559608
560609 /* Set the timer interrupt. */
561610 schedule_alarm (now );
@@ -590,11 +639,17 @@ enable_timeouts(const EnableTimeoutParams *timeouts, int count)
590639 case TMPARAM_AFTER :
591640 fin_time = TimestampTzPlusMilliseconds (now ,
592641 timeouts [i ].delay_ms );
593- enable_timeout (id , now , fin_time );
642+ enable_timeout (id , now , fin_time , 0 );
594643 break ;
595644
596645 case TMPARAM_AT :
597- enable_timeout (id , now , timeouts [i ].fin_time );
646+ enable_timeout (id , now , timeouts [i ].fin_time , 0 );
647+ break ;
648+
649+ case TMPARAM_EVERY :
650+ fin_time = TimestampTzPlusMilliseconds (now ,
651+ timeouts [i ].delay_ms );
652+ enable_timeout (id , now , fin_time , timeouts [i ].delay_ms );
598653 break ;
599654
600655 default :
0 commit comments