Skip to content

Commit a64ca63

Browse files
committed
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.
1 parent f69aece commit a64ca63

File tree

1 file changed

+17
-10
lines changed

1 file changed

+17
-10
lines changed

src/backend/utils/adt/misc.c

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -384,16 +384,16 @@ pg_sleep(PG_FUNCTION_ARGS)
384384
float8 endtime;
385385

386386
/*
387-
* We break the requested sleep into segments of no more than 1 second, to
388-
* put an upper bound on how long it will take us to respond to a cancel
389-
* or die interrupt. (Note that pg_usleep is interruptible by signals on
390-
* some platforms but not others.) Also, this method avoids exposing
391-
* pg_usleep's upper bound on allowed delays.
387+
* We sleep using WaitLatch, to ensure that we'll wake up promptly if an
388+
* important signal (such as SIGALRM or SIGINT) arrives. Because
389+
* WaitLatch's upper limit of delay is INT_MAX milliseconds, and the user
390+
* might ask for more than that, we sleep for at most 10 minutes and then
391+
* loop.
392392
*
393393
* By computing the intended stop time initially, we avoid accumulation of
394394
* extra delay across multiple sleeps. This also ensures we won't delay
395-
* less than the specified time if pg_usleep is interrupted by other
396-
* signals such as SIGHUP.
395+
* less than the specified time when WaitLatch is terminated early by a
396+
* non-query-cancelling signal such as SIGHUP.
397397
*/
398398

399399
#ifdef HAVE_INT64_TIMESTAMP
@@ -407,15 +407,22 @@ pg_sleep(PG_FUNCTION_ARGS)
407407
for (;;)
408408
{
409409
float8 delay;
410+
long delay_ms;
410411

411412
CHECK_FOR_INTERRUPTS();
413+
412414
delay = endtime - GetNowFloat();
413-
if (delay >= 1.0)
414-
pg_usleep(1000000L);
415+
if (delay >= 600.0)
416+
delay_ms = 600000;
415417
else if (delay > 0.0)
416-
pg_usleep((long) ceil(delay * 1000000.0));
418+
delay_ms = (long) ceil(delay * 1000.0);
417419
else
418420
break;
421+
422+
(void) WaitLatch(&MyProc->procLatch,
423+
WL_LATCH_SET | WL_TIMEOUT,
424+
delay_ms);
425+
ResetLatch(&MyProc->procLatch);
419426
}
420427

421428
PG_RETURN_VOID();

0 commit comments

Comments
 (0)