From a64ca63e59c11d8fe6db24eee3d82b61db7c2c83 Mon Sep 17 00:00:00 2001
From: Tom Lane <tgl@sss.pgh.pa.us>
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 bf06ec048ff..aecdcd056cd 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();
-- 
GitLab