From 0b9d3d4dcd0561fbf674e09af1160f087eda535b Mon Sep 17 00:00:00 2001
From: Tom Lane <tgl@sss.pgh.pa.us>
Date: Sat, 4 Aug 2007 03:15:49 +0000
Subject: [PATCH] Fix a problem in my recent patch to initialize cancel_key for
 autovac workers as well as regular backends: if no regular backend launches
 before the autovac launcher tries to start an autovac worker, the postmaster
 would get an Assert fault due to calling PostmasterRandom before random_seed
 was initialized. Cleanest solution seems to be to take the initialization of
 random_seed out of ServerLoop and let PostmasterRandom do it for itself.

---
 src/backend/postmaster/postmaster.c | 53 ++++++++++++++---------------
 1 file changed, 26 insertions(+), 27 deletions(-)

diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c
index 74d90e6f887..4543c5c5032 100644
--- a/src/backend/postmaster/postmaster.c
+++ b/src/backend/postmaster/postmaster.c
@@ -37,7 +37,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/postmaster/postmaster.c,v 1.538 2007/08/03 20:06:50 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/postmaster/postmaster.c,v 1.539 2007/08/04 03:15:49 tgl Exp $
  *
  * NOTES
  *
@@ -230,6 +230,7 @@ static volatile sig_atomic_t start_autovac_launcher = false;
  * backend from the postmaster to that backend (via fork).
  */
 static unsigned int random_seed = 0;
+static struct timeval random_start_time;
 
 extern char *optarg;
 extern int	optind,
@@ -966,6 +967,8 @@ PostmasterMain(int argc, char *argv[])
 	 * Remember postmaster startup time
 	 */
 	PgStartTime = GetCurrentTimestamp();
+	/* PostmasterRandom wants its own copy */
+	gettimeofday(&random_start_time, NULL);
 
 	/*
 	 * We're ready to rock and roll...
@@ -1140,10 +1143,7 @@ ServerLoop(void)
 	int			nSockets;
 	time_t		now,
 				last_touch_time;
-	struct timeval earlier,
-				later;
 
-	gettimeofday(&earlier, NULL);
 	last_touch_time = time(NULL);
 
 	nSockets = initMasks(&readmask);
@@ -1194,24 +1194,6 @@ ServerLoop(void)
 		 */
 		if (selres > 0)
 		{
-			/*
-			 * Select a random seed at the time of first receiving a request.
-			 */
-			while (random_seed == 0)
-			{
-				gettimeofday(&later, NULL);
-
-				/*
-				 * We are not sure how much precision is in tv_usec, so we
-				 * swap the high and low 16 bits of 'later' and XOR them with
-				 * 'earlier'. On the off chance that the result is 0, we loop
-				 * until it isn't.
-				 */
-				random_seed = earlier.tv_usec ^
-					((later.tv_usec << 16) |
-					 ((later.tv_usec >> 16) & 0xffff));
-			}
-
 			for (i = 0; i < MAXLISTEN; i++)
 			{
 				if (ListenSocket[i] == -1)
@@ -2970,6 +2952,7 @@ BackendRun(Port *port)
 	 * a new random sequence in the random() library function.
 	 */
 	random_seed = 0;
+	random_start_time.tv_usec = 0;
 	/* slightly hacky way to get integer microseconds part of timestamptz */
 	TimestampDifference(0, port->SessionStartTime, &secs, &usecs);
 	srandom((unsigned int) (MyProcPid ^ usecs));
@@ -3778,13 +3761,29 @@ RandomSalt(char *cryptSalt, char *md5Salt)
 static long
 PostmasterRandom(void)
 {
-	static bool initialized = false;
-
-	if (!initialized)
+	/*
+	 * Select a random seed at the time of first receiving a request.
+	 */
+	if (random_seed == 0)
 	{
-		Assert(random_seed != 0);
+		do
+		{
+			struct timeval random_stop_time;
+
+			gettimeofday(&random_stop_time, NULL);
+			/*
+			 * We are not sure how much precision is in tv_usec, so we swap
+			 * the high and low 16 bits of 'random_stop_time' and XOR them
+			 * with 'random_start_time'. On the off chance that the result is
+			 * 0, we loop until it isn't.
+			 */
+			random_seed = random_start_time.tv_usec ^
+				((random_stop_time.tv_usec << 16) |
+				 ((random_stop_time.tv_usec >> 16) & 0xffff));
+		}
+		while (random_seed == 0);
+
 		srandom(random_seed);
-		initialized = true;
 	}
 
 	return random();
-- 
GitLab