@@ -36,6 +36,7 @@ typedef struct timeout_params
36
36
37
37
TimestampTz start_time ; /* time that timeout was last activated */
38
38
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 */
39
40
} timeout_params ;
40
41
41
42
/*
@@ -153,7 +154,8 @@ remove_timeout_index(int index)
153
154
* Enable the specified timeout reason
154
155
*/
155
156
static 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 )
157
159
{
158
160
int i ;
159
161
@@ -188,6 +190,7 @@ enable_timeout(TimeoutId id, TimestampTz now, TimestampTz fin_time)
188
190
all_timeouts [id ].indicator = false;
189
191
all_timeouts [id ].start_time = now ;
190
192
all_timeouts [id ].fin_time = fin_time ;
193
+ all_timeouts [id ].interval_in_ms = interval_in_ms ;
191
194
192
195
insert_timeout (id , i );
193
196
}
@@ -399,6 +402,29 @@ handle_sig_alarm(SIGNAL_ARGS)
399
402
/* And call its handler function */
400
403
this_timeout -> timeout_handler ();
401
404
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
+
402
428
/*
403
429
* The handler might not take negligible time (CheckDeadLock
404
430
* for instance isn't too cheap), so let's update our idea of
@@ -449,6 +475,7 @@ InitializeTimeouts(void)
449
475
all_timeouts [i ].timeout_handler = NULL ;
450
476
all_timeouts [i ].start_time = 0 ;
451
477
all_timeouts [i ].fin_time = 0 ;
478
+ all_timeouts [i ].interval_in_ms = 0 ;
452
479
}
453
480
454
481
all_timeouts_initialized = true;
@@ -532,7 +559,29 @@ enable_timeout_after(TimeoutId id, int delay_ms)
532
559
/* Queue the timeout at the appropriate time. */
533
560
now = GetCurrentTimestamp ();
534
561
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 );
536
585
537
586
/* Set the timer interrupt. */
538
587
schedule_alarm (now );
@@ -555,7 +604,7 @@ enable_timeout_at(TimeoutId id, TimestampTz fin_time)
555
604
556
605
/* Queue the timeout at the appropriate time. */
557
606
now = GetCurrentTimestamp ();
558
- enable_timeout (id , now , fin_time );
607
+ enable_timeout (id , now , fin_time , 0 );
559
608
560
609
/* Set the timer interrupt. */
561
610
schedule_alarm (now );
@@ -590,11 +639,17 @@ enable_timeouts(const EnableTimeoutParams *timeouts, int count)
590
639
case TMPARAM_AFTER :
591
640
fin_time = TimestampTzPlusMilliseconds (now ,
592
641
timeouts [i ].delay_ms );
593
- enable_timeout (id , now , fin_time );
642
+ enable_timeout (id , now , fin_time , 0 );
594
643
break ;
595
644
596
645
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 );
598
653
break ;
599
654
600
655
default :
0 commit comments