PostgreSQL Source Code  git master
timeout.c
Go to the documentation of this file.
1 /*-------------------------------------------------------------------------
2  *
3  * timeout.c
4  * Routines to multiplex SIGALRM interrupts for multiple timeout reasons.
5  *
6  * Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group
7  * Portions Copyright (c) 1994, Regents of the University of California
8  *
9  *
10  * IDENTIFICATION
11  * src/backend/utils/misc/timeout.c
12  *
13  *-------------------------------------------------------------------------
14  */
15 #include "postgres.h"
16 
17 #include <sys/time.h>
18 
19 #include "miscadmin.h"
20 #include "storage/proc.h"
21 #include "utils/timeout.h"
22 #include "utils/timestamp.h"
23 
24 
25 /* Data about any one timeout reason */
26 typedef struct timeout_params
27 {
28  TimeoutId index; /* identifier of timeout reason */
29 
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 */
33 
34  /* callback function for timeout, or NULL if timeout not registered */
36 
37  TimestampTz start_time; /* time that timeout was last activated */
38  TimestampTz fin_time; /* time it is, or was last, due to fire */
40 
41 /*
42  * List of possible timeout reasons in the order of enum TimeoutId.
43  */
45 static bool all_timeouts_initialized = false;
46 
47 /*
48  * List of active timeouts ordered by their fin_time and priority.
49  * This list is subject to change by the interrupt handler, so it's volatile.
50  */
51 static volatile int num_active_timeouts = 0;
53 
54 /*
55  * Flag controlling whether the signal handler is allowed to do anything.
56  * We leave this "false" when we're not expecting interrupts, just in case.
57  *
58  * Note that we don't bother to reset any pending timer interrupt when we
59  * disable the signal handler; it's not really worth the cycles to do so,
60  * since the probability of the interrupt actually occurring while we have
61  * it disabled is low. See comments in schedule_alarm() about that.
62  */
63 static volatile sig_atomic_t alarm_enabled = false;
64 
65 #define disable_alarm() (alarm_enabled = false)
66 #define enable_alarm() (alarm_enabled = true)
67 
68 
69 /*****************************************************************************
70  * Internal helper functions
71  *
72  * For all of these, it is caller's responsibility to protect them from
73  * interruption by the signal handler. Generally, call disable_alarm()
74  * first to prevent interruption, then update state, and last call
75  * schedule_alarm(), which will re-enable the signal handler if needed.
76  *****************************************************************************/
77 
78 /*
79  * Find the index of a given timeout reason in the active array.
80  * If it's not there, return -1.
81  */
82 static int
84 {
85  int i;
86 
87  for (i = 0; i < num_active_timeouts; i++)
88  {
89  if (active_timeouts[i]->index == id)
90  return i;
91  }
92 
93  return -1;
94 }
95 
96 /*
97  * Insert specified timeout reason into the list of active timeouts
98  * at the given index.
99  */
100 static void
102 {
103  int i;
104 
106  elog(FATAL, "timeout index %d out of range 0..%d", index,
107  num_active_timeouts);
108 
109  Assert(!all_timeouts[id].active);
110  all_timeouts[id].active = true;
111 
112  for (i = num_active_timeouts - 1; i >= index; i--)
113  active_timeouts[i + 1] = active_timeouts[i];
114 
115  active_timeouts[index] = &all_timeouts[id];
116 
117  num_active_timeouts++;
118 }
119 
120 /*
121  * Remove the index'th element from the timeout list.
122  */
123 static void
125 {
126  int i;
127 
129  elog(FATAL, "timeout index %d out of range 0..%d", index,
130  num_active_timeouts - 1);
131 
132  Assert(active_timeouts[index]->active);
133  active_timeouts[index]->active = false;
134 
135  for (i = index + 1; i < num_active_timeouts; i++)
136  active_timeouts[i - 1] = active_timeouts[i];
137 
138  num_active_timeouts--;
139 }
140 
141 /*
142  * Enable the specified timeout reason
143  */
144 static void
146 {
147  int i;
148 
149  /* Assert request is sane */
151  Assert(all_timeouts[id].timeout_handler != NULL);
152 
153  /*
154  * If this timeout was already active, momentarily disable it. We
155  * interpret the call as a directive to reschedule the timeout.
156  */
157  if (all_timeouts[id].active)
159 
160  /*
161  * Find out the index where to insert the new timeout. We sort by
162  * fin_time, and for equal fin_time by priority.
163  */
164  for (i = 0; i < num_active_timeouts; i++)
165  {
166  timeout_params *old_timeout = active_timeouts[i];
167 
168  if (fin_time < old_timeout->fin_time)
169  break;
170  if (fin_time == old_timeout->fin_time && id < old_timeout->index)
171  break;
172  }
173 
174  /*
175  * Mark the timeout active, and insert it into the active list.
176  */
177  all_timeouts[id].indicator = false;
178  all_timeouts[id].start_time = now;
179  all_timeouts[id].fin_time = fin_time;
180 
181  insert_timeout(id, i);
182 }
183 
184 /*
185  * Schedule alarm for the next active timeout, if any
186  *
187  * We assume the caller has obtained the current time, or a close-enough
188  * approximation.
189  */
190 static void
192 {
193  if (num_active_timeouts > 0)
194  {
195  struct itimerval timeval;
196  long secs;
197  int usecs;
198 
199  MemSet(&timeval, 0, sizeof(struct itimerval));
200 
201  /* Get the time remaining till the nearest pending timeout */
202  TimestampDifference(now, active_timeouts[0]->fin_time,
203  &secs, &usecs);
204 
205  /*
206  * It's possible that the difference is less than a microsecond;
207  * ensure we don't cancel, rather than set, the interrupt.
208  */
209  if (secs == 0 && usecs == 0)
210  usecs = 1;
211 
212  timeval.it_value.tv_sec = secs;
213  timeval.it_value.tv_usec = usecs;
214 
215  /*
216  * We must enable the signal handler before calling setitimer(); if we
217  * did it in the other order, we'd have a race condition wherein the
218  * interrupt could occur before we can set alarm_enabled, so that the
219  * signal handler would fail to do anything.
220  *
221  * Because we didn't bother to reset the timer in disable_alarm(),
222  * it's possible that a previously-set interrupt will fire between
223  * enable_alarm() and setitimer(). This is safe, however. There are
224  * two possible outcomes:
225  *
226  * 1. The signal handler finds nothing to do (because the nearest
227  * timeout event is still in the future). It will re-set the timer
228  * and return. Then we'll overwrite the timer value with a new one.
229  * This will mean that the timer fires a little later than we
230  * intended, but only by the amount of time it takes for the signal
231  * handler to do nothing useful, which shouldn't be much.
232  *
233  * 2. The signal handler executes and removes one or more timeout
234  * events. When it returns, either the queue is now empty or the
235  * frontmost event is later than the one we looked at above. So we'll
236  * overwrite the timer value with one that is too soon (plus or minus
237  * the signal handler's execution time), causing a useless interrupt
238  * to occur. But the handler will then re-set the timer and
239  * everything will still work as expected.
240  *
241  * Since these cases are of very low probability (the window here
242  * being quite narrow), it's not worth adding cycles to the mainline
243  * code to prevent occasional wasted interrupts.
244  */
245  enable_alarm();
246 
247  /* Set the alarm timer */
248  if (setitimer(ITIMER_REAL, &timeval, NULL) != 0)
249  elog(FATAL, "could not enable SIGALRM timer: %m");
250  }
251 }
252 
253 
254 /*****************************************************************************
255  * Signal handler
256  *****************************************************************************/
257 
258 /*
259  * Signal handler for SIGALRM
260  *
261  * Process any active timeout reasons and then reschedule the interrupt
262  * as needed.
263  */
264 static void
266 {
267  int save_errno = errno;
268 
269  /*
270  * Bump the holdoff counter, to make sure nothing we call will process
271  * interrupts directly. No timeout handler should do that, but these
272  * failures are hard to debug, so better be sure.
273  */
274  HOLD_INTERRUPTS();
275 
276  /*
277  * SIGALRM is always cause for waking anything waiting on the process
278  * latch.
279  */
280  SetLatch(MyLatch);
281 
282  /*
283  * Fire any pending timeouts, but only if we're enabled to do so.
284  */
285  if (alarm_enabled)
286  {
287  /*
288  * Disable alarms, just in case this platform allows signal handlers
289  * to interrupt themselves. schedule_alarm() will re-enable if
290  * appropriate.
291  */
292  disable_alarm();
293 
294  if (num_active_timeouts > 0)
295  {
297 
298  /* While the first pending timeout has been reached ... */
299  while (num_active_timeouts > 0 &&
300  now >= active_timeouts[0]->fin_time)
301  {
302  timeout_params *this_timeout = active_timeouts[0];
303 
304  /* Remove it from the active list */
306 
307  /* Mark it as fired */
308  this_timeout->indicator = true;
309 
310  /* And call its handler function */
311  this_timeout->timeout_handler();
312 
313  /*
314  * The handler might not take negligible time (CheckDeadLock
315  * for instance isn't too cheap), so let's update our idea of
316  * "now" after each one.
317  */
318  now = GetCurrentTimestamp();
319  }
320 
321  /* Done firing timeouts, so reschedule next interrupt if any */
322  schedule_alarm(now);
323  }
324  }
325 
327 
328  errno = save_errno;
329 }
330 
331 
332 /*****************************************************************************
333  * Public API
334  *****************************************************************************/
335 
336 /*
337  * Initialize timeout module.
338  *
339  * This must be called in every process that wants to use timeouts.
340  *
341  * If the process was forked from another one that was also using this
342  * module, be sure to call this before re-enabling signals; else handlers
343  * meant to run in the parent process might get invoked in this one.
344  */
345 void
347 {
348  int i;
349 
350  /* Initialize, or re-initialize, all local state */
351  disable_alarm();
352 
354 
355  for (i = 0; i < MAX_TIMEOUTS; i++)
356  {
357  all_timeouts[i].index = i;
358  all_timeouts[i].active = false;
359  all_timeouts[i].indicator = false;
360  all_timeouts[i].timeout_handler = NULL;
361  all_timeouts[i].start_time = 0;
362  all_timeouts[i].fin_time = 0;
363  }
364 
366 
367  /* Now establish the signal handler */
369 }
370 
371 /*
372  * Register a timeout reason
373  *
374  * For predefined timeouts, this just registers the callback function.
375  *
376  * For user-defined timeouts, pass id == USER_TIMEOUT; we then allocate and
377  * return a timeout ID.
378  */
379 TimeoutId
381 {
383 
384  /* There's no need to disable the signal handler here. */
385 
386  if (id >= USER_TIMEOUT)
387  {
388  /* Allocate a user-defined timeout reason */
389  for (id = USER_TIMEOUT; id < MAX_TIMEOUTS; id++)
390  if (all_timeouts[id].timeout_handler == NULL)
391  break;
392  if (id >= MAX_TIMEOUTS)
393  ereport(FATAL,
394  (errcode(ERRCODE_CONFIGURATION_LIMIT_EXCEEDED),
395  errmsg("cannot add more timeout reasons")));
396  }
397 
398  Assert(all_timeouts[id].timeout_handler == NULL);
399 
400  all_timeouts[id].timeout_handler = handler;
401 
402  return id;
403 }
404 
405 /*
406  * Reschedule any pending SIGALRM interrupt.
407  *
408  * This can be used during error recovery in case query cancel resulted in loss
409  * of a SIGALRM event (due to longjmp'ing out of handle_sig_alarm before it
410  * could do anything). But note it's not necessary if any of the public
411  * enable_ or disable_timeout functions are called in the same area, since
412  * those all do schedule_alarm() internally if needed.
413  */
414 void
416 {
417  /* For flexibility, allow this to be called before we're initialized. */
419  return;
420 
421  /* Disable timeout interrupts for safety. */
422  disable_alarm();
423 
424  /* Reschedule the interrupt, if any timeouts remain active. */
425  if (num_active_timeouts > 0)
427 }
428 
429 /*
430  * Enable the specified timeout to fire after the specified delay.
431  *
432  * Delay is given in milliseconds.
433  */
434 void
436 {
439 
440  /* Disable timeout interrupts for safety. */
441  disable_alarm();
442 
443  /* Queue the timeout at the appropriate time. */
444  now = GetCurrentTimestamp();
445  fin_time = TimestampTzPlusMilliseconds(now, delay_ms);
446  enable_timeout(id, now, fin_time);
447 
448  /* Set the timer interrupt. */
449  schedule_alarm(now);
450 }
451 
452 /*
453  * Enable the specified timeout to fire at the specified time.
454  *
455  * This is provided to support cases where there's a reason to calculate
456  * the timeout by reference to some point other than "now". If there isn't,
457  * use enable_timeout_after(), to avoid calling GetCurrentTimestamp() twice.
458  */
459 void
461 {
463 
464  /* Disable timeout interrupts for safety. */
465  disable_alarm();
466 
467  /* Queue the timeout at the appropriate time. */
468  now = GetCurrentTimestamp();
469  enable_timeout(id, now, fin_time);
470 
471  /* Set the timer interrupt. */
472  schedule_alarm(now);
473 }
474 
475 /*
476  * Enable multiple timeouts at once.
477  *
478  * This works like calling enable_timeout_after() and/or enable_timeout_at()
479  * multiple times. Use this to reduce the number of GetCurrentTimestamp()
480  * and setitimer() calls needed to establish multiple timeouts.
481  */
482 void
483 enable_timeouts(const EnableTimeoutParams *timeouts, int count)
484 {
486  int i;
487 
488  /* Disable timeout interrupts for safety. */
489  disable_alarm();
490 
491  /* Queue the timeout(s) at the appropriate times. */
492  now = GetCurrentTimestamp();
493 
494  for (i = 0; i < count; i++)
495  {
496  TimeoutId id = timeouts[i].id;
498 
499  switch (timeouts[i].type)
500  {
501  case TMPARAM_AFTER:
502  fin_time = TimestampTzPlusMilliseconds(now,
503  timeouts[i].delay_ms);
504  enable_timeout(id, now, fin_time);
505  break;
506 
507  case TMPARAM_AT:
508  enable_timeout(id, now, timeouts[i].fin_time);
509  break;
510 
511  default:
512  elog(ERROR, "unrecognized timeout type %d",
513  (int) timeouts[i].type);
514  break;
515  }
516  }
517 
518  /* Set the timer interrupt. */
519  schedule_alarm(now);
520 }
521 
522 /*
523  * Cancel the specified timeout.
524  *
525  * The timeout's I've-been-fired indicator is reset,
526  * unless keep_indicator is true.
527  *
528  * When a timeout is canceled, any other active timeout remains in force.
529  * It's not an error to disable a timeout that is not enabled.
530  */
531 void
532 disable_timeout(TimeoutId id, bool keep_indicator)
533 {
534  /* Assert request is sane */
536  Assert(all_timeouts[id].timeout_handler != NULL);
537 
538  /* Disable timeout interrupts for safety. */
539  disable_alarm();
540 
541  /* Find the timeout and remove it from the active list. */
542  if (all_timeouts[id].active)
544 
545  /* Mark it inactive, whether it was active or not. */
546  if (!keep_indicator)
547  all_timeouts[id].indicator = false;
548 
549  /* Reschedule the interrupt, if any timeouts remain active. */
550  if (num_active_timeouts > 0)
552 }
553 
554 /*
555  * Cancel multiple timeouts at once.
556  *
557  * The timeouts' I've-been-fired indicators are reset,
558  * unless timeouts[i].keep_indicator is true.
559  *
560  * This works like calling disable_timeout() multiple times.
561  * Use this to reduce the number of GetCurrentTimestamp()
562  * and setitimer() calls needed to cancel multiple timeouts.
563  */
564 void
565 disable_timeouts(const DisableTimeoutParams *timeouts, int count)
566 {
567  int i;
568 
570 
571  /* Disable timeout interrupts for safety. */
572  disable_alarm();
573 
574  /* Cancel the timeout(s). */
575  for (i = 0; i < count; i++)
576  {
577  TimeoutId id = timeouts[i].id;
578 
579  Assert(all_timeouts[id].timeout_handler != NULL);
580 
581  if (all_timeouts[id].active)
583 
584  if (!timeouts[i].keep_indicator)
585  all_timeouts[id].indicator = false;
586  }
587 
588  /* Reschedule the interrupt, if any timeouts remain active. */
589  if (num_active_timeouts > 0)
591 }
592 
593 /*
594  * Disable SIGALRM and remove all timeouts from the active list,
595  * and optionally reset their timeout indicators.
596  */
597 void
598 disable_all_timeouts(bool keep_indicators)
599 {
600  int i;
601 
602  disable_alarm();
603 
604  /*
605  * Only bother to reset the timer if we think it's active. We could just
606  * let the interrupt happen anyway, but it's probably a bit cheaper to do
607  * setitimer() than to let the useless interrupt happen.
608  */
609  if (num_active_timeouts > 0)
610  {
611  struct itimerval timeval;
612 
613  MemSet(&timeval, 0, sizeof(struct itimerval));
614  if (setitimer(ITIMER_REAL, &timeval, NULL) != 0)
615  elog(FATAL, "could not disable SIGALRM timer: %m");
616  }
617 
619 
620  for (i = 0; i < MAX_TIMEOUTS; i++)
621  {
622  all_timeouts[i].active = false;
623  if (!keep_indicators)
624  all_timeouts[i].indicator = false;
625  }
626 }
627 
628 /*
629  * Return true if the timeout is active (enabled and not yet fired)
630  *
631  * This is, of course, subject to race conditions, as the timeout could fire
632  * immediately after we look.
633  */
634 bool
636 {
637  return all_timeouts[id].active;
638 }
639 
640 /*
641  * Return the timeout's I've-been-fired indicator
642  *
643  * If reset_indicator is true, reset the indicator when returning true.
644  * To avoid missing timeouts due to race conditions, we are careful not to
645  * reset the indicator when returning false.
646  */
647 bool
648 get_timeout_indicator(TimeoutId id, bool reset_indicator)
649 {
650  if (all_timeouts[id].indicator)
651  {
652  if (reset_indicator)
653  all_timeouts[id].indicator = false;
654  return true;
655  }
656  return false;
657 }
658 
659 /*
660  * Return the time when the timeout was most recently activated
661  *
662  * Note: will return 0 if timeout has never been activated in this process.
663  * However, we do *not* reset the start_time when a timeout occurs, so as
664  * not to create a race condition if SIGALRM fires just as some code is
665  * about to fetch the value.
666  */
669 {
670  return all_timeouts[id].start_time;
671 }
672 
673 /*
674  * Return the time when the timeout is, or most recently was, due to fire
675  *
676  * Note: will return 0 if timeout has never been activated in this process.
677  * However, we do *not* reset the fin_time when a timeout occurs, so as
678  * not to create a race condition if SIGALRM fires just as some code is
679  * about to fetch the value.
680  */
683 {
684  return all_timeouts[id].fin_time;
685 }
static bool all_timeouts_initialized
Definition: timeout.c:45
TimestampTz get_timeout_start_time(TimeoutId id)
Definition: timeout.c:668
void InitializeTimeouts(void)
Definition: timeout.c:346
static void remove_timeout_index(int index)
Definition: timeout.c:124
TimeoutId id
Definition: timeout.h:54
TimestampTz get_timeout_finish_time(TimeoutId id)
Definition: timeout.c:682
#define enable_alarm()
Definition: timeout.c:66
TimestampTz GetCurrentTimestamp(void)
Definition: timestamp.c:1583
int64 TimestampTz
Definition: timestamp.h:39
TimestampTz fin_time
Definition: timeout.c:38
int errcode(int sqlerrcode)
Definition: elog.c:608
struct timeval it_value
Definition: win32_port.h:186
#define MemSet(start, val, len)
Definition: c.h:962
#define disable_alarm()
Definition: timeout.c:65
timeout_handler_proc timeout_handler
Definition: timeout.c:35
volatile bool indicator
Definition: timeout.c:32
void SetLatch(Latch *latch)
Definition: latch.c:436
void disable_timeouts(const DisableTimeoutParams *timeouts, int count)
Definition: timeout.c:565
void reschedule_timeouts(void)
Definition: timeout.c:415
volatile bool active
Definition: timeout.c:31
Definition: type.h:89
#define RESUME_INTERRUPTS()
Definition: miscadmin.h:118
void enable_timeouts(const EnableTimeoutParams *timeouts, int count)
Definition: timeout.c:483
void(* timeout_handler_proc)(void)
Definition: timeout.h:41
void enable_timeout_at(TimeoutId id, TimestampTz fin_time)
Definition: timeout.c:460
void disable_all_timeouts(bool keep_indicators)
Definition: timeout.c:598
#define ERROR
Definition: elog.h:43
#define FATAL
Definition: elog.h:52
TimeoutId id
Definition: timeout.h:65
static timeout_params all_timeouts[MAX_TIMEOUTS]
Definition: timeout.c:44
static void enable_timeout(TimeoutId id, TimestampTz now, TimestampTz fin_time)
Definition: timeout.c:145
TimestampTz start_time
Definition: timeout.c:37
static void insert_timeout(TimeoutId id, int index)
Definition: timeout.c:101
int setitimer(int which, const struct itimerval *value, struct itimerval *ovalue)
Definition: timer.c:86
#define ereport(elevel, rest)
Definition: elog.h:141
static volatile sig_atomic_t alarm_enabled
Definition: timeout.c:63
static void schedule_alarm(TimestampTz now)
Definition: timeout.c:191
bool get_timeout_indicator(TimeoutId id, bool reset_indicator)
Definition: timeout.c:648
#define TimestampTzPlusMilliseconds(tz, ms)
Definition: timestamp.h:56
pqsigfunc pqsignal(int signum, pqsigfunc handler)
Definition: signal.c:170
TimeoutId RegisterTimeout(TimeoutId id, timeout_handler_proc handler)
Definition: timeout.c:380
void enable_timeout_after(TimeoutId id, int delay_ms)
Definition: timeout.c:435
TimeoutId index
Definition: timeout.c:28
#define SIGNAL_ARGS
Definition: c.h:1288
#define Assert(condition)
Definition: c.h:739
TimeoutId
Definition: timeout.h:23
#define SIGALRM
Definition: win32_port.h:160
static timeout_params *volatile active_timeouts[MAX_TIMEOUTS]
Definition: timeout.c:52
static int find_active_timeout(TimeoutId id)
Definition: timeout.c:83
int errmsg(const char *fmt,...)
Definition: elog.c:822
#define HOLD_INTERRUPTS()
Definition: miscadmin.h:116
#define elog(elevel,...)
Definition: elog.h:228
int i
struct timeout_params timeout_params
struct Latch * MyLatch
Definition: globals.c:54
void disable_timeout(TimeoutId id, bool keep_indicator)
Definition: timeout.c:532
void TimestampDifference(TimestampTz start_time, TimestampTz stop_time, long *secs, int *microsecs)
Definition: timestamp.c:1657
static volatile int num_active_timeouts
Definition: timeout.c:51
Datum now(PG_FUNCTION_ARGS)
Definition: timestamp.c:1547
#define ITIMER_REAL
Definition: win32_port.h:182
bool get_timeout_active(TimeoutId id)
Definition: timeout.c:635
static void handle_sig_alarm(SIGNAL_ARGS)
Definition: timeout.c:265