#include "postgres.h"
#include <sys/time.h>
#include "storage/proc.h"
#include "utils/timeout.h"
#include "utils/timestamp.h"
Go to the source code of this file.
#define disable_alarm | ( | ) | (alarm_enabled = false) |
Definition at line 63 of file timeout.c.
Referenced by disable_all_timeouts(), disable_timeout(), disable_timeouts(), enable_timeout_after(), enable_timeout_at(), enable_timeouts(), handle_sig_alarm(), and InitializeTimeouts().
#define enable_alarm | ( | ) | (alarm_enabled = true) |
Definition at line 64 of file timeout.c.
Referenced by schedule_alarm().
typedef struct timeout_params timeout_params |
void disable_all_timeouts | ( | bool | keep_indicators | ) |
Definition at line 564 of file timeout.c.
References disable_alarm, elog, FATAL, i, ITIMER_REAL, MemSet, NULL, num_active_timeouts, and setitimer().
Referenced by AutoVacLauncherMain(), PostgresMain(), and ResolveRecoveryConflictWithBufferPin().
{ 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; if (!keep_indicators) { int i; for (i = 0; i < MAX_TIMEOUTS; i++) all_timeouts[i].indicator = false; } }
Definition at line 493 of file timeout.c.
References all_timeouts_initialized, Assert, disable_alarm, find_active_timeout(), GetCurrentTimestamp(), i, timeout_params::indicator, NULL, num_active_timeouts, remove_timeout_index(), and schedule_alarm().
Referenced by BackendInitialize(), finish_xact_command(), PerformAuthentication(), ProcSleep(), StandbyTimeoutHandler(), and start_xact_command().
{ int i; /* Assert request is sane */ Assert(all_timeouts_initialized); Assert(all_timeouts[id].timeout_handler != NULL); /* Disable timeout interrupts for safety. */ disable_alarm(); /* Find the timeout and remove it from the active list. */ i = find_active_timeout(id); if (i >= 0) remove_timeout_index(i); /* Mark it inactive, whether it was active or not. */ if (!keep_indicator) all_timeouts[id].indicator = false; /* Reschedule the interrupt, if any timeouts remain active. */ if (num_active_timeouts > 0) schedule_alarm(GetCurrentTimestamp()); }
void disable_timeouts | ( | const DisableTimeoutParams * | timeouts, | |
int | count | |||
) |
Definition at line 529 of file timeout.c.
References all_timeouts_initialized, Assert, disable_alarm, find_active_timeout(), GetCurrentTimestamp(), i, DisableTimeoutParams::id, timeout_params::indicator, NULL, num_active_timeouts, remove_timeout_index(), and schedule_alarm().
Referenced by LockErrorCleanup(), and ProcSleep().
{ int i; Assert(all_timeouts_initialized); /* Disable timeout interrupts for safety. */ disable_alarm(); /* Cancel the timeout(s). */ for (i = 0; i < count; i++) { TimeoutId id = timeouts[i].id; int idx; Assert(all_timeouts[id].timeout_handler != NULL); idx = find_active_timeout(id); if (idx >= 0) remove_timeout_index(idx); if (!timeouts[i].keep_indicator) all_timeouts[id].indicator = false; } /* Reschedule the interrupt, if any timeouts remain active. */ if (num_active_timeouts > 0) schedule_alarm(GetCurrentTimestamp()); }
static void enable_timeout | ( | TimeoutId | id, | |
TimestampTz | now, | |||
TimestampTz | fin_time | |||
) | [static] |
Definition at line 137 of file timeout.c.
References all_timeouts_initialized, Assert, timeout_params::fin_time, find_active_timeout(), i, timeout_params::indicator, insert_timeout(), NULL, num_active_timeouts, remove_timeout_index(), and timeout_params::start_time.
Referenced by enable_timeout_after(), enable_timeout_at(), and enable_timeouts().
{ int i; /* Assert request is sane */ Assert(all_timeouts_initialized); Assert(all_timeouts[id].timeout_handler != NULL); /* * If this timeout was already active, momentarily disable it. We * interpret the call as a directive to reschedule the timeout. */ i = find_active_timeout(id); if (i >= 0) remove_timeout_index(i); /* * Find out the index where to insert the new timeout. We sort by * fin_time, and for equal fin_time by priority. */ for (i = 0; i < num_active_timeouts; i++) { timeout_params *old_timeout = active_timeouts[i]; if (fin_time < old_timeout->fin_time) break; if (fin_time == old_timeout->fin_time && id < old_timeout->index) break; } /* * Mark the timeout active, and insert it into the active list. */ all_timeouts[id].indicator = false; all_timeouts[id].start_time = now; all_timeouts[id].fin_time = fin_time; insert_timeout(id, i); }
void enable_timeout_after | ( | TimeoutId | id, | |
int | delay_ms | |||
) |
Definition at line 396 of file timeout.c.
References disable_alarm, enable_timeout(), GetCurrentTimestamp(), schedule_alarm(), and TimestampTzPlusMilliseconds.
Referenced by BackendInitialize(), PerformAuthentication(), ProcSleep(), ResolveRecoveryConflictWithBufferPin(), and start_xact_command().
{ TimestampTz now; TimestampTz fin_time; /* Disable timeout interrupts for safety. */ disable_alarm(); /* Queue the timeout at the appropriate time. */ now = GetCurrentTimestamp(); fin_time = TimestampTzPlusMilliseconds(now, delay_ms); enable_timeout(id, now, fin_time); /* Set the timer interrupt. */ schedule_alarm(now); }
void enable_timeout_at | ( | TimeoutId | id, | |
TimestampTz | fin_time | |||
) |
Definition at line 421 of file timeout.c.
References disable_alarm, enable_timeout(), GetCurrentTimestamp(), and schedule_alarm().
{ TimestampTz now; /* Disable timeout interrupts for safety. */ disable_alarm(); /* Queue the timeout at the appropriate time. */ now = GetCurrentTimestamp(); enable_timeout(id, now, fin_time); /* Set the timer interrupt. */ schedule_alarm(now); }
void enable_timeouts | ( | const EnableTimeoutParams * | timeouts, | |
int | count | |||
) |
Definition at line 444 of file timeout.c.
References disable_alarm, elog, enable_timeout(), ERROR, GetCurrentTimestamp(), i, EnableTimeoutParams::id, schedule_alarm(), TimestampTzPlusMilliseconds, TMPARAM_AFTER, and TMPARAM_AT.
Referenced by ProcSleep(), and ResolveRecoveryConflictWithBufferPin().
{ TimestampTz now; int i; /* Disable timeout interrupts for safety. */ disable_alarm(); /* Queue the timeout(s) at the appropriate times. */ now = GetCurrentTimestamp(); for (i = 0; i < count; i++) { TimeoutId id = timeouts[i].id; TimestampTz fin_time; switch (timeouts[i].type) { case TMPARAM_AFTER: fin_time = TimestampTzPlusMilliseconds(now, timeouts[i].delay_ms); enable_timeout(id, now, fin_time); break; case TMPARAM_AT: enable_timeout(id, now, timeouts[i].fin_time); break; default: elog(ERROR, "unrecognized timeout type %d", (int) timeouts[i].type); break; } } /* Set the timer interrupt. */ schedule_alarm(now); }
static int find_active_timeout | ( | TimeoutId | id | ) | [static] |
Definition at line 81 of file timeout.c.
References i, and num_active_timeouts.
Referenced by disable_timeout(), disable_timeouts(), and enable_timeout().
{ int i; for (i = 0; i < num_active_timeouts; i++) { if (active_timeouts[i]->index == id) return i; } return -1; }
Definition at line 601 of file timeout.c.
References timeout_params::indicator.
Referenced by ProcessInterrupts().
{ if (all_timeouts[id].indicator) { if (reset_indicator) all_timeouts[id].indicator = false; return true; } return false; }
TimestampTz get_timeout_start_time | ( | TimeoutId | id | ) |
Definition at line 621 of file timeout.c.
References timeout_params::start_time.
Referenced by ProcSleep().
{ return all_timeouts[id].start_time; }
static void handle_sig_alarm | ( | SIGNAL_ARGS | ) | [static] |
Definition at line 258 of file timeout.c.
References alarm_enabled, disable_alarm, GetCurrentTimestamp(), timeout_params::indicator, MyProc, now(), num_active_timeouts, PGPROC::procLatch, remove_timeout_index(), schedule_alarm(), SetLatch(), and timeout_params::timeout_handler.
Referenced by InitializeTimeouts().
{ int save_errno = errno; /* * SIGALRM is always cause for waking anything waiting on the process * latch. Cope with MyProc not being there, as the startup process also * uses this signal handler. */ if (MyProc) SetLatch(&MyProc->procLatch); /* * Fire any pending timeouts, but only if we're enabled to do so. */ if (alarm_enabled) { /* * Disable alarms, just in case this platform allows signal handlers * to interrupt themselves. schedule_alarm() will re-enable if * appropriate. */ disable_alarm(); if (num_active_timeouts > 0) { TimestampTz now = GetCurrentTimestamp(); /* While the first pending timeout has been reached ... */ while (num_active_timeouts > 0 && now >= active_timeouts[0]->fin_time) { timeout_params *this_timeout = active_timeouts[0]; /* Remove it from the active list */ remove_timeout_index(0); /* Mark it as fired */ this_timeout->indicator = true; /* And call its handler function */ (*this_timeout->timeout_handler) (); /* * The handler might not take negligible time (CheckDeadLock * for instance isn't too cheap), so let's update our idea of * "now" after each one. */ now = GetCurrentTimestamp(); } /* Done firing timeouts, so reschedule next interrupt if any */ schedule_alarm(now); } } errno = save_errno; }
void InitializeTimeouts | ( | void | ) |
Definition at line 332 of file timeout.c.
References all_timeouts_initialized, disable_alarm, timeout_params::fin_time, handle_sig_alarm(), i, timeout_params::index, timeout_params::indicator, num_active_timeouts, pqsignal(), SIGALRM, timeout_params::start_time, and timeout_params::timeout_handler.
Referenced by AutoVacLauncherMain(), AutoVacWorkerMain(), BackendInitialize(), do_start_bgworker(), PostgresMain(), StartupProcessMain(), and WalSndSignals().
{ int i; /* Initialize, or re-initialize, all local state */ disable_alarm(); num_active_timeouts = 0; for (i = 0; i < MAX_TIMEOUTS; i++) { all_timeouts[i].index = i; all_timeouts[i].indicator = false; all_timeouts[i].timeout_handler = NULL; all_timeouts[i].start_time = 0; all_timeouts[i].fin_time = 0; } all_timeouts_initialized = true; /* Now establish the signal handler */ pqsignal(SIGALRM, handle_sig_alarm); }
static void insert_timeout | ( | TimeoutId | id, | |
int | index | |||
) | [static] |
Definition at line 99 of file timeout.c.
References elog, FATAL, i, and num_active_timeouts.
Referenced by enable_timeout().
{ int i; if (index < 0 || index > num_active_timeouts) elog(FATAL, "timeout index %d out of range 0..%d", index, num_active_timeouts); for (i = num_active_timeouts - 1; i >= index; i--) active_timeouts[i + 1] = active_timeouts[i]; active_timeouts[index] = &all_timeouts[id]; num_active_timeouts++; }
TimeoutId RegisterTimeout | ( | TimeoutId | id, | |
timeout_handler_proc | handler | |||
) |
Definition at line 365 of file timeout.c.
References all_timeouts_initialized, Assert, ereport, errcode(), errmsg(), FATAL, NULL, timeout_params::timeout_handler, and USER_TIMEOUT.
Referenced by BackendInitialize(), InitPostgres(), and StartupProcessMain().
{ Assert(all_timeouts_initialized); /* There's no need to disable the signal handler here. */ if (id >= USER_TIMEOUT) { /* Allocate a user-defined timeout reason */ for (id = USER_TIMEOUT; id < MAX_TIMEOUTS; id++) if (all_timeouts[id].timeout_handler == NULL) break; if (id >= MAX_TIMEOUTS) ereport(FATAL, (errcode(ERRCODE_CONFIGURATION_LIMIT_EXCEEDED), errmsg("cannot add more timeout reasons"))); } Assert(all_timeouts[id].timeout_handler == NULL); all_timeouts[id].timeout_handler = handler; return id; }
static void remove_timeout_index | ( | int | index | ) | [static] |
Definition at line 119 of file timeout.c.
References elog, FATAL, i, and num_active_timeouts.
Referenced by disable_timeout(), disable_timeouts(), enable_timeout(), and handle_sig_alarm().
{ int i; if (index < 0 || index >= num_active_timeouts) elog(FATAL, "timeout index %d out of range 0..%d", index, num_active_timeouts - 1); for (i = index + 1; i < num_active_timeouts; i++) active_timeouts[i - 1] = active_timeouts[i]; num_active_timeouts--; }
static void schedule_alarm | ( | TimestampTz | now | ) | [static] |
Definition at line 184 of file timeout.c.
References elog, enable_alarm, FATAL, itimerval::it_value, ITIMER_REAL, MemSet, NULL, num_active_timeouts, setitimer(), and TimestampDifference().
Referenced by disable_timeout(), disable_timeouts(), enable_timeout_after(), enable_timeout_at(), enable_timeouts(), and handle_sig_alarm().
{ if (num_active_timeouts > 0) { struct itimerval timeval; long secs; int usecs; MemSet(&timeval, 0, sizeof(struct itimerval)); /* Get the time remaining till the nearest pending timeout */ TimestampDifference(now, active_timeouts[0]->fin_time, &secs, &usecs); /* * It's possible that the difference is less than a microsecond; * ensure we don't cancel, rather than set, the interrupt. */ if (secs == 0 && usecs == 0) usecs = 1; timeval.it_value.tv_sec = secs; timeval.it_value.tv_usec = usecs; /* * We must enable the signal handler before calling setitimer(); if we * did it in the other order, we'd have a race condition wherein the * interrupt could occur before we can set alarm_enabled, so that the * signal handler would fail to do anything. * * Because we didn't bother to reset the timer in disable_alarm(), * it's possible that a previously-set interrupt will fire between * enable_alarm() and setitimer(). This is safe, however. There are * two possible outcomes: * * 1. The signal handler finds nothing to do (because the nearest * timeout event is still in the future). It will re-set the timer * and return. Then we'll overwrite the timer value with a new one. * This will mean that the timer fires a little later than we * intended, but only by the amount of time it takes for the signal * handler to do nothing useful, which shouldn't be much. * * 2. The signal handler executes and removes one or more timeout * events. When it returns, either the queue is now empty or the * frontmost event is later than the one we looked at above. So we'll * overwrite the timer value with one that is too soon (plus or minus * the signal handler's execution time), causing a useless interrupt * to occur. But the handler will then re-set the timer and * everything will still work as expected. * * Since these cases are of very low probability (the window here * being quite narrow), it's not worth adding cycles to the mainline * code to prevent occasional wasted interrupts. */ enable_alarm(); /* Set the alarm timer */ if (setitimer(ITIMER_REAL, &timeval, NULL) != 0) elog(FATAL, "could not enable SIGALRM timer: %m"); } }
timeout_params* volatile active_timeouts[MAX_TIMEOUTS] [static] |
volatile sig_atomic_t alarm_enabled = false [static] |
Definition at line 61 of file timeout.c.
Referenced by handle_sig_alarm().
timeout_params all_timeouts[MAX_TIMEOUTS] [static] |
bool all_timeouts_initialized = false [static] |
Definition at line 43 of file timeout.c.
Referenced by disable_timeout(), disable_timeouts(), enable_timeout(), InitializeTimeouts(), and RegisterTimeout().
volatile int num_active_timeouts = 0 [static] |
Definition at line 49 of file timeout.c.
Referenced by disable_all_timeouts(), disable_timeout(), disable_timeouts(), enable_timeout(), find_active_timeout(), handle_sig_alarm(), InitializeTimeouts(), insert_timeout(), remove_timeout_index(), and schedule_alarm().