Now that we have non-Latin1 SGML detection, restore Latin1 chars
[pgsql.git] / src / backend / utils / misc / timeout.c
blobec7e570920a5d8c1179be51a8461cbef121fa9b7
1 /*-------------------------------------------------------------------------
3 * timeout.c
4 * Routines to multiplex SIGALRM interrupts for multiple timeout reasons.
6 * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
10 * IDENTIFICATION
11 * src/backend/utils/misc/timeout.c
13 *-------------------------------------------------------------------------
15 #include "postgres.h"
17 #include <sys/time.h>
19 #include "miscadmin.h"
20 #include "storage/latch.h"
21 #include "utils/timeout.h"
22 #include "utils/timestamp.h"
25 /* Data about any one timeout reason */
26 typedef struct timeout_params
28 TimeoutId index; /* identifier of timeout reason */
30 /* volatile because these may be changed from the signal handler */
31 volatile bool active; /* true if timeout is in active_timeouts[] */
32 volatile bool indicator; /* true if timeout has occurred */
34 /* callback function for timeout, or NULL if timeout not registered */
35 timeout_handler_proc timeout_handler;
37 TimestampTz start_time; /* time that timeout was last activated */
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 */
40 } timeout_params;
43 * List of possible timeout reasons in the order of enum TimeoutId.
45 static timeout_params all_timeouts[MAX_TIMEOUTS];
46 static bool all_timeouts_initialized = false;
49 * List of active timeouts ordered by their fin_time and priority.
50 * This list is subject to change by the interrupt handler, so it's volatile.
52 static volatile int num_active_timeouts = 0;
53 static timeout_params *volatile active_timeouts[MAX_TIMEOUTS];
56 * Flag controlling whether the signal handler is allowed to do anything.
57 * This is useful to avoid race conditions with the handler. Note in
58 * particular that this lets us make changes in the data structures without
59 * tediously disabling and re-enabling the timer signal. Most of the time,
60 * no interrupt would happen anyway during such critical sections, but if
61 * one does, this rule ensures it's safe. Leaving the signal enabled across
62 * multiple operations can greatly reduce the number of kernel calls we make,
63 * too. See comments in schedule_alarm() about that.
65 * We leave this "false" when we're not expecting interrupts, just in case.
67 static volatile sig_atomic_t alarm_enabled = false;
69 #define disable_alarm() (alarm_enabled = false)
70 #define enable_alarm() (alarm_enabled = true)
73 * State recording if and when we next expect the interrupt to fire.
74 * (signal_due_at is valid only when signal_pending is true.)
75 * Note that the signal handler will unconditionally reset signal_pending to
76 * false, so that can change asynchronously even when alarm_enabled is false.
78 static volatile sig_atomic_t signal_pending = false;
79 static volatile TimestampTz signal_due_at = 0;
82 /*****************************************************************************
83 * Internal helper functions
85 * For all of these, it is caller's responsibility to protect them from
86 * interruption by the signal handler. Generally, call disable_alarm()
87 * first to prevent interruption, then update state, and last call
88 * schedule_alarm(), which will re-enable the signal handler if needed.
89 *****************************************************************************/
92 * Find the index of a given timeout reason in the active array.
93 * If it's not there, return -1.
95 static int
96 find_active_timeout(TimeoutId id)
98 int i;
100 for (i = 0; i < num_active_timeouts; i++)
102 if (active_timeouts[i]->index == id)
103 return i;
106 return -1;
110 * Insert specified timeout reason into the list of active timeouts
111 * at the given index.
113 static void
114 insert_timeout(TimeoutId id, int index)
116 int i;
118 if (index < 0 || index > num_active_timeouts)
119 elog(FATAL, "timeout index %d out of range 0..%d", index,
120 num_active_timeouts);
122 Assert(!all_timeouts[id].active);
123 all_timeouts[id].active = true;
125 for (i = num_active_timeouts - 1; i >= index; i--)
126 active_timeouts[i + 1] = active_timeouts[i];
128 active_timeouts[index] = &all_timeouts[id];
130 num_active_timeouts++;
134 * Remove the index'th element from the timeout list.
136 static void
137 remove_timeout_index(int index)
139 int i;
141 if (index < 0 || index >= num_active_timeouts)
142 elog(FATAL, "timeout index %d out of range 0..%d", index,
143 num_active_timeouts - 1);
145 Assert(active_timeouts[index]->active);
146 active_timeouts[index]->active = false;
148 for (i = index + 1; i < num_active_timeouts; i++)
149 active_timeouts[i - 1] = active_timeouts[i];
151 num_active_timeouts--;
155 * Enable the specified timeout reason
157 static void
158 enable_timeout(TimeoutId id, TimestampTz now, TimestampTz fin_time,
159 int interval_in_ms)
161 int i;
163 /* Assert request is sane */
164 Assert(all_timeouts_initialized);
165 Assert(all_timeouts[id].timeout_handler != NULL);
168 * If this timeout was already active, momentarily disable it. We
169 * interpret the call as a directive to reschedule the timeout.
171 if (all_timeouts[id].active)
172 remove_timeout_index(find_active_timeout(id));
175 * Find out the index where to insert the new timeout. We sort by
176 * fin_time, and for equal fin_time by priority.
178 for (i = 0; i < num_active_timeouts; i++)
180 timeout_params *old_timeout = active_timeouts[i];
182 if (fin_time < old_timeout->fin_time)
183 break;
184 if (fin_time == old_timeout->fin_time && id < old_timeout->index)
185 break;
189 * Mark the timeout active, and insert it into the active list.
191 all_timeouts[id].indicator = false;
192 all_timeouts[id].start_time = now;
193 all_timeouts[id].fin_time = fin_time;
194 all_timeouts[id].interval_in_ms = interval_in_ms;
196 insert_timeout(id, i);
200 * Schedule alarm for the next active timeout, if any
202 * We assume the caller has obtained the current time, or a close-enough
203 * approximation. (It's okay if a tick or two has passed since "now", or
204 * if a little more time elapses before we reach the kernel call; that will
205 * cause us to ask for an interrupt a tick or two later than the nearest
206 * timeout, which is no big deal. Passing a "now" value that's in the future
207 * would be bad though.)
209 static void
210 schedule_alarm(TimestampTz now)
212 if (num_active_timeouts > 0)
214 struct itimerval timeval;
215 TimestampTz nearest_timeout;
216 long secs;
217 int usecs;
219 MemSet(&timeval, 0, sizeof(struct itimerval));
222 * If we think there's a signal pending, but current time is more than
223 * 10ms past when the signal was due, then assume that the timeout
224 * request got lost somehow; clear signal_pending so that we'll reset
225 * the interrupt request below. (10ms corresponds to the worst-case
226 * timeout granularity on modern systems.) It won't hurt us if the
227 * interrupt does manage to fire between now and when we reach the
228 * setitimer() call.
230 if (signal_pending && now > signal_due_at + 10 * 1000)
231 signal_pending = false;
234 * Get the time remaining till the nearest pending timeout. If it is
235 * negative, assume that we somehow missed an interrupt, and clear
236 * signal_pending. This gives us another chance to recover if the
237 * kernel drops a timeout request for some reason.
239 nearest_timeout = active_timeouts[0]->fin_time;
240 if (now > nearest_timeout)
242 signal_pending = false;
243 /* force an interrupt as soon as possible */
244 secs = 0;
245 usecs = 1;
247 else
249 TimestampDifference(now, nearest_timeout,
250 &secs, &usecs);
253 * It's possible that the difference is less than a microsecond;
254 * ensure we don't cancel, rather than set, the interrupt.
256 if (secs == 0 && usecs == 0)
257 usecs = 1;
260 timeval.it_value.tv_sec = secs;
261 timeval.it_value.tv_usec = usecs;
264 * We must enable the signal handler before calling setitimer(); if we
265 * did it in the other order, we'd have a race condition wherein the
266 * interrupt could occur before we can set alarm_enabled, so that the
267 * signal handler would fail to do anything.
269 * Because we didn't bother to disable the timer in disable_alarm(),
270 * it's possible that a previously-set interrupt will fire between
271 * enable_alarm() and setitimer(). This is safe, however. There are
272 * two possible outcomes:
274 * 1. The signal handler finds nothing to do (because the nearest
275 * timeout event is still in the future). It will re-set the timer
276 * and return. Then we'll overwrite the timer value with a new one.
277 * This will mean that the timer fires a little later than we
278 * intended, but only by the amount of time it takes for the signal
279 * handler to do nothing useful, which shouldn't be much.
281 * 2. The signal handler executes and removes one or more timeout
282 * events. When it returns, either the queue is now empty or the
283 * frontmost event is later than the one we looked at above. So we'll
284 * overwrite the timer value with one that is too soon (plus or minus
285 * the signal handler's execution time), causing a useless interrupt
286 * to occur. But the handler will then re-set the timer and
287 * everything will still work as expected.
289 * Since these cases are of very low probability (the window here
290 * being quite narrow), it's not worth adding cycles to the mainline
291 * code to prevent occasional wasted interrupts.
293 enable_alarm();
296 * If there is already an interrupt pending that's at or before the
297 * needed time, we need not do anything more. The signal handler will
298 * do the right thing in the first case, and re-schedule the interrupt
299 * for later in the second case. It might seem that the extra
300 * interrupt is wasted work, but it's not terribly much work, and this
301 * method has very significant advantages in the common use-case where
302 * we repeatedly set a timeout that we don't expect to reach and then
303 * cancel it. Instead of invoking setitimer() every time the timeout
304 * is set or canceled, we perform one interrupt and a re-scheduling
305 * setitimer() call at intervals roughly equal to the timeout delay.
306 * For example, with statement_timeout = 1s and a throughput of
307 * thousands of queries per second, this method requires an interrupt
308 * and setitimer() call roughly once a second, rather than thousands
309 * of setitimer() calls per second.
311 * Because of the possible passage of time between when we obtained
312 * "now" and when we reach setitimer(), the kernel's opinion of when
313 * to trigger the interrupt is likely to be a bit later than
314 * signal_due_at. That's fine, for the same reasons described above.
316 if (signal_pending && nearest_timeout >= signal_due_at)
317 return;
320 * As with calling enable_alarm(), we must set signal_pending *before*
321 * calling setitimer(); if we did it after, the signal handler could
322 * trigger before we set it, leaving us with a false opinion that a
323 * signal is still coming.
325 * Other race conditions involved with setting/checking signal_pending
326 * are okay, for the reasons described above. One additional point is
327 * that the signal handler could fire after we set signal_due_at, but
328 * still before the setitimer() call. Then the handler could
329 * overwrite signal_due_at with a value it computes, which will be the
330 * same as or perhaps later than what we just computed. After we
331 * perform setitimer(), the net effect would be that signal_due_at
332 * gives a time later than when the interrupt will really happen;
333 * which is a safe situation.
335 signal_due_at = nearest_timeout;
336 signal_pending = true;
338 /* Set the alarm timer */
339 if (setitimer(ITIMER_REAL, &timeval, NULL) != 0)
342 * Clearing signal_pending here is a bit pro forma, but not
343 * entirely so, since something in the FATAL exit path could try
344 * to use timeout facilities.
346 signal_pending = false;
347 elog(FATAL, "could not enable SIGALRM timer: %m");
353 /*****************************************************************************
354 * Signal handler
355 *****************************************************************************/
358 * Signal handler for SIGALRM
360 * Process any active timeout reasons and then reschedule the interrupt
361 * as needed.
363 static void
364 handle_sig_alarm(SIGNAL_ARGS)
367 * Bump the holdoff counter, to make sure nothing we call will process
368 * interrupts directly. No timeout handler should do that, but these
369 * failures are hard to debug, so better be sure.
371 HOLD_INTERRUPTS();
374 * SIGALRM is always cause for waking anything waiting on the process
375 * latch.
377 SetLatch(MyLatch);
380 * Always reset signal_pending, even if !alarm_enabled, since indeed no
381 * signal is now pending.
383 signal_pending = false;
386 * Fire any pending timeouts, but only if we're enabled to do so.
388 if (alarm_enabled)
391 * Disable alarms, just in case this platform allows signal handlers
392 * to interrupt themselves. schedule_alarm() will re-enable if
393 * appropriate.
395 disable_alarm();
397 if (num_active_timeouts > 0)
399 TimestampTz now = GetCurrentTimestamp();
401 /* While the first pending timeout has been reached ... */
402 while (num_active_timeouts > 0 &&
403 now >= active_timeouts[0]->fin_time)
405 timeout_params *this_timeout = active_timeouts[0];
407 /* Remove it from the active list */
408 remove_timeout_index(0);
410 /* Mark it as fired */
411 this_timeout->indicator = true;
413 /* And call its handler function */
414 this_timeout->timeout_handler();
416 /* If it should fire repeatedly, re-enable it. */
417 if (this_timeout->interval_in_ms > 0)
419 TimestampTz new_fin_time;
422 * To guard against drift, schedule the next instance of
423 * the timeout based on the intended firing time rather
424 * than the actual firing time. But if the timeout was so
425 * late that we missed an entire cycle, fall back to
426 * scheduling based on the actual firing time.
428 new_fin_time =
429 TimestampTzPlusMilliseconds(this_timeout->fin_time,
430 this_timeout->interval_in_ms);
431 if (new_fin_time < now)
432 new_fin_time =
433 TimestampTzPlusMilliseconds(now,
434 this_timeout->interval_in_ms);
435 enable_timeout(this_timeout->index, now, new_fin_time,
436 this_timeout->interval_in_ms);
440 * The handler might not take negligible time (CheckDeadLock
441 * for instance isn't too cheap), so let's update our idea of
442 * "now" after each one.
444 now = GetCurrentTimestamp();
447 /* Done firing timeouts, so reschedule next interrupt if any */
448 schedule_alarm(now);
452 RESUME_INTERRUPTS();
456 /*****************************************************************************
457 * Public API
458 *****************************************************************************/
461 * Initialize timeout module.
463 * This must be called in every process that wants to use timeouts.
465 * If the process was forked from another one that was also using this
466 * module, be sure to call this before re-enabling signals; else handlers
467 * meant to run in the parent process might get invoked in this one.
469 void
470 InitializeTimeouts(void)
472 int i;
474 /* Initialize, or re-initialize, all local state */
475 disable_alarm();
477 num_active_timeouts = 0;
479 for (i = 0; i < MAX_TIMEOUTS; i++)
481 all_timeouts[i].index = i;
482 all_timeouts[i].active = false;
483 all_timeouts[i].indicator = false;
484 all_timeouts[i].timeout_handler = NULL;
485 all_timeouts[i].start_time = 0;
486 all_timeouts[i].fin_time = 0;
487 all_timeouts[i].interval_in_ms = 0;
490 all_timeouts_initialized = true;
492 /* Now establish the signal handler */
493 pqsignal(SIGALRM, handle_sig_alarm);
497 * Register a timeout reason
499 * For predefined timeouts, this just registers the callback function.
501 * For user-defined timeouts, pass id == USER_TIMEOUT; we then allocate and
502 * return a timeout ID.
504 TimeoutId
505 RegisterTimeout(TimeoutId id, timeout_handler_proc handler)
507 Assert(all_timeouts_initialized);
509 /* There's no need to disable the signal handler here. */
511 if (id >= USER_TIMEOUT)
513 /* Allocate a user-defined timeout reason */
514 for (id = USER_TIMEOUT; id < MAX_TIMEOUTS; id++)
515 if (all_timeouts[id].timeout_handler == NULL)
516 break;
517 if (id >= MAX_TIMEOUTS)
518 ereport(FATAL,
519 (errcode(ERRCODE_CONFIGURATION_LIMIT_EXCEEDED),
520 errmsg("cannot add more timeout reasons")));
523 Assert(all_timeouts[id].timeout_handler == NULL);
525 all_timeouts[id].timeout_handler = handler;
527 return id;
531 * Reschedule any pending SIGALRM interrupt.
533 * This can be used during error recovery in case query cancel resulted in loss
534 * of a SIGALRM event (due to longjmp'ing out of handle_sig_alarm before it
535 * could do anything). But note it's not necessary if any of the public
536 * enable_ or disable_timeout functions are called in the same area, since
537 * those all do schedule_alarm() internally if needed.
539 void
540 reschedule_timeouts(void)
542 /* For flexibility, allow this to be called before we're initialized. */
543 if (!all_timeouts_initialized)
544 return;
546 /* Disable timeout interrupts for safety. */
547 disable_alarm();
549 /* Reschedule the interrupt, if any timeouts remain active. */
550 if (num_active_timeouts > 0)
551 schedule_alarm(GetCurrentTimestamp());
555 * Enable the specified timeout to fire after the specified delay.
557 * Delay is given in milliseconds.
559 void
560 enable_timeout_after(TimeoutId id, int delay_ms)
562 TimestampTz now;
563 TimestampTz fin_time;
565 /* Disable timeout interrupts for safety. */
566 disable_alarm();
568 /* Queue the timeout at the appropriate time. */
569 now = GetCurrentTimestamp();
570 fin_time = TimestampTzPlusMilliseconds(now, delay_ms);
571 enable_timeout(id, now, fin_time, 0);
573 /* Set the timer interrupt. */
574 schedule_alarm(now);
578 * Enable the specified timeout to fire periodically, with the specified
579 * delay as the time between firings.
581 * Delay is given in milliseconds.
583 void
584 enable_timeout_every(TimeoutId id, TimestampTz fin_time, int delay_ms)
586 TimestampTz now;
588 /* Disable timeout interrupts for safety. */
589 disable_alarm();
591 /* Queue the timeout at the appropriate time. */
592 now = GetCurrentTimestamp();
593 enable_timeout(id, now, fin_time, delay_ms);
595 /* Set the timer interrupt. */
596 schedule_alarm(now);
600 * Enable the specified timeout to fire at the specified time.
602 * This is provided to support cases where there's a reason to calculate
603 * the timeout by reference to some point other than "now". If there isn't,
604 * use enable_timeout_after(), to avoid calling GetCurrentTimestamp() twice.
606 void
607 enable_timeout_at(TimeoutId id, TimestampTz fin_time)
609 TimestampTz now;
611 /* Disable timeout interrupts for safety. */
612 disable_alarm();
614 /* Queue the timeout at the appropriate time. */
615 now = GetCurrentTimestamp();
616 enable_timeout(id, now, fin_time, 0);
618 /* Set the timer interrupt. */
619 schedule_alarm(now);
623 * Enable multiple timeouts at once.
625 * This works like calling enable_timeout_after() and/or enable_timeout_at()
626 * multiple times. Use this to reduce the number of GetCurrentTimestamp()
627 * and setitimer() calls needed to establish multiple timeouts.
629 void
630 enable_timeouts(const EnableTimeoutParams *timeouts, int count)
632 TimestampTz now;
633 int i;
635 /* Disable timeout interrupts for safety. */
636 disable_alarm();
638 /* Queue the timeout(s) at the appropriate times. */
639 now = GetCurrentTimestamp();
641 for (i = 0; i < count; i++)
643 TimeoutId id = timeouts[i].id;
644 TimestampTz fin_time;
646 switch (timeouts[i].type)
648 case TMPARAM_AFTER:
649 fin_time = TimestampTzPlusMilliseconds(now,
650 timeouts[i].delay_ms);
651 enable_timeout(id, now, fin_time, 0);
652 break;
654 case TMPARAM_AT:
655 enable_timeout(id, now, timeouts[i].fin_time, 0);
656 break;
658 case TMPARAM_EVERY:
659 fin_time = TimestampTzPlusMilliseconds(now,
660 timeouts[i].delay_ms);
661 enable_timeout(id, now, fin_time, timeouts[i].delay_ms);
662 break;
664 default:
665 elog(ERROR, "unrecognized timeout type %d",
666 (int) timeouts[i].type);
667 break;
671 /* Set the timer interrupt. */
672 schedule_alarm(now);
676 * Cancel the specified timeout.
678 * The timeout's I've-been-fired indicator is reset,
679 * unless keep_indicator is true.
681 * When a timeout is canceled, any other active timeout remains in force.
682 * It's not an error to disable a timeout that is not enabled.
684 void
685 disable_timeout(TimeoutId id, bool keep_indicator)
687 /* Assert request is sane */
688 Assert(all_timeouts_initialized);
689 Assert(all_timeouts[id].timeout_handler != NULL);
691 /* Disable timeout interrupts for safety. */
692 disable_alarm();
694 /* Find the timeout and remove it from the active list. */
695 if (all_timeouts[id].active)
696 remove_timeout_index(find_active_timeout(id));
698 /* Mark it inactive, whether it was active or not. */
699 if (!keep_indicator)
700 all_timeouts[id].indicator = false;
702 /* Reschedule the interrupt, if any timeouts remain active. */
703 if (num_active_timeouts > 0)
704 schedule_alarm(GetCurrentTimestamp());
708 * Cancel multiple timeouts at once.
710 * The timeouts' I've-been-fired indicators are reset,
711 * unless timeouts[i].keep_indicator is true.
713 * This works like calling disable_timeout() multiple times.
714 * Use this to reduce the number of GetCurrentTimestamp()
715 * and setitimer() calls needed to cancel multiple timeouts.
717 void
718 disable_timeouts(const DisableTimeoutParams *timeouts, int count)
720 int i;
722 Assert(all_timeouts_initialized);
724 /* Disable timeout interrupts for safety. */
725 disable_alarm();
727 /* Cancel the timeout(s). */
728 for (i = 0; i < count; i++)
730 TimeoutId id = timeouts[i].id;
732 Assert(all_timeouts[id].timeout_handler != NULL);
734 if (all_timeouts[id].active)
735 remove_timeout_index(find_active_timeout(id));
737 if (!timeouts[i].keep_indicator)
738 all_timeouts[id].indicator = false;
741 /* Reschedule the interrupt, if any timeouts remain active. */
742 if (num_active_timeouts > 0)
743 schedule_alarm(GetCurrentTimestamp());
747 * Disable the signal handler, remove all timeouts from the active list,
748 * and optionally reset their timeout indicators.
750 void
751 disable_all_timeouts(bool keep_indicators)
753 int i;
755 disable_alarm();
758 * We used to disable the timer interrupt here, but in common usage
759 * patterns it's cheaper to leave it enabled; that may save us from having
760 * to enable it again shortly. See comments in schedule_alarm().
763 num_active_timeouts = 0;
765 for (i = 0; i < MAX_TIMEOUTS; i++)
767 all_timeouts[i].active = false;
768 if (!keep_indicators)
769 all_timeouts[i].indicator = false;
774 * Return true if the timeout is active (enabled and not yet fired)
776 * This is, of course, subject to race conditions, as the timeout could fire
777 * immediately after we look.
779 bool
780 get_timeout_active(TimeoutId id)
782 return all_timeouts[id].active;
786 * Return the timeout's I've-been-fired indicator
788 * If reset_indicator is true, reset the indicator when returning true.
789 * To avoid missing timeouts due to race conditions, we are careful not to
790 * reset the indicator when returning false.
792 bool
793 get_timeout_indicator(TimeoutId id, bool reset_indicator)
795 if (all_timeouts[id].indicator)
797 if (reset_indicator)
798 all_timeouts[id].indicator = false;
799 return true;
801 return false;
805 * Return the time when the timeout was most recently activated
807 * Note: will return 0 if timeout has never been activated in this process.
808 * However, we do *not* reset the start_time when a timeout occurs, so as
809 * not to create a race condition if SIGALRM fires just as some code is
810 * about to fetch the value.
812 TimestampTz
813 get_timeout_start_time(TimeoutId id)
815 return all_timeouts[id].start_time;
819 * Return the time when the timeout is, or most recently was, due to fire
821 * Note: will return 0 if timeout has never been activated in this process.
822 * However, we do *not* reset the fin_time when a timeout occurs, so as
823 * not to create a race condition if SIGALRM fires just as some code is
824 * about to fetch the value.
826 TimestampTz
827 get_timeout_finish_time(TimeoutId id)
829 return all_timeouts[id].fin_time;