PostgreSQL Source Code  git master
timeout.c File Reference
#include "postgres.h"
#include <sys/time.h>
#include "miscadmin.h"
#include "storage/proc.h"
#include "utils/timeout.h"
#include "utils/timestamp.h"
Include dependency graph for timeout.c:

Go to the source code of this file.

Data Structures

struct  timeout_params
 

Macros

#define disable_alarm()   (alarm_enabled = false)
 
#define enable_alarm()   (alarm_enabled = true)
 

Typedefs

typedef struct timeout_params timeout_params
 

Functions

static int find_active_timeout (TimeoutId id)
 
static void insert_timeout (TimeoutId id, int index)
 
static void remove_timeout_index (int index)
 
static void enable_timeout (TimeoutId id, TimestampTz now, TimestampTz fin_time)
 
static void schedule_alarm (TimestampTz now)
 
static void handle_sig_alarm (SIGNAL_ARGS)
 
void InitializeTimeouts (void)
 
TimeoutId RegisterTimeout (TimeoutId id, timeout_handler_proc handler)
 
void reschedule_timeouts (void)
 
void enable_timeout_after (TimeoutId id, int delay_ms)
 
void enable_timeout_at (TimeoutId id, TimestampTz fin_time)
 
void enable_timeouts (const EnableTimeoutParams *timeouts, int count)
 
void disable_timeout (TimeoutId id, bool keep_indicator)
 
void disable_timeouts (const DisableTimeoutParams *timeouts, int count)
 
void disable_all_timeouts (bool keep_indicators)
 
bool get_timeout_active (TimeoutId id)
 
bool get_timeout_indicator (TimeoutId id, bool reset_indicator)
 
TimestampTz get_timeout_start_time (TimeoutId id)
 
TimestampTz get_timeout_finish_time (TimeoutId id)
 

Variables

static timeout_params all_timeouts [MAX_TIMEOUTS]
 
static bool all_timeouts_initialized = false
 
static volatile int num_active_timeouts = 0
 
static timeout_params *volatile active_timeouts [MAX_TIMEOUTS]
 
static volatile sig_atomic_t alarm_enabled = false
 
static volatile sig_atomic_t signal_pending = false
 
static TimestampTz signal_due_at = 0
 

Macro Definition Documentation

◆ disable_alarm

◆ enable_alarm

#define enable_alarm ( )    (alarm_enabled = true)

Definition at line 69 of file timeout.c.

Referenced by schedule_alarm().

Typedef Documentation

◆ timeout_params

Function Documentation

◆ disable_all_timeouts()

void disable_all_timeouts ( bool  keep_indicators)

Definition at line 687 of file timeout.c.

References timeout_params::active, disable_alarm, i, timeout_params::indicator, MAX_TIMEOUTS, and num_active_timeouts.

Referenced by AutoVacLauncherMain(), PostgresMain(), ResolveRecoveryConflictWithBufferPin(), and ResolveRecoveryConflictWithLock().

688 {
689  int i;
690 
691  disable_alarm();
692 
693  /*
694  * We used to disable the timer interrupt here, but in common usage
695  * patterns it's cheaper to leave it enabled; that may save us from having
696  * to enable it again shortly. See comments in schedule_alarm().
697  */
698 
700 
701  for (i = 0; i < MAX_TIMEOUTS; i++)
702  {
703  all_timeouts[i].active = false;
704  if (!keep_indicators)
705  all_timeouts[i].indicator = false;
706  }
707 }
#define disable_alarm()
Definition: timeout.c:68
volatile bool indicator
Definition: timeout.c:32
volatile bool active
Definition: timeout.c:31
static timeout_params all_timeouts[MAX_TIMEOUTS]
Definition: timeout.c:44
int i
static volatile int num_active_timeouts
Definition: timeout.c:51

◆ disable_timeout()

void disable_timeout ( TimeoutId  id,
bool  keep_indicator 
)

Definition at line 621 of file timeout.c.

References timeout_params::active, all_timeouts_initialized, Assert, disable_alarm, find_active_timeout(), GetCurrentTimestamp(), timeout_params::indicator, num_active_timeouts, remove_timeout_index(), schedule_alarm(), and timeout_params::timeout_handler.

Referenced by BackendInitialize(), disable_statement_timeout(), enable_statement_timeout(), PerformAuthentication(), PostgresMain(), ProcSleep(), and StandbyTimeoutHandler().

622 {
623  /* Assert request is sane */
625  Assert(all_timeouts[id].timeout_handler != NULL);
626 
627  /* Disable timeout interrupts for safety. */
628  disable_alarm();
629 
630  /* Find the timeout and remove it from the active list. */
631  if (all_timeouts[id].active)
633 
634  /* Mark it inactive, whether it was active or not. */
635  if (!keep_indicator)
636  all_timeouts[id].indicator = false;
637 
638  /* Reschedule the interrupt, if any timeouts remain active. */
639  if (num_active_timeouts > 0)
641 }
static bool all_timeouts_initialized
Definition: timeout.c:45
static void remove_timeout_index(int index)
Definition: timeout.c:135
TimestampTz GetCurrentTimestamp(void)
Definition: timestamp.c:1578
#define disable_alarm()
Definition: timeout.c:68
volatile bool indicator
Definition: timeout.c:32
static timeout_params all_timeouts[MAX_TIMEOUTS]
Definition: timeout.c:44
static void schedule_alarm(TimestampTz now)
Definition: timeout.c:206
#define Assert(condition)
Definition: c.h:804
static int find_active_timeout(TimeoutId id)
Definition: timeout.c:94
static volatile int num_active_timeouts
Definition: timeout.c:51

◆ disable_timeouts()

void disable_timeouts ( const DisableTimeoutParams timeouts,
int  count 
)

Definition at line 654 of file timeout.c.

References timeout_params::active, all_timeouts_initialized, Assert, disable_alarm, find_active_timeout(), GetCurrentTimestamp(), i, DisableTimeoutParams::id, timeout_params::indicator, num_active_timeouts, remove_timeout_index(), schedule_alarm(), and timeout_params::timeout_handler.

Referenced by LockErrorCleanup(), and ProcSleep().

655 {
656  int i;
657 
659 
660  /* Disable timeout interrupts for safety. */
661  disable_alarm();
662 
663  /* Cancel the timeout(s). */
664  for (i = 0; i < count; i++)
665  {
666  TimeoutId id = timeouts[i].id;
667 
668  Assert(all_timeouts[id].timeout_handler != NULL);
669 
670  if (all_timeouts[id].active)
672 
673  if (!timeouts[i].keep_indicator)
674  all_timeouts[id].indicator = false;
675  }
676 
677  /* Reschedule the interrupt, if any timeouts remain active. */
678  if (num_active_timeouts > 0)
680 }
static bool all_timeouts_initialized
Definition: timeout.c:45
static void remove_timeout_index(int index)
Definition: timeout.c:135
TimestampTz GetCurrentTimestamp(void)
Definition: timestamp.c:1578
#define disable_alarm()
Definition: timeout.c:68
volatile bool indicator
Definition: timeout.c:32
TimeoutId id
Definition: timeout.h:66
static timeout_params all_timeouts[MAX_TIMEOUTS]
Definition: timeout.c:44
static void schedule_alarm(TimestampTz now)
Definition: timeout.c:206
#define Assert(condition)
Definition: c.h:804
TimeoutId
Definition: timeout.h:23
static int find_active_timeout(TimeoutId id)
Definition: timeout.c:94
int i
static volatile int num_active_timeouts
Definition: timeout.c:51

◆ enable_timeout()

static void enable_timeout ( TimeoutId  id,
TimestampTz  now,
TimestampTz  fin_time 
)
static

Definition at line 156 of file timeout.c.

References timeout_params::active, all_timeouts_initialized, Assert, timeout_params::fin_time, find_active_timeout(), i, timeout_params::indicator, insert_timeout(), now(), num_active_timeouts, remove_timeout_index(), timeout_params::start_time, and timeout_params::timeout_handler.

Referenced by enable_timeout_after(), enable_timeout_at(), and enable_timeouts().

157 {
158  int i;
159 
160  /* Assert request is sane */
162  Assert(all_timeouts[id].timeout_handler != NULL);
163 
164  /*
165  * If this timeout was already active, momentarily disable it. We
166  * interpret the call as a directive to reschedule the timeout.
167  */
168  if (all_timeouts[id].active)
170 
171  /*
172  * Find out the index where to insert the new timeout. We sort by
173  * fin_time, and for equal fin_time by priority.
174  */
175  for (i = 0; i < num_active_timeouts; i++)
176  {
177  timeout_params *old_timeout = active_timeouts[i];
178 
179  if (fin_time < old_timeout->fin_time)
180  break;
181  if (fin_time == old_timeout->fin_time && id < old_timeout->index)
182  break;
183  }
184 
185  /*
186  * Mark the timeout active, and insert it into the active list.
187  */
188  all_timeouts[id].indicator = false;
190  all_timeouts[id].fin_time = fin_time;
191 
192  insert_timeout(id, i);
193 }
static bool all_timeouts_initialized
Definition: timeout.c:45
static void remove_timeout_index(int index)
Definition: timeout.c:135
TimestampTz fin_time
Definition: timeout.c:38
volatile bool indicator
Definition: timeout.c:32
Definition: type.h:89
static timeout_params all_timeouts[MAX_TIMEOUTS]
Definition: timeout.c:44
TimestampTz start_time
Definition: timeout.c:37
static void insert_timeout(TimeoutId id, int index)
Definition: timeout.c:112
#define Assert(condition)
Definition: c.h:804
static timeout_params *volatile active_timeouts[MAX_TIMEOUTS]
Definition: timeout.c:52
static int find_active_timeout(TimeoutId id)
Definition: timeout.c:94
int i
static volatile int num_active_timeouts
Definition: timeout.c:51
Datum now(PG_FUNCTION_ARGS)
Definition: timestamp.c:1542

◆ enable_timeout_after()

void enable_timeout_after ( TimeoutId  id,
int  delay_ms 
)

Definition at line 524 of file timeout.c.

References disable_alarm, enable_timeout(), timeout_params::fin_time, GetCurrentTimestamp(), now(), schedule_alarm(), and TimestampTzPlusMilliseconds.

Referenced by BackendInitialize(), enable_statement_timeout(), PerformAuthentication(), PostgresMain(), and ProcSleep().

525 {
527  TimestampTz fin_time;
528 
529  /* Disable timeout interrupts for safety. */
530  disable_alarm();
531 
532  /* Queue the timeout at the appropriate time. */
533  now = GetCurrentTimestamp();
534  fin_time = TimestampTzPlusMilliseconds(now, delay_ms);
535  enable_timeout(id, now, fin_time);
536 
537  /* Set the timer interrupt. */
538  schedule_alarm(now);
539 }
TimestampTz GetCurrentTimestamp(void)
Definition: timestamp.c:1578
int64 TimestampTz
Definition: timestamp.h:39
#define disable_alarm()
Definition: timeout.c:68
static void enable_timeout(TimeoutId id, TimestampTz now, TimestampTz fin_time)
Definition: timeout.c:156
static void schedule_alarm(TimestampTz now)
Definition: timeout.c:206
#define TimestampTzPlusMilliseconds(tz, ms)
Definition: timestamp.h:56
Datum now(PG_FUNCTION_ARGS)
Definition: timestamp.c:1542

◆ enable_timeout_at()

void enable_timeout_at ( TimeoutId  id,
TimestampTz  fin_time 
)

Definition at line 549 of file timeout.c.

References disable_alarm, enable_timeout(), GetCurrentTimestamp(), now(), and schedule_alarm().

550 {
552 
553  /* Disable timeout interrupts for safety. */
554  disable_alarm();
555 
556  /* Queue the timeout at the appropriate time. */
557  now = GetCurrentTimestamp();
558  enable_timeout(id, now, fin_time);
559 
560  /* Set the timer interrupt. */
561  schedule_alarm(now);
562 }
TimestampTz GetCurrentTimestamp(void)
Definition: timestamp.c:1578
int64 TimestampTz
Definition: timestamp.h:39
#define disable_alarm()
Definition: timeout.c:68
static void enable_timeout(TimeoutId id, TimestampTz now, TimestampTz fin_time)
Definition: timeout.c:156
static void schedule_alarm(TimestampTz now)
Definition: timeout.c:206
Datum now(PG_FUNCTION_ARGS)
Definition: timestamp.c:1542

◆ enable_timeouts()

void enable_timeouts ( const EnableTimeoutParams timeouts,
int  count 
)

Definition at line 572 of file timeout.c.

References disable_alarm, elog, enable_timeout(), ERROR, timeout_params::fin_time, GetCurrentTimestamp(), i, EnableTimeoutParams::id, now(), schedule_alarm(), TimestampTzPlusMilliseconds, TMPARAM_AFTER, TMPARAM_AT, and generate_unaccent_rules::type.

Referenced by ProcSleep(), ResolveRecoveryConflictWithBufferPin(), and ResolveRecoveryConflictWithLock().

573 {
575  int i;
576 
577  /* Disable timeout interrupts for safety. */
578  disable_alarm();
579 
580  /* Queue the timeout(s) at the appropriate times. */
581  now = GetCurrentTimestamp();
582 
583  for (i = 0; i < count; i++)
584  {
585  TimeoutId id = timeouts[i].id;
586  TimestampTz fin_time;
587 
588  switch (timeouts[i].type)
589  {
590  case TMPARAM_AFTER:
591  fin_time = TimestampTzPlusMilliseconds(now,
592  timeouts[i].delay_ms);
593  enable_timeout(id, now, fin_time);
594  break;
595 
596  case TMPARAM_AT:
597  enable_timeout(id, now, timeouts[i].fin_time);
598  break;
599 
600  default:
601  elog(ERROR, "unrecognized timeout type %d",
602  (int) timeouts[i].type);
603  break;
604  }
605  }
606 
607  /* Set the timer interrupt. */
608  schedule_alarm(now);
609 }
TimeoutId id
Definition: timeout.h:55
TimestampTz GetCurrentTimestamp(void)
Definition: timestamp.c:1578
int64 TimestampTz
Definition: timestamp.h:39
#define disable_alarm()
Definition: timeout.c:68
#define ERROR
Definition: elog.h:45
static void enable_timeout(TimeoutId id, TimestampTz now, TimestampTz fin_time)
Definition: timeout.c:156
static void schedule_alarm(TimestampTz now)
Definition: timeout.c:206
#define TimestampTzPlusMilliseconds(tz, ms)
Definition: timestamp.h:56
TimeoutId
Definition: timeout.h:23
#define elog(elevel,...)
Definition: elog.h:227
int i
Datum now(PG_FUNCTION_ARGS)
Definition: timestamp.c:1542

◆ find_active_timeout()

static int find_active_timeout ( TimeoutId  id)
static

Definition at line 94 of file timeout.c.

References i, and num_active_timeouts.

Referenced by disable_timeout(), disable_timeouts(), and enable_timeout().

95 {
96  int i;
97 
98  for (i = 0; i < num_active_timeouts; i++)
99  {
100  if (active_timeouts[i]->index == id)
101  return i;
102  }
103 
104  return -1;
105 }
Definition: type.h:89
static timeout_params *volatile active_timeouts[MAX_TIMEOUTS]
Definition: timeout.c:52
int i
static volatile int num_active_timeouts
Definition: timeout.c:51

◆ get_timeout_active()

bool get_timeout_active ( TimeoutId  id)

Definition at line 716 of file timeout.c.

References timeout_params::active.

Referenced by disable_statement_timeout(), and enable_statement_timeout().

717 {
718  return all_timeouts[id].active;
719 }
volatile bool active
Definition: timeout.c:31
static timeout_params all_timeouts[MAX_TIMEOUTS]
Definition: timeout.c:44

◆ get_timeout_finish_time()

TimestampTz get_timeout_finish_time ( TimeoutId  id)

Definition at line 763 of file timeout.c.

References timeout_params::fin_time.

Referenced by ProcessInterrupts().

764 {
765  return all_timeouts[id].fin_time;
766 }
TimestampTz fin_time
Definition: timeout.c:38
static timeout_params all_timeouts[MAX_TIMEOUTS]
Definition: timeout.c:44

◆ get_timeout_indicator()

bool get_timeout_indicator ( TimeoutId  id,
bool  reset_indicator 
)

Definition at line 729 of file timeout.c.

References timeout_params::indicator.

Referenced by ProcessInterrupts().

730 {
731  if (all_timeouts[id].indicator)
732  {
733  if (reset_indicator)
734  all_timeouts[id].indicator = false;
735  return true;
736  }
737  return false;
738 }
volatile bool indicator
Definition: timeout.c:32
static timeout_params all_timeouts[MAX_TIMEOUTS]
Definition: timeout.c:44

◆ get_timeout_start_time()

TimestampTz get_timeout_start_time ( TimeoutId  id)

Definition at line 749 of file timeout.c.

References timeout_params::start_time.

Referenced by ProcSleep().

750 {
751  return all_timeouts[id].start_time;
752 }
static timeout_params all_timeouts[MAX_TIMEOUTS]
Definition: timeout.c:44
TimestampTz start_time
Definition: timeout.c:37

◆ handle_sig_alarm()

static void handle_sig_alarm ( SIGNAL_ARGS  )
static

Definition at line 348 of file timeout.c.

References alarm_enabled, disable_alarm, timeout_params::fin_time, GetCurrentTimestamp(), HOLD_INTERRUPTS, timeout_params::indicator, MyLatch, now(), num_active_timeouts, remove_timeout_index(), RESUME_INTERRUPTS, schedule_alarm(), SetLatch(), signal_pending, and timeout_params::timeout_handler.

Referenced by InitializeTimeouts().

349 {
350  int save_errno = errno;
351 
352  /*
353  * Bump the holdoff counter, to make sure nothing we call will process
354  * interrupts directly. No timeout handler should do that, but these
355  * failures are hard to debug, so better be sure.
356  */
357  HOLD_INTERRUPTS();
358 
359  /*
360  * SIGALRM is always cause for waking anything waiting on the process
361  * latch.
362  */
363  SetLatch(MyLatch);
364 
365  /*
366  * Always reset signal_pending, even if !alarm_enabled, since indeed no
367  * signal is now pending.
368  */
369  signal_pending = false;
370 
371  /*
372  * Fire any pending timeouts, but only if we're enabled to do so.
373  */
374  if (alarm_enabled)
375  {
376  /*
377  * Disable alarms, just in case this platform allows signal handlers
378  * to interrupt themselves. schedule_alarm() will re-enable if
379  * appropriate.
380  */
381  disable_alarm();
382 
383  if (num_active_timeouts > 0)
384  {
386 
387  /* While the first pending timeout has been reached ... */
388  while (num_active_timeouts > 0 &&
389  now >= active_timeouts[0]->fin_time)
390  {
391  timeout_params *this_timeout = active_timeouts[0];
392 
393  /* Remove it from the active list */
395 
396  /* Mark it as fired */
397  this_timeout->indicator = true;
398 
399  /* And call its handler function */
400  this_timeout->timeout_handler();
401 
402  /*
403  * The handler might not take negligible time (CheckDeadLock
404  * for instance isn't too cheap), so let's update our idea of
405  * "now" after each one.
406  */
407  now = GetCurrentTimestamp();
408  }
409 
410  /* Done firing timeouts, so reschedule next interrupt if any */
411  schedule_alarm(now);
412  }
413  }
414 
416 
417  errno = save_errno;
418 }
static void remove_timeout_index(int index)
Definition: timeout.c:135
TimestampTz GetCurrentTimestamp(void)
Definition: timestamp.c:1578
int64 TimestampTz
Definition: timestamp.h:39
#define disable_alarm()
Definition: timeout.c:68
timeout_handler_proc timeout_handler
Definition: timeout.c:35
volatile bool indicator
Definition: timeout.c:32
void SetLatch(Latch *latch)
Definition: latch.c:567
#define RESUME_INTERRUPTS()
Definition: miscadmin.h:119
static volatile sig_atomic_t alarm_enabled
Definition: timeout.c:66
static volatile sig_atomic_t signal_pending
Definition: timeout.c:76
static void schedule_alarm(TimestampTz now)
Definition: timeout.c:206
static timeout_params *volatile active_timeouts[MAX_TIMEOUTS]
Definition: timeout.c:52
#define HOLD_INTERRUPTS()
Definition: miscadmin.h:117
struct Latch * MyLatch
Definition: globals.c:55
static volatile int num_active_timeouts
Definition: timeout.c:51
Datum now(PG_FUNCTION_ARGS)
Definition: timestamp.c:1542

◆ InitializeTimeouts()

void InitializeTimeouts ( void  )

Definition at line 435 of file timeout.c.

References timeout_params::active, all_timeouts_initialized, disable_alarm, timeout_params::fin_time, handle_sig_alarm(), i, timeout_params::index, timeout_params::indicator, MAX_TIMEOUTS, num_active_timeouts, pqsignal(), SIGALRM, timeout_params::start_time, and timeout_params::timeout_handler.

Referenced by AutoVacLauncherMain(), AutoVacWorkerMain(), BackendInitialize(), PostgresMain(), StartBackgroundWorker(), StartupProcessMain(), and WalSndSignals().

436 {
437  int i;
438 
439  /* Initialize, or re-initialize, all local state */
440  disable_alarm();
441 
443 
444  for (i = 0; i < MAX_TIMEOUTS; i++)
445  {
446  all_timeouts[i].index = i;
447  all_timeouts[i].active = false;
448  all_timeouts[i].indicator = false;
451  all_timeouts[i].fin_time = 0;
452  }
453 
455 
456  /* Now establish the signal handler */
458 }
static bool all_timeouts_initialized
Definition: timeout.c:45
TimestampTz fin_time
Definition: timeout.c:38
#define disable_alarm()
Definition: timeout.c:68
timeout_handler_proc timeout_handler
Definition: timeout.c:35
volatile bool indicator
Definition: timeout.c:32
volatile bool active
Definition: timeout.c:31
static timeout_params all_timeouts[MAX_TIMEOUTS]
Definition: timeout.c:44
TimestampTz start_time
Definition: timeout.c:37
pqsigfunc pqsignal(int signum, pqsigfunc handler)
Definition: signal.c:170
TimeoutId index
Definition: timeout.c:28
#define SIGALRM
Definition: win32_port.h:165
int i
static volatile int num_active_timeouts
Definition: timeout.c:51
static void handle_sig_alarm(SIGNAL_ARGS)
Definition: timeout.c:348

◆ insert_timeout()

static void insert_timeout ( TimeoutId  id,
int  index 
)
static

Definition at line 112 of file timeout.c.

References timeout_params::active, Assert, elog, FATAL, i, timeout_params::index, and num_active_timeouts.

Referenced by enable_timeout().

113 {
114  int i;
115 
117  elog(FATAL, "timeout index %d out of range 0..%d", index,
118  num_active_timeouts);
119 
120  Assert(!all_timeouts[id].active);
121  all_timeouts[id].active = true;
122 
123  for (i = num_active_timeouts - 1; i >= index; i--)
124  active_timeouts[i + 1] = active_timeouts[i];
125 
127 
128  num_active_timeouts++;
129 }
volatile bool active
Definition: timeout.c:31
Definition: type.h:89
#define FATAL
Definition: elog.h:54
static timeout_params all_timeouts[MAX_TIMEOUTS]
Definition: timeout.c:44
#define Assert(condition)
Definition: c.h:804
static timeout_params *volatile active_timeouts[MAX_TIMEOUTS]
Definition: timeout.c:52
#define elog(elevel,...)
Definition: elog.h:227
int i
static volatile int num_active_timeouts
Definition: timeout.c:51

◆ RegisterTimeout()

TimeoutId RegisterTimeout ( TimeoutId  id,
timeout_handler_proc  handler 
)

Definition at line 469 of file timeout.c.

References all_timeouts_initialized, Assert, ereport, errcode(), errmsg(), FATAL, MAX_TIMEOUTS, timeout_params::timeout_handler, and USER_TIMEOUT.

Referenced by BackendInitialize(), InitPostgres(), and StartupProcessMain().

470 {
472 
473  /* There's no need to disable the signal handler here. */
474 
475  if (id >= USER_TIMEOUT)
476  {
477  /* Allocate a user-defined timeout reason */
478  for (id = USER_TIMEOUT; id < MAX_TIMEOUTS; id++)
479  if (all_timeouts[id].timeout_handler == NULL)
480  break;
481  if (id >= MAX_TIMEOUTS)
482  ereport(FATAL,
483  (errcode(ERRCODE_CONFIGURATION_LIMIT_EXCEEDED),
484  errmsg("cannot add more timeout reasons")));
485  }
486 
487  Assert(all_timeouts[id].timeout_handler == NULL);
488 
489  all_timeouts[id].timeout_handler = handler;
490 
491  return id;
492 }
static bool all_timeouts_initialized
Definition: timeout.c:45
int errcode(int sqlerrcode)
Definition: elog.c:694
timeout_handler_proc timeout_handler
Definition: timeout.c:35
#define FATAL
Definition: elog.h:54
static timeout_params all_timeouts[MAX_TIMEOUTS]
Definition: timeout.c:44
#define ereport(elevel,...)
Definition: elog.h:155
#define Assert(condition)
Definition: c.h:804
int errmsg(const char *fmt,...)
Definition: elog.c:905

◆ remove_timeout_index()

static void remove_timeout_index ( int  index)
static

Definition at line 135 of file timeout.c.

References timeout_params::active, Assert, elog, FATAL, i, timeout_params::index, and num_active_timeouts.

Referenced by disable_timeout(), disable_timeouts(), enable_timeout(), and handle_sig_alarm().

136 {
137  int i;
138 
140  elog(FATAL, "timeout index %d out of range 0..%d", index,
141  num_active_timeouts - 1);
142 
143  Assert(active_timeouts[index]->active);
144  active_timeouts[index]->active = false;
145 
146  for (i = index + 1; i < num_active_timeouts; i++)
147  active_timeouts[i - 1] = active_timeouts[i];
148 
149  num_active_timeouts--;
150 }
volatile bool active
Definition: timeout.c:31
Definition: type.h:89
#define FATAL
Definition: elog.h:54
#define Assert(condition)
Definition: c.h:804
static timeout_params *volatile active_timeouts[MAX_TIMEOUTS]
Definition: timeout.c:52
#define elog(elevel,...)
Definition: elog.h:227
int i
static volatile int num_active_timeouts
Definition: timeout.c:51

◆ reschedule_timeouts()

void reschedule_timeouts ( void  )

Definition at line 504 of file timeout.c.

References all_timeouts_initialized, disable_alarm, GetCurrentTimestamp(), num_active_timeouts, and schedule_alarm().

Referenced by AbortSubTransaction(), and AbortTransaction().

505 {
506  /* For flexibility, allow this to be called before we're initialized. */
508  return;
509 
510  /* Disable timeout interrupts for safety. */
511  disable_alarm();
512 
513  /* Reschedule the interrupt, if any timeouts remain active. */
514  if (num_active_timeouts > 0)
516 }
static bool all_timeouts_initialized
Definition: timeout.c:45
TimestampTz GetCurrentTimestamp(void)
Definition: timestamp.c:1578
#define disable_alarm()
Definition: timeout.c:68
static void schedule_alarm(TimestampTz now)
Definition: timeout.c:206
static volatile int num_active_timeouts
Definition: timeout.c:51

◆ schedule_alarm()

static void schedule_alarm ( TimestampTz  now)
static

Definition at line 206 of file timeout.c.

References elog, enable_alarm, FATAL, timeout_params::fin_time, itimerval::it_value, ITIMER_REAL, MemSet, num_active_timeouts, setitimer(), signal_due_at, signal_pending, and TimestampDifference().

Referenced by disable_timeout(), disable_timeouts(), enable_timeout_after(), enable_timeout_at(), enable_timeouts(), handle_sig_alarm(), and reschedule_timeouts().

207 {
208  if (num_active_timeouts > 0)
209  {
210  struct itimerval timeval;
211  TimestampTz nearest_timeout;
212  long secs;
213  int usecs;
214 
215  MemSet(&timeval, 0, sizeof(struct itimerval));
216 
217  /*
218  * Get the time remaining till the nearest pending timeout. If it is
219  * negative, assume that we somehow missed an interrupt, and force
220  * signal_pending off. This gives us a chance to recover if the
221  * kernel drops a timeout request for some reason.
222  */
223  nearest_timeout = active_timeouts[0]->fin_time;
224  if (now > nearest_timeout)
225  {
226  signal_pending = false;
227  /* force an interrupt as soon as possible */
228  secs = 0;
229  usecs = 1;
230  }
231  else
232  {
233  TimestampDifference(now, nearest_timeout,
234  &secs, &usecs);
235 
236  /*
237  * It's possible that the difference is less than a microsecond;
238  * ensure we don't cancel, rather than set, the interrupt.
239  */
240  if (secs == 0 && usecs == 0)
241  usecs = 1;
242  }
243 
244  timeval.it_value.tv_sec = secs;
245  timeval.it_value.tv_usec = usecs;
246 
247  /*
248  * We must enable the signal handler before calling setitimer(); if we
249  * did it in the other order, we'd have a race condition wherein the
250  * interrupt could occur before we can set alarm_enabled, so that the
251  * signal handler would fail to do anything.
252  *
253  * Because we didn't bother to disable the timer in disable_alarm(),
254  * it's possible that a previously-set interrupt will fire between
255  * enable_alarm() and setitimer(). This is safe, however. There are
256  * two possible outcomes:
257  *
258  * 1. The signal handler finds nothing to do (because the nearest
259  * timeout event is still in the future). It will re-set the timer
260  * and return. Then we'll overwrite the timer value with a new one.
261  * This will mean that the timer fires a little later than we
262  * intended, but only by the amount of time it takes for the signal
263  * handler to do nothing useful, which shouldn't be much.
264  *
265  * 2. The signal handler executes and removes one or more timeout
266  * events. When it returns, either the queue is now empty or the
267  * frontmost event is later than the one we looked at above. So we'll
268  * overwrite the timer value with one that is too soon (plus or minus
269  * the signal handler's execution time), causing a useless interrupt
270  * to occur. But the handler will then re-set the timer and
271  * everything will still work as expected.
272  *
273  * Since these cases are of very low probability (the window here
274  * being quite narrow), it's not worth adding cycles to the mainline
275  * code to prevent occasional wasted interrupts.
276  */
277  enable_alarm();
278 
279  /*
280  * If there is already an interrupt pending that's at or before the
281  * needed time, we need not do anything more. The signal handler will
282  * do the right thing in the first case, and re-schedule the interrupt
283  * for later in the second case. It might seem that the extra
284  * interrupt is wasted work, but it's not terribly much work, and this
285  * method has very significant advantages in the common use-case where
286  * we repeatedly set a timeout that we don't expect to reach and then
287  * cancel it. Instead of invoking setitimer() every time the timeout
288  * is set or canceled, we perform one interrupt and a re-scheduling
289  * setitimer() call at intervals roughly equal to the timeout delay.
290  * For example, with statement_timeout = 1s and a throughput of
291  * thousands of queries per second, this method requires an interrupt
292  * and setitimer() call roughly once a second, rather than thousands
293  * of setitimer() calls per second.
294  *
295  * Because of the possible passage of time between when we obtained
296  * "now" and when we reach setitimer(), the kernel's opinion of when
297  * to trigger the interrupt is likely to be a bit later than
298  * signal_due_at. That's fine, for the same reasons described above.
299  */
300  if (signal_pending && nearest_timeout >= signal_due_at)
301  return;
302 
303  /*
304  * As with calling enable_alarm(), we must set signal_pending *before*
305  * calling setitimer(); if we did it after, the signal handler could
306  * trigger before we set it, leaving us with a false opinion that a
307  * signal is still coming.
308  *
309  * Other race conditions involved with setting/checking signal_pending
310  * are okay, for the reasons described above. One additional point is
311  * that the signal handler could fire after we set signal_due_at, but
312  * still before the setitimer() call. Then the handler could
313  * overwrite signal_due_at with a value it computes, which will be the
314  * same as or perhaps later than what we just computed. After we
315  * perform setitimer(), the net effect would be that signal_due_at
316  * gives a time later than when the interrupt will really happen;
317  * which is a safe situation.
318  */
319  signal_due_at = nearest_timeout;
320  signal_pending = true;
321 
322  /* Set the alarm timer */
323  if (setitimer(ITIMER_REAL, &timeval, NULL) != 0)
324  {
325  /*
326  * Clearing signal_pending here is a bit pro forma, but not
327  * entirely so, since something in the FATAL exit path could try
328  * to use timeout facilities.
329  */
330  signal_pending = false;
331  elog(FATAL, "could not enable SIGALRM timer: %m");
332  }
333  }
334 }
#define enable_alarm()
Definition: timeout.c:69
int64 TimestampTz
Definition: timestamp.h:39
TimestampTz fin_time
Definition: timeout.c:38
static TimestampTz signal_due_at
Definition: timeout.c:77
#define MemSet(start, val, len)
Definition: c.h:1008
#define FATAL
Definition: elog.h:54
int setitimer(int which, const struct itimerval *value, struct itimerval *ovalue)
Definition: timer.c:86
static volatile sig_atomic_t signal_pending
Definition: timeout.c:76
static timeout_params *volatile active_timeouts[MAX_TIMEOUTS]
Definition: timeout.c:52
#define elog(elevel,...)
Definition: elog.h:227
void TimestampDifference(TimestampTz start_time, TimestampTz stop_time, long *secs, int *microsecs)
Definition: timestamp.c:1654
static volatile int num_active_timeouts
Definition: timeout.c:51
Datum now(PG_FUNCTION_ARGS)
Definition: timestamp.c:1542
#define ITIMER_REAL
Definition: win32_port.h:187

Variable Documentation

◆ active_timeouts

timeout_params* volatile active_timeouts[MAX_TIMEOUTS]
static

Definition at line 52 of file timeout.c.

◆ alarm_enabled

volatile sig_atomic_t alarm_enabled = false
static

Definition at line 66 of file timeout.c.

Referenced by handle_sig_alarm().

◆ all_timeouts

timeout_params all_timeouts[MAX_TIMEOUTS]
static

Definition at line 44 of file timeout.c.

◆ all_timeouts_initialized

bool all_timeouts_initialized = false
static

◆ num_active_timeouts

◆ signal_due_at

TimestampTz signal_due_at = 0
static

Definition at line 77 of file timeout.c.

Referenced by schedule_alarm().

◆ signal_pending

volatile sig_atomic_t signal_pending = false
static

Definition at line 76 of file timeout.c.

Referenced by handle_sig_alarm(), and schedule_alarm().