Skip to content

Commit 732e667

Browse files
committed
Add enable_timeout_every() to fire the same timeout repeatedly.
enable_timeout_at() and enable_timeout_after() can still be used when you want to fire a timeout just once. Patch by me, per a suggestion from Tom Lane. Discussion: http://postgr.es/m/2992585.1632938816@sss.pgh.pa.us Discussion: http://postgr.es/m/CA+TgmoYqSF5sCNrgTom9r3Nh=at4WmYFD=gsV-omStZ60S0ZUQ@mail.gmail.com
1 parent 902a2c2 commit 732e667

File tree

2 files changed

+65
-7
lines changed

2 files changed

+65
-7
lines changed

src/backend/utils/misc/timeout.c

Lines changed: 60 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -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
*/
155156
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)
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:

src/include/utils/timeout.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,14 +48,15 @@ typedef void (*timeout_handler_proc) (void);
4848
typedef enum TimeoutType
4949
{
5050
TMPARAM_AFTER,
51-
TMPARAM_AT
51+
TMPARAM_AT,
52+
TMPARAM_EVERY
5253
} TimeoutType;
5354

5455
typedef struct
5556
{
5657
TimeoutId id; /* timeout to set */
5758
TimeoutType type; /* TMPARAM_AFTER or TMPARAM_AT */
58-
int delay_ms; /* only used for TMPARAM_AFTER */
59+
int delay_ms; /* only used for TMPARAM_AFTER/EVERY */
5960
TimestampTz fin_time; /* only used for TMPARAM_AT */
6061
} EnableTimeoutParams;
6162

@@ -75,6 +76,8 @@ extern void reschedule_timeouts(void);
7576

7677
/* timeout operation */
7778
extern void enable_timeout_after(TimeoutId id, int delay_ms);
79+
extern void enable_timeout_every(TimeoutId id, TimestampTz fin_time,
80+
int delay_ms);
7881
extern void enable_timeout_at(TimeoutId id, TimestampTz fin_time);
7982
extern void enable_timeouts(const EnableTimeoutParams *timeouts, int count);
8083
extern void disable_timeout(TimeoutId id, bool keep_indicator);

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy