From a64ca63e59c11d8fe6db24eee3d82b61db7c2c83 Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Sat, 15 Jun 2013 16:22:29 -0400 Subject: [PATCH] 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. --- src/backend/utils/adt/misc.c | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/src/backend/utils/adt/misc.c b/src/backend/utils/adt/misc.c index bf06ec048f..aecdcd056c 100644 --- a/src/backend/utils/adt/misc.c +++ b/src/backend/utils/adt/misc.c @@ -384,16 +384,16 @@ pg_sleep(PG_FUNCTION_ARGS) float8 endtime; /* - * We break the requested sleep into segments of no more than 1 second, to - * put an upper bound on how long it will take us to respond to a cancel - * or die interrupt. (Note that pg_usleep is interruptible by signals on - * some platforms but not others.) Also, this method avoids exposing - * pg_usleep's upper bound on allowed delays. + * We sleep using WaitLatch, to ensure that we'll wake up promptly if an + * important signal (such as SIGALRM or SIGINT) arrives. Because + * WaitLatch's upper limit of delay is INT_MAX milliseconds, and the user + * might ask for more than that, we sleep for at most 10 minutes and then + * loop. * * By computing the intended stop time initially, we avoid accumulation of * extra delay across multiple sleeps. This also ensures we won't delay - * less than the specified time if pg_usleep is interrupted by other - * signals such as SIGHUP. + * less than the specified time when WaitLatch is terminated early by a + * non-query-cancelling signal such as SIGHUP. */ #ifdef HAVE_INT64_TIMESTAMP @@ -407,15 +407,22 @@ pg_sleep(PG_FUNCTION_ARGS) for (;;) { float8 delay; + long delay_ms; CHECK_FOR_INTERRUPTS(); + delay = endtime - GetNowFloat(); - if (delay >= 1.0) - pg_usleep(1000000L); + if (delay >= 600.0) + delay_ms = 600000; else if (delay > 0.0) - pg_usleep((long) ceil(delay * 1000000.0)); + delay_ms = (long) ceil(delay * 1000.0); else break; + + (void) WaitLatch(&MyProc->procLatch, + WL_LATCH_SET | WL_TIMEOUT, + delay_ms); + ResetLatch(&MyProc->procLatch); } PG_RETURN_VOID();