Commit a64ca63e authored by Tom Lane's avatar Tom Lane

Use WaitLatch, not pg_usleep, for delaying in pg_sleep().

This avoids platform-dependent behavior wherein pg_sleep() might fail to be
interrupted by statement timeout, query cancel, SIGTERM, etc.  Also, since
there's no reason to wake up once a second any more, we can reduce the
power consumption of a sleeping backend a tad.

Back-patch to 9.3, since use of SA_RESTART for SIGALRM makes this a bigger
issue than it used to be.
parent f69aece6
...@@ -384,16 +384,16 @@ pg_sleep(PG_FUNCTION_ARGS) ...@@ -384,16 +384,16 @@ pg_sleep(PG_FUNCTION_ARGS)
float8 endtime; float8 endtime;
/* /*
* We break the requested sleep into segments of no more than 1 second, to * We sleep using WaitLatch, to ensure that we'll wake up promptly if an
* put an upper bound on how long it will take us to respond to a cancel * important signal (such as SIGALRM or SIGINT) arrives. Because
* or die interrupt. (Note that pg_usleep is interruptible by signals on * WaitLatch's upper limit of delay is INT_MAX milliseconds, and the user
* some platforms but not others.) Also, this method avoids exposing * might ask for more than that, we sleep for at most 10 minutes and then
* pg_usleep's upper bound on allowed delays. * loop.
* *
* By computing the intended stop time initially, we avoid accumulation of * By computing the intended stop time initially, we avoid accumulation of
* extra delay across multiple sleeps. This also ensures we won't delay * extra delay across multiple sleeps. This also ensures we won't delay
* less than the specified time if pg_usleep is interrupted by other * less than the specified time when WaitLatch is terminated early by a
* signals such as SIGHUP. * non-query-cancelling signal such as SIGHUP.
*/ */
#ifdef HAVE_INT64_TIMESTAMP #ifdef HAVE_INT64_TIMESTAMP
...@@ -407,15 +407,22 @@ pg_sleep(PG_FUNCTION_ARGS) ...@@ -407,15 +407,22 @@ pg_sleep(PG_FUNCTION_ARGS)
for (;;) for (;;)
{ {
float8 delay; float8 delay;
long delay_ms;
CHECK_FOR_INTERRUPTS(); CHECK_FOR_INTERRUPTS();
delay = endtime - GetNowFloat(); delay = endtime - GetNowFloat();
if (delay >= 1.0) if (delay >= 600.0)
pg_usleep(1000000L); delay_ms = 600000;
else if (delay > 0.0) else if (delay > 0.0)
pg_usleep((long) ceil(delay * 1000000.0)); delay_ms = (long) ceil(delay * 1000.0);
else else
break; break;
(void) WaitLatch(&MyProc->procLatch,
WL_LATCH_SET | WL_TIMEOUT,
delay_ms);
ResetLatch(&MyProc->procLatch);
} }
PG_RETURN_VOID(); PG_RETURN_VOID();
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment