#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().
1.7.1