1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95
|
@@ -51,6 +51,13 @@ static bool all_timeouts_initialized = false; static volatile int num_active_timeouts = 0; static timeout_params *volatile active_timeouts[MAX_TIMEOUTS];
+/* + * State used to avoid installing a new timer interrupt when the previous one + * hasn't fired yet, but isn't too late. + */ +static TimestampTz sigalrm_due_at = PG_INT64_MAX; +static volatile sig_atomic_t sigalrm_delivered = false; + /* * Flag controlling whether the signal handler is allowed to do anything. * We leave this "false" when we're not expecting interrupts, just in case. @@ -195,12 +202,13 @@ schedule_alarm(TimestampTz now) struct itimerval timeval; long secs; int usecs; + TimestampTz nearest_timeout;
MemSet(&timeval, 0, sizeof(struct itimerval));
/* Get the time remaining till the nearest pending timeout */ - TimestampDifference(now, active_timeouts[0]->fin_time, - &secs, &usecs); + nearest_timeout = active_timeouts[0]->fin_time; + TimestampDifference(now, nearest_timeout, &secs, &usecs);
/* * It's possible that the difference is less than a microsecond; @@ -244,9 +252,18 @@ schedule_alarm(TimestampTz now) */ enable_alarm();
+ /* + * Try to avoid having to set the interval timer, if we already know + * that there is an undelivered signal due at the same time or sooner. + */ + if (nearest_timeout >= sigalrm_due_at && !sigalrm_delivered) + return; + /* Set the alarm timer */ if (setitimer(ITIMER_REAL, &timeval, NULL) != 0) elog(FATAL, "could not enable SIGALRM timer: %m"); + sigalrm_due_at = nearest_timeout; + sigalrm_delivered = false; } }
@@ -266,6 +283,8 @@ handle_sig_alarm(SIGNAL_ARGS) { int save_errno = errno;
+ sigalrm_delivered = true; + /* * Bump the holdoff counter, to make sure nothing we call will process * interrupts directly. No timeout handler should do that, but these @@ -591,8 +610,9 @@ disable_timeouts(const DisableTimeoutParams *timeouts, int count) }
/* - * Disable SIGALRM and remove all timeouts from the active list, - * and optionally reset their timeout indicators. + * Remove all timeouts from the active list, and optionally reset their timeout + * indicators. Leave any existing itimer installed, because it may allow us to + * avoid having to set it again soon. */ void disable_all_timeouts(bool keep_indicators) @@ -601,20 +621,6 @@ disable_all_timeouts(bool keep_indicators)
disable_alarm();
- /* - * Only bother to reset the timer if we think it's active. We could just - * let the interrupt happen anyway, but it's probably a bit cheaper to do - * setitimer() than to let the useless interrupt happen. - */ - if (num_active_timeouts > 0) - { - struct itimerval timeval; - - MemSet(&timeval, 0, sizeof(struct itimerval)); - if (setitimer(ITIMER_REAL, &timeval, NULL) != 0) - elog(FATAL, "could not disable SIGALRM timer: %m"); - } - num_active_timeouts = 0;
for (i = 0; i < MAX_TIMEOUTS; i++)
|