<resent because of list filter>

[1]: http://cfbot.cputube.org/

Indeed. I wish that these results would be available from the cf interface.

Attached a v11 which might improve things.

Not enough. Here is a v12 which might improve things further.

Not enough. Here is a v13 which might improve things further more.

--
Fabien.
diff --git a/configure b/configure
index 7542fe30a1..7dc95e3960 100755
--- a/configure
+++ b/configure
@@ -800,6 +800,7 @@ infodir
 docdir
 oldincludedir
 includedir
+runstatedir
 localstatedir
 sharedstatedir
 sysconfdir
@@ -941,6 +942,7 @@ datadir='${datarootdir}'
 sysconfdir='${prefix}/etc'
 sharedstatedir='${prefix}/com'
 localstatedir='${prefix}/var'
+runstatedir='${localstatedir}/run'
 includedir='${prefix}/include'
 oldincludedir='/usr/include'
 docdir='${datarootdir}/doc/${PACKAGE_TARNAME}'
@@ -1193,6 +1195,15 @@ do
   | -silent | --silent | --silen | --sile | --sil)
     silent=yes ;;
 
+  -runstatedir | --runstatedir | --runstatedi | --runstated \
+  | --runstate | --runstat | --runsta | --runst | --runs \
+  | --run | --ru | --r)
+    ac_prev=runstatedir ;;
+  -runstatedir=* | --runstatedir=* | --runstatedi=* | --runstated=* \
+  | --runstate=* | --runstat=* | --runsta=* | --runst=* | --runs=* \
+  | --run=* | --ru=* | --r=*)
+    runstatedir=$ac_optarg ;;
+
   -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
     ac_prev=sbindir ;;
   -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
@@ -1330,7 +1341,7 @@ fi
 for ac_var in	exec_prefix prefix bindir sbindir libexecdir datarootdir \
 		datadir sysconfdir sharedstatedir localstatedir includedir \
 		oldincludedir docdir infodir htmldir dvidir pdfdir psdir \
-		libdir localedir mandir
+		libdir localedir mandir runstatedir
 do
   eval ac_val=\$$ac_var
   # Remove trailing slashes.
@@ -1483,6 +1494,7 @@ Fine tuning of the installation directories:
   --sysconfdir=DIR        read-only single-machine data [PREFIX/etc]
   --sharedstatedir=DIR    modifiable architecture-independent data [PREFIX/com]
   --localstatedir=DIR     modifiable single-machine data [PREFIX/var]
+  --runstatedir=DIR       modifiable per-process data [LOCALSTATEDIR/run]
   --libdir=DIR            object code libraries [EPREFIX/lib]
   --includedir=DIR        C header files [PREFIX/include]
   --oldincludedir=DIR     C header files for non-gcc [/usr/include]
@@ -15026,7 +15038,7 @@ else
     We can't simply define LARGE_OFF_T to be 9223372036854775807,
     since some C++ compilers masquerading as C compilers
     incorrectly reject 9223372036854775807.  */
-#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62))
+#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31))
   int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721
 		       && LARGE_OFF_T % 2147483647 == 1)
 		      ? 1 : -1];
@@ -15072,7 +15084,7 @@ else
     We can't simply define LARGE_OFF_T to be 9223372036854775807,
     since some C++ compilers masquerading as C compilers
     incorrectly reject 9223372036854775807.  */
-#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62))
+#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31))
   int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721
 		       && LARGE_OFF_T % 2147483647 == 1)
 		      ? 1 : -1];
@@ -15096,7 +15108,7 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
     We can't simply define LARGE_OFF_T to be 9223372036854775807,
     since some C++ compilers masquerading as C compilers
     incorrectly reject 9223372036854775807.  */
-#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62))
+#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31))
   int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721
 		       && LARGE_OFF_T % 2147483647 == 1)
 		      ? 1 : -1];
@@ -15141,7 +15153,7 @@ else
     We can't simply define LARGE_OFF_T to be 9223372036854775807,
     since some C++ compilers masquerading as C compilers
     incorrectly reject 9223372036854775807.  */
-#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62))
+#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31))
   int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721
 		       && LARGE_OFF_T % 2147483647 == 1)
 		      ? 1 : -1];
@@ -15165,7 +15177,7 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
     We can't simply define LARGE_OFF_T to be 9223372036854775807,
     since some C++ compilers masquerading as C compilers
     incorrectly reject 9223372036854775807.  */
-#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62))
+#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31))
   int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721
 		       && LARGE_OFF_T % 2147483647 == 1)
 		      ? 1 : -1];
@@ -16301,32 +16313,6 @@ esac
 
 fi
 
-ac_fn_c_check_func "$LINENO" "random" "ac_cv_func_random"
-if test "x$ac_cv_func_random" = xyes; then :
-  $as_echo "#define HAVE_RANDOM 1" >>confdefs.h
-
-else
-  case " $LIBOBJS " in
-  *" random.$ac_objext "* ) ;;
-  *) LIBOBJS="$LIBOBJS random.$ac_objext"
- ;;
-esac
-
-fi
-
-ac_fn_c_check_func "$LINENO" "srandom" "ac_cv_func_srandom"
-if test "x$ac_cv_func_srandom" = xyes; then :
-  $as_echo "#define HAVE_SRANDOM 1" >>confdefs.h
-
-else
-  case " $LIBOBJS " in
-  *" srandom.$ac_objext "* ) ;;
-  *) LIBOBJS="$LIBOBJS srandom.$ac_objext"
- ;;
-esac
-
-fi
-
 ac_fn_c_check_func "$LINENO" "strlcat" "ac_cv_func_strlcat"
 if test "x$ac_cv_func_strlcat" = xyes; then :
   $as_echo "#define HAVE_STRLCAT 1" >>confdefs.h
diff --git a/configure.ac b/configure.ac
index ed3cdb9a8e..b36b32ed94 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1822,8 +1822,6 @@ AC_REPLACE_FUNCS(m4_normalize([
 	mkdtemp
 	pread
 	pwrite
-	random
-	srandom
 	strlcat
 	strlcpy
 	strnlen
diff --git a/contrib/amcheck/verify_nbtree.c b/contrib/amcheck/verify_nbtree.c
index d19f73127c..b250ae912b 100644
--- a/contrib/amcheck/verify_nbtree.c
+++ b/contrib/amcheck/verify_nbtree.c
@@ -32,6 +32,7 @@
 #include "catalog/index.h"
 #include "catalog/pg_am.h"
 #include "commands/tablecmds.h"
+#include "common/pg_prng.h"
 #include "lib/bloomfilter.h"
 #include "miscadmin.h"
 #include "storage/lmgr.h"
@@ -465,8 +466,8 @@ bt_check_every_level(Relation rel, Relation heaprel, bool heapkeyspace,
 		total_pages = RelationGetNumberOfBlocks(rel);
 		total_elems = Max(total_pages * (MaxTIDsPerBTreePage / 3),
 						  (int64) state->rel->rd_rel->reltuples);
-		/* Random seed relies on backend srandom() call to avoid repetition */
-		seed = random();
+		/* Random seed relies on backend prng initialization to avoid repetition */
+		seed = pg_prng_u64(&pg_global_prng_state);
 		/* Create Bloom filter to fingerprint index */
 		state->filter = bloom_create(total_elems, maintenance_work_mem, seed);
 		state->heaptuplespresent = 0;
diff --git a/contrib/file_fdw/file_fdw.c b/contrib/file_fdw/file_fdw.c
index 2c2f149fb0..146b524076 100644
--- a/contrib/file_fdw/file_fdw.c
+++ b/contrib/file_fdw/file_fdw.c
@@ -1188,7 +1188,7 @@ file_acquire_sample_rows(Relation onerel, int elevel,
 				 * Found a suitable tuple, so save it, replacing one old tuple
 				 * at random
 				 */
-				int			k = (int) (targrows * sampler_random_fract(rstate.randstate));
+				int			k = (int) (targrows * sampler_random_fract(&rstate.randstate));
 
 				Assert(k >= 0 && k < targrows);
 				heap_freetuple(rows[k]);
diff --git a/contrib/postgres_fdw/postgres_fdw.c b/contrib/postgres_fdw/postgres_fdw.c
index 76d4fea21c..c139382170 100644
--- a/contrib/postgres_fdw/postgres_fdw.c
+++ b/contrib/postgres_fdw/postgres_fdw.c
@@ -5157,7 +5157,7 @@ analyze_row_processor(PGresult *res, int row, PgFdwAnalyzeState *astate)
 		if (astate->rowstoskip <= 0)
 		{
 			/* Choose a random reservoir element to replace. */
-			pos = (int) (targrows * sampler_random_fract(astate->rstate.randstate));
+			pos = (int) (targrows * sampler_random_fract(&astate->rstate.randstate));
 			Assert(pos >= 0 && pos < targrows);
 			heap_freetuple(astate->rows[pos]);
 		}
diff --git a/contrib/tablefunc/tablefunc.c b/contrib/tablefunc/tablefunc.c
index 779bd4415e..fdd117f81e 100644
--- a/contrib/tablefunc/tablefunc.c
+++ b/contrib/tablefunc/tablefunc.c
@@ -36,6 +36,7 @@
 
 #include "access/htup_details.h"
 #include "catalog/pg_type.h"
+#include "common/pg_prng.h"
 #include "executor/spi.h"
 #include "funcapi.h"
 #include "lib/stringinfo.h"
@@ -290,8 +291,8 @@ get_normal_pair(float8 *x1, float8 *x2)
 
 	do
 	{
-		u1 = (float8) random() / (float8) MAX_RANDOM_VALUE;
-		u2 = (float8) random() / (float8) MAX_RANDOM_VALUE;
+		u1 = pg_prng_f64(&pg_global_prng_state);
+		u2 = pg_prng_f64(&pg_global_prng_state);
 
 		v1 = (2.0 * u1) - 1.0;
 		v2 = (2.0 * u2) - 1.0;
diff --git a/contrib/tsm_system_rows/tsm_system_rows.c b/contrib/tsm_system_rows/tsm_system_rows.c
index 4996612902..1a46d4b143 100644
--- a/contrib/tsm_system_rows/tsm_system_rows.c
+++ b/contrib/tsm_system_rows/tsm_system_rows.c
@@ -69,7 +69,7 @@ static BlockNumber system_rows_nextsampleblock(SampleScanState *node, BlockNumbe
 static OffsetNumber system_rows_nextsampletuple(SampleScanState *node,
 												BlockNumber blockno,
 												OffsetNumber maxoffset);
-static uint32 random_relative_prime(uint32 n, SamplerRandomState randstate);
+static uint32 random_relative_prime(uint32 n, pg_prng_state *randstate);
 
 
 /*
@@ -213,25 +213,25 @@ system_rows_nextsampleblock(SampleScanState *node, BlockNumber nblocks)
 		if (sampler->step == 0)
 		{
 			/* Initialize now that we have scan descriptor */
-			SamplerRandomState randstate;
+			pg_prng_state randstate;
 
 			/* If relation is empty, there's nothing to scan */
 			if (nblocks == 0)
 				return InvalidBlockNumber;
 
 			/* We only need an RNG during this setup step */
-			sampler_random_init_state(sampler->seed, randstate);
+			sampler_random_init_state(sampler->seed, &randstate);
 
 			/* Compute nblocks/firstblock/step only once per query */
 			sampler->nblocks = nblocks;
 
 			/* Choose random starting block within the relation */
 			/* (Actually this is the predecessor of the first block visited) */
-			sampler->firstblock = sampler_random_fract(randstate) *
+			sampler->firstblock = sampler_random_fract(&randstate) *
 				sampler->nblocks;
 
 			/* Find relative prime as step size for linear probing */
-			sampler->step = random_relative_prime(sampler->nblocks, randstate);
+			sampler->step = random_relative_prime(sampler->nblocks, &randstate);
 		}
 
 		/* Reinitialize lb */
@@ -317,7 +317,7 @@ gcd(uint32 a, uint32 b)
  * (else return 1).
  */
 static uint32
-random_relative_prime(uint32 n, SamplerRandomState randstate)
+random_relative_prime(uint32 n, pg_prng_state *randstate)
 {
 	uint32		r;
 
diff --git a/contrib/tsm_system_time/tsm_system_time.c b/contrib/tsm_system_time/tsm_system_time.c
index 788d8f9a68..36acc6c106 100644
--- a/contrib/tsm_system_time/tsm_system_time.c
+++ b/contrib/tsm_system_time/tsm_system_time.c
@@ -69,7 +69,7 @@ static BlockNumber system_time_nextsampleblock(SampleScanState *node, BlockNumbe
 static OffsetNumber system_time_nextsampletuple(SampleScanState *node,
 												BlockNumber blockno,
 												OffsetNumber maxoffset);
-static uint32 random_relative_prime(uint32 n, SamplerRandomState randstate);
+static uint32 random_relative_prime(uint32 n, pg_prng_state *randstate);
 
 
 /*
@@ -224,25 +224,25 @@ system_time_nextsampleblock(SampleScanState *node, BlockNumber nblocks)
 		if (sampler->step == 0)
 		{
 			/* Initialize now that we have scan descriptor */
-			SamplerRandomState randstate;
+			pg_prng_state randstate;
 
 			/* If relation is empty, there's nothing to scan */
 			if (nblocks == 0)
 				return InvalidBlockNumber;
 
 			/* We only need an RNG during this setup step */
-			sampler_random_init_state(sampler->seed, randstate);
+			sampler_random_init_state(sampler->seed, &randstate);
 
 			/* Compute nblocks/firstblock/step only once per query */
 			sampler->nblocks = nblocks;
 
 			/* Choose random starting block within the relation */
 			/* (Actually this is the predecessor of the first block visited) */
-			sampler->firstblock = sampler_random_fract(randstate) *
+			sampler->firstblock = sampler_random_fract(&randstate) *
 				sampler->nblocks;
 
 			/* Find relative prime as step size for linear probing */
-			sampler->step = random_relative_prime(sampler->nblocks, randstate);
+			sampler->step = random_relative_prime(sampler->nblocks, &randstate);
 		}
 
 		/* Reinitialize lb and start_time */
@@ -330,7 +330,7 @@ gcd(uint32 a, uint32 b)
  * (else return 1).
  */
 static uint32
-random_relative_prime(uint32 n, SamplerRandomState randstate)
+random_relative_prime(uint32 n, pg_prng_state *randstate)
 {
 	uint32		r;
 
diff --git a/src/backend/access/gin/ginget.c b/src/backend/access/gin/ginget.c
index 03191e016c..3c2f24b653 100644
--- a/src/backend/access/gin/ginget.c
+++ b/src/backend/access/gin/ginget.c
@@ -16,6 +16,7 @@
 
 #include "access/gin_private.h"
 #include "access/relscan.h"
+#include "common/pg_prng.h"
 #include "miscadmin.h"
 #include "storage/predicate.h"
 #include "utils/datum.h"
@@ -787,7 +788,7 @@ entryLoadMoreItems(GinState *ginstate, GinScanEntry entry,
 	}
 }
 
-#define gin_rand() (((double) random()) / ((double) MAX_RANDOM_VALUE))
+#define gin_rand() pg_prng_f64(&pg_global_prng_state)
 #define dropItem(e) ( gin_rand() > ((double)GinFuzzySearchLimit)/((double)((e)->predictNumberResult)) )
 
 /*
diff --git a/src/backend/access/gist/gistutil.c b/src/backend/access/gist/gistutil.c
index 43ba03b6eb..0eff4ade84 100644
--- a/src/backend/access/gist/gistutil.c
+++ b/src/backend/access/gist/gistutil.c
@@ -19,6 +19,7 @@
 #include "access/htup_details.h"
 #include "access/reloptions.h"
 #include "catalog/pg_opclass.h"
+#include "common/pg_prng.h"
 #include "storage/indexfsm.h"
 #include "storage/lmgr.h"
 #include "utils/float.h"
@@ -507,7 +508,7 @@ gistchoose(Relation r, Page p, IndexTuple it,	/* it has compressed entry */
 			if (keep_current_best == -1)
 			{
 				/* we didn't make the random choice yet for this old best */
-				keep_current_best = (random() <= (MAX_RANDOM_VALUE / 2)) ? 1 : 0;
+				keep_current_best = pg_prng_bool(&pg_global_prng_state) ? 1 : 0;
 			}
 			if (keep_current_best == 0)
 			{
diff --git a/src/backend/access/nbtree/nbtinsert.c b/src/backend/access/nbtree/nbtinsert.c
index 7355e1dba1..37d8840ce0 100644
--- a/src/backend/access/nbtree/nbtinsert.c
+++ b/src/backend/access/nbtree/nbtinsert.c
@@ -19,6 +19,7 @@
 #include "access/nbtxlog.h"
 #include "access/transam.h"
 #include "access/xloginsert.h"
+#include "common/pg_prng.h"
 #include "lib/qunique.h"
 #include "miscadmin.h"
 #include "storage/lmgr.h"
@@ -968,7 +969,7 @@ _bt_findinsertloc(Relation rel,
 
 			if (P_RIGHTMOST(opaque) ||
 				_bt_compare(rel, itup_key, page, P_HIKEY) != 0 ||
-				random() <= (MAX_RANDOM_VALUE / 100))
+				pg_prng_f64(&pg_global_prng_state) <= 0.01)
 				break;
 
 			_bt_stepright(rel, insertstate, stack);
diff --git a/src/backend/access/spgist/spgdoinsert.c b/src/backend/access/spgist/spgdoinsert.c
index 70557bcf3d..5389c93366 100644
--- a/src/backend/access/spgist/spgdoinsert.c
+++ b/src/backend/access/spgist/spgdoinsert.c
@@ -19,6 +19,7 @@
 #include "access/spgist_private.h"
 #include "access/spgxlog.h"
 #include "access/xloginsert.h"
+#include "common/pg_prng.h"
 #include "miscadmin.h"
 #include "storage/bufmgr.h"
 #include "utils/rel.h"
@@ -2210,7 +2211,7 @@ spgdoinsert(Relation index, SpGistState *state,
 				if (out.resultType == spgAddNode)
 					elog(ERROR, "cannot add a node to an allTheSame inner tuple");
 				else if (out.resultType == spgMatchNode)
-					out.result.matchNode.nodeN = random() % innerTuple->nNodes;
+					out.result.matchNode.nodeN = pg_prng_u32(&pg_global_prng_state) % innerTuple->nNodes;
 			}
 
 			switch (out.resultType)
diff --git a/src/backend/access/transam/xact.c b/src/backend/access/transam/xact.c
index 6597ec45a9..d0557be7c9 100644
--- a/src/backend/access/transam/xact.c
+++ b/src/backend/access/transam/xact.c
@@ -37,6 +37,7 @@
 #include "commands/async.h"
 #include "commands/tablecmds.h"
 #include "commands/trigger.h"
+#include "common/pg_prng.h"
 #include "executor/spi.h"
 #include "libpq/be-fsstubs.h"
 #include "libpq/pqsignal.h"
@@ -1939,7 +1940,7 @@ StartTransaction(void)
 	/* Determine if statements are logged in this transaction */
 	xact_is_sampled = log_xact_sample_rate != 0 &&
 		(log_xact_sample_rate == 1 ||
-		 random() <= log_xact_sample_rate * MAX_RANDOM_VALUE);
+		 pg_prng_f64(&pg_global_prng_state) <= log_xact_sample_rate);
 
 	/*
 	 * initialize current transaction state fields
diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index 8bfb2ad958..fe623393d7 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -38,6 +38,7 @@
 #include "commands/progress.h"
 #include "commands/tablecmds.h"
 #include "commands/vacuum.h"
+#include "common/pg_prng.h"
 #include "executor/executor.h"
 #include "foreign/fdwapi.h"
 #include "miscadmin.h"
@@ -1173,7 +1174,7 @@ acquire_sample_rows(Relation onerel, int elevel,
 	OldestXmin = GetOldestNonRemovableTransactionId(onerel);
 
 	/* Prepare for sampling block numbers */
-	randseed = random();
+	randseed = pg_prng_i32(&pg_global_prng_state);
 	nblocks = BlockSampler_Init(&bs, totalblocks, targrows, randseed);
 
 #ifdef USE_PREFETCH
@@ -1290,7 +1291,7 @@ acquire_sample_rows(Relation onerel, int elevel,
 					 * Found a suitable tuple, so save it, replacing one old
 					 * tuple at random
 					 */
-					int			k = (int) (targrows * sampler_random_fract(rstate.randstate));
+					int			k = (int) (targrows * sampler_random_fract(&rstate.randstate));
 
 					Assert(k >= 0 && k < targrows);
 					heap_freetuple(rows[k]);
diff --git a/src/backend/executor/nodeSamplescan.c b/src/backend/executor/nodeSamplescan.c
index 44232d50d0..09c34e96fa 100644
--- a/src/backend/executor/nodeSamplescan.c
+++ b/src/backend/executor/nodeSamplescan.c
@@ -17,6 +17,7 @@
 #include "access/relscan.h"
 #include "access/tableam.h"
 #include "access/tsmapi.h"
+#include "common/pg_prng.h"
 #include "executor/executor.h"
 #include "executor/nodeSamplescan.h"
 #include "miscadmin.h"
@@ -154,7 +155,7 @@ ExecInitSampleScan(SampleScan *node, EState *estate, int eflags)
 	 * do this just once, since the seed shouldn't change over rescans.
 	 */
 	if (tsc->repeatable == NULL)
-		scanstate->seed = random();
+		scanstate->seed = pg_prng_i32(&pg_global_prng_state);
 
 	/*
 	 * Finally, initialize the TABLESAMPLE method handler.
diff --git a/src/backend/optimizer/geqo/geqo_random.c b/src/backend/optimizer/geqo/geqo_random.c
index f21bc047e6..8b42a9ffba 100644
--- a/src/backend/optimizer/geqo/geqo_random.c
+++ b/src/backend/optimizer/geqo/geqo_random.c
@@ -21,14 +21,7 @@ geqo_set_seed(PlannerInfo *root, double seed)
 {
 	GeqoPrivateData *private = (GeqoPrivateData *) root->join_search_private;
 
-	/*
-	 * XXX. This seeding algorithm could certainly be improved - but it is not
-	 * critical to do so.
-	 */
-	memset(private->random_state, 0, sizeof(private->random_state));
-	memcpy(private->random_state,
-		   &seed,
-		   Min(sizeof(private->random_state), sizeof(seed)));
+	pg_prng_fseed(&private->random_state, seed);
 }
 
 double
@@ -36,5 +29,5 @@ geqo_rand(PlannerInfo *root)
 {
 	GeqoPrivateData *private = (GeqoPrivateData *) root->join_search_private;
 
-	return pg_erand48(private->random_state);
+	return pg_prng_f64(&private->random_state);
 }
diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c
index e2a76ba055..13df3cc2e4 100644
--- a/src/backend/postmaster/postmaster.c
+++ b/src/backend/postmaster/postmaster.c
@@ -98,6 +98,7 @@
 #include "catalog/pg_control.h"
 #include "common/file_perm.h"
 #include "common/ip.h"
+#include "common/pg_prng.h"
 #include "common/string.h"
 #include "lib/ilist.h"
 #include "libpq/auth.h"
@@ -2675,19 +2676,22 @@ ClosePostmasterPorts(bool am_syslogger)
 void
 InitProcessGlobals(void)
 {
-	unsigned int rseed;
-
 	MyProcPid = getpid();
 	MyStartTimestamp = GetCurrentTimestamp();
 	MyStartTime = timestamptz_to_time_t(MyStartTimestamp);
 
 	/*
-	 * Set a different seed for random() in every process.  We want something
+	 * Set a different global seed in every process.  We want something
 	 * unpredictable, so if possible, use high-quality random bits for the
 	 * seed.  Otherwise, fall back to a seed based on timestamp and PID.
 	 */
-	if (!pg_strong_random(&rseed, sizeof(rseed)))
+	if (!pg_prng_strong_seed(&pg_global_prng_state))
 	{
+		uint64	rseed;
+
+		ereport(WARNING,
+				(errmsg_internal("pg_prng_strong_seed() failed, falling back to weaker seeding")));
+
 		/*
 		 * Since PIDs and timestamps tend to change more frequently in their
 		 * least significant bits, shift the timestamp left to allow a larger
@@ -2698,8 +2702,9 @@ InitProcessGlobals(void)
 		rseed = ((uint64) MyProcPid) ^
 			((uint64) MyStartTimestamp << 12) ^
 			((uint64) MyStartTimestamp >> 20);
+
+		pg_prng_seed(&pg_global_prng_state, rseed);
 	}
-	srandom(rseed);
 }
 
 
diff --git a/src/backend/storage/file/fd.c b/src/backend/storage/file/fd.c
index f9cda6906d..431931bcfe 100644
--- a/src/backend/storage/file/fd.c
+++ b/src/backend/storage/file/fd.c
@@ -92,6 +92,7 @@
 #include "catalog/pg_tablespace.h"
 #include "common/file_perm.h"
 #include "common/file_utils.h"
+#include "common/pg_prng.h"
 #include "miscadmin.h"
 #include "pgstat.h"
 #include "port/pg_iovec.h"
@@ -2938,7 +2939,7 @@ SetTempTablespaces(Oid *tableSpaces, int numSpaces)
 	 * available tablespaces.
 	 */
 	if (numSpaces > 1)
-		nextTempTableSpace = random() % numSpaces;
+		nextTempTableSpace = pg_prng_u32(&pg_global_prng_state) % numSpaces;
 	else
 		nextTempTableSpace = 0;
 }
diff --git a/src/backend/storage/ipc/dsm.c b/src/backend/storage/ipc/dsm.c
index b461a5f7e9..e97844614e 100644
--- a/src/backend/storage/ipc/dsm.c
+++ b/src/backend/storage/ipc/dsm.c
@@ -33,6 +33,7 @@
 #endif
 #include <sys/stat.h>
 
+#include "common/pg_prng.h"
 #include "lib/ilist.h"
 #include "miscadmin.h"
 #include "port/pg_bitutils.h"
@@ -180,7 +181,7 @@ dsm_postmaster_startup(PGShmemHeader *shim)
 	{
 		Assert(dsm_control_address == NULL);
 		Assert(dsm_control_mapped_size == 0);
-		dsm_control_handle = random() << 1; /* Even numbers only */
+		dsm_control_handle = pg_prng_u32(&pg_global_prng_state) << 1; /* Even numbers only */
 		if (dsm_control_handle == DSM_HANDLE_INVALID)
 			continue;
 		if (dsm_impl_op(DSM_OP_CREATE, dsm_control_handle, segsize,
@@ -536,7 +537,7 @@ dsm_create(Size size, int flags)
 		for (;;)
 		{
 			Assert(seg->mapped_address == NULL && seg->mapped_size == 0);
-			seg->handle = random() << 1;	/* Even numbers only */
+			seg->handle = pg_prng_u32(&pg_global_prng_state) << 1;	/* Even numbers only */
 			if (seg->handle == DSM_HANDLE_INVALID)	/* Reserve sentinel */
 				continue;
 			if (dsm_impl_op(DSM_OP_CREATE, seg->handle, size, &seg->impl_private,
@@ -1237,7 +1238,7 @@ make_main_region_dsm_handle(int slot)
 	 */
 	handle = 1;
 	handle |= slot << 1;
-	handle |= random() << (pg_leftmost_one_pos32(dsm_control->maxitems) + 1);
+	handle |= pg_prng_i32(&pg_global_prng_state) << (pg_leftmost_one_pos32(dsm_control->maxitems) + 1);
 	return handle;
 }
 
diff --git a/src/backend/storage/lmgr/s_lock.c b/src/backend/storage/lmgr/s_lock.c
index 91322a40c1..74c6f251ce 100644
--- a/src/backend/storage/lmgr/s_lock.c
+++ b/src/backend/storage/lmgr/s_lock.c
@@ -50,6 +50,7 @@
 #include <time.h>
 #include <unistd.h>
 
+#include "common/pg_prng.h"
 #include "port/atomics.h"
 #include "storage/s_lock.h"
 
@@ -63,6 +64,7 @@
 slock_t		dummy_spinlock;
 
 static int	spins_per_delay = DEFAULT_SPINS_PER_DELAY;
+static pg_prng_state	prng_state;
 
 
 /*
@@ -143,8 +145,7 @@ perform_spin_delay(SpinDelayStatus *status)
 #endif
 
 		/* increase delay by a random fraction between 1X and 2X */
-		status->cur_delay += (int) (status->cur_delay *
-									((double) random() / (double) MAX_RANDOM_VALUE) + 0.5);
+		status->cur_delay += (int) (status->cur_delay * (pg_prng_f64(&prng_state) + 0.5));
 		/* wrap back to minimum delay when max is exceeded */
 		if (status->cur_delay > MAX_DELAY_USEC)
 			status->cur_delay = MIN_DELAY_USEC;
@@ -303,7 +304,7 @@ volatile struct test_lock_struct test_lock;
 int
 main()
 {
-	srandom((unsigned int) time(NULL));
+	pg_prng_seed(&prng_state, (unsigned int) time(NULL));
 
 	test_lock.pad1 = test_lock.pad2 = 0x44;
 
diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c
index 0775abe35d..ef6c27dade 100644
--- a/src/backend/tcop/postgres.c
+++ b/src/backend/tcop/postgres.c
@@ -42,6 +42,7 @@
 #include "catalog/pg_type.h"
 #include "commands/async.h"
 #include "commands/prepare.h"
+#include "common/pg_prng.h"
 #include "executor/spi.h"
 #include "jit/jit.h"
 #include "libpq/libpq.h"
@@ -2355,13 +2356,13 @@ check_log_duration(char *msec_str, bool was_logged)
 
 		/*
 		 * Do not log if log_statement_sample_rate = 0. Log a sample if
-		 * log_statement_sample_rate <= 1 and avoid unnecessary random() call
+		 * log_statement_sample_rate <= 1 and avoid unnecessary random call
 		 * if log_statement_sample_rate = 1.
 		 */
 		if (exceeded_sample_duration)
 			in_sample = log_statement_sample_rate != 0 &&
 				(log_statement_sample_rate == 1 ||
-				 random() <= log_statement_sample_rate * MAX_RANDOM_VALUE);
+				 pg_prng_f64(&pg_global_prng_state) <= log_statement_sample_rate);
 
 		if (exceeded_duration || in_sample || log_duration || xact_is_sampled)
 		{
diff --git a/src/backend/utils/adt/float.c b/src/backend/utils/adt/float.c
index 098bbb372b..9fc0b108dd 100644
--- a/src/backend/utils/adt/float.c
+++ b/src/backend/utils/adt/float.c
@@ -21,6 +21,7 @@
 
 #include "catalog/pg_type.h"
 #include "common/int.h"
+#include "common/pg_prng.h"
 #include "common/shortest_dec.h"
 #include "libpq/pqformat.h"
 #include "miscadmin.h"
@@ -65,7 +66,7 @@ float8		degree_c_one = 1.0;
 
 /* State for drandom() and setseed() */
 static bool drandom_seed_set = false;
-static unsigned short drandom_seed[3] = {0, 0, 0};
+static pg_prng_state drandom_seed = PG_PRNG_DEFAULT_STATE;
 
 /* Local function prototypes */
 static double sind_q1(double x);
@@ -2762,22 +2763,20 @@ drandom(PG_FUNCTION_ARGS)
 		 * Should that fail for some reason, we fall back on a lower-quality
 		 * seed based on current time and PID.
 		 */
-		if (!pg_strong_random(drandom_seed, sizeof(drandom_seed)))
+		if (!pg_strong_random(&drandom_seed, sizeof(drandom_seed)))
 		{
 			TimestampTz now = GetCurrentTimestamp();
 			uint64		iseed;
 
 			/* Mix the PID with the most predictable bits of the timestamp */
 			iseed = (uint64) now ^ ((uint64) MyProcPid << 32);
-			drandom_seed[0] = (unsigned short) iseed;
-			drandom_seed[1] = (unsigned short) (iseed >> 16);
-			drandom_seed[2] = (unsigned short) (iseed >> 32);
+			pg_prng_seed(&drandom_seed, iseed);
 		}
 		drandom_seed_set = true;
 	}
 
-	/* pg_erand48 produces desired result range [0.0 - 1.0) */
-	result = pg_erand48(drandom_seed);
+	/* produces desired result range [0.0 - 1.0) */
+	result = pg_prng_f64(&drandom_seed);
 
 	PG_RETURN_FLOAT8(result);
 }
@@ -2790,7 +2789,6 @@ Datum
 setseed(PG_FUNCTION_ARGS)
 {
 	float8		seed = PG_GETARG_FLOAT8(0);
-	uint64		iseed;
 
 	if (seed < -1 || seed > 1 || isnan(seed))
 		ereport(ERROR,
@@ -2798,11 +2796,7 @@ setseed(PG_FUNCTION_ARGS)
 				 errmsg("setseed parameter %g is out of allowed range [-1,1]",
 						seed)));
 
-	/* Use sign bit + 47 fractional bits to fill drandom_seed[] */
-	iseed = (int64) (seed * (float8) UINT64CONST(0x7FFFFFFFFFFF));
-	drandom_seed[0] = (unsigned short) iseed;
-	drandom_seed[1] = (unsigned short) (iseed >> 16);
-	drandom_seed[2] = (unsigned short) (iseed >> 32);
+	pg_prng_fseed(&drandom_seed, seed);
 	drandom_seed_set = true;
 
 	PG_RETURN_VOID();
diff --git a/src/backend/utils/misc/sampling.c b/src/backend/utils/misc/sampling.c
index 0c327e823f..f1c86150d8 100644
--- a/src/backend/utils/misc/sampling.c
+++ b/src/backend/utils/misc/sampling.c
@@ -49,7 +49,7 @@ BlockSampler_Init(BlockSampler bs, BlockNumber nblocks, int samplesize,
 	bs->t = 0;					/* blocks scanned so far */
 	bs->m = 0;					/* blocks selected so far */
 
-	sampler_random_init_state(randseed, bs->randstate);
+	sampler_random_init_state(randseed, &bs->randstate);
 
 	return Min(bs->n, bs->N);
 }
@@ -98,7 +98,7 @@ BlockSampler_Next(BlockSampler bs)
 	 * less than k, which means that we cannot fail to select enough blocks.
 	 *----------
 	 */
-	V = sampler_random_fract(bs->randstate);
+	V = sampler_random_fract(&bs->randstate);
 	p = 1.0 - (double) k / (double) K;
 	while (V < p)
 	{
@@ -136,10 +136,10 @@ reservoir_init_selection_state(ReservoirState rs, int n)
 	 * Reservoir sampling is not used anywhere where it would need to return
 	 * repeatable results so we can initialize it randomly.
 	 */
-	sampler_random_init_state(random(), rs->randstate);
+	sampler_random_init_state(pg_prng_u32(&pg_global_prng_state), &rs->randstate);
 
 	/* Initial value of W (for use when Algorithm Z is first applied) */
-	rs->W = exp(-log(sampler_random_fract(rs->randstate)) / n);
+	rs->W = exp(-log(sampler_random_fract(&rs->randstate)) / n);
 }
 
 double
@@ -154,7 +154,7 @@ reservoir_get_next_S(ReservoirState rs, double t, int n)
 		double		V,
 					quot;
 
-		V = sampler_random_fract(rs->randstate);	/* Generate V */
+		V = sampler_random_fract(&rs->randstate);	/* Generate V */
 		S = 0;
 		t += 1;
 		/* Note: "num" in Vitter's code is always equal to t - n */
@@ -186,7 +186,7 @@ reservoir_get_next_S(ReservoirState rs, double t, int n)
 						tmp;
 
 			/* Generate U and X */
-			U = sampler_random_fract(rs->randstate);
+			U = sampler_random_fract(&rs->randstate);
 			X = t * (W - 1.0);
 			S = floor(X);		/* S is tentatively set to floor(X) */
 			/* Test if U <= h(S)/cg(X) in the manner of (6.3) */
@@ -215,7 +215,7 @@ reservoir_get_next_S(ReservoirState rs, double t, int n)
 				y *= numer / denom;
 				denom -= 1;
 			}
-			W = exp(-log(sampler_random_fract(rs->randstate)) / n); /* Generate W in advance */
+			W = exp(-log(sampler_random_fract(&rs->randstate)) / n); /* Generate W in advance */
 			if (exp(log(y) / n) <= (t + X) / t)
 				break;
 		}
@@ -230,24 +230,22 @@ reservoir_get_next_S(ReservoirState rs, double t, int n)
  *----------
  */
 void
-sampler_random_init_state(long seed, SamplerRandomState randstate)
+sampler_random_init_state(long seed, pg_prng_state *randstate)
 {
-	randstate[0] = 0x330e;		/* same as pg_erand48, but could be anything */
-	randstate[1] = (unsigned short) seed;
-	randstate[2] = (unsigned short) (seed >> 16);
+	pg_prng_seed(randstate, (uint64_t) seed);
 }
 
 /* Select a random value R uniformly distributed in (0 - 1) */
 double
-sampler_random_fract(SamplerRandomState randstate)
+sampler_random_fract(pg_prng_state *randstate)
 {
 	double		res;
 
-	/* pg_erand48 returns a value in [0.0 - 1.0), so we must reject 0 */
+	/* pg_prng_f64 returned value in [0.0 - 1.0), so we must reject 0.0 */
 	do
 	{
-		res = pg_erand48(randstate);
-	} while (res == 0.0);
+		res = pg_prng_f64(randstate);
+	} while (unlikely(res == 0.0));
 	return res;
 }
 
@@ -266,22 +264,28 @@ double
 anl_random_fract(void)
 {
 	/* initialize if first time through */
-	if (oldrs.randstate[0] == 0)
-		sampler_random_init_state(random(), oldrs.randstate);
+	if (!oldrs.randstate_initialized)
+	{
+		sampler_random_init_state(pg_prng_u32(&pg_global_prng_state), &oldrs.randstate);
+		oldrs.randstate_initialized = true;
+	}
 
 	/* and compute a random fraction */
-	return sampler_random_fract(oldrs.randstate);
+	return sampler_random_fract(&oldrs.randstate);
 }
 
 double
 anl_init_selection_state(int n)
 {
 	/* initialize if first time through */
-	if (oldrs.randstate[0] == 0)
-		sampler_random_init_state(random(), oldrs.randstate);
+	if (!oldrs.randstate_initialized)
+	{
+		sampler_random_init_state(pg_prng_u32(&pg_global_prng_state), &oldrs.randstate);
+		oldrs.randstate_initialized = true;
+	}
 
 	/* Initial value of W (for use when Algorithm Z is first applied) */
-	return exp(-log(sampler_random_fract(oldrs.randstate)) / n);
+	return exp(-log(sampler_random_fract(&oldrs.randstate)) / n);
 }
 
 double
diff --git a/src/bin/initdb/initdb.c b/src/bin/initdb/initdb.c
index 1ed4808d53..af9f5169e9 100644
--- a/src/bin/initdb/initdb.c
+++ b/src/bin/initdb/initdb.c
@@ -66,6 +66,7 @@
 #include "common/file_perm.h"
 #include "common/file_utils.h"
 #include "common/logging.h"
+#include "common/pg_prng.h"
 #include "common/restricted_token.h"
 #include "common/string.h"
 #include "common/username.h"
@@ -880,9 +881,10 @@ choose_dsm_implementation(void)
 {
 #ifdef HAVE_SHM_OPEN
 	int			ntries = 10;
+	pg_prng_state	prng_state;
 
-	/* Initialize random(); this function is its only user in this program. */
-	srandom((unsigned int) (getpid() ^ time(NULL)));
+	/* Initialize pgng state this function is its only user in this program. */
+	pg_prng_seed(&prng_state, ((unsigned int) (getpid() ^ time(NULL))));
 
 	while (ntries > 0)
 	{
@@ -890,7 +892,7 @@ choose_dsm_implementation(void)
 		char		name[64];
 		int			fd;
 
-		handle = random();
+		handle = pg_prng_u32(&prng_state);
 		snprintf(name, 64, "/PostgreSQL.%u", handle);
 		if ((fd = shm_open(name, O_CREAT | O_RDWR | O_EXCL, 0600)) != -1)
 		{
diff --git a/src/bin/pg_test_fsync/pg_test_fsync.c b/src/bin/pg_test_fsync/pg_test_fsync.c
index fef31844fa..5b3c197aa6 100644
--- a/src/bin/pg_test_fsync/pg_test_fsync.c
+++ b/src/bin/pg_test_fsync/pg_test_fsync.c
@@ -15,6 +15,7 @@
 
 #include "access/xlogdefs.h"
 #include "common/logging.h"
+#include "common/pg_prng.h"
 #include "getopt_long.h"
 
 /*
@@ -71,6 +72,7 @@ static char full_buf[DEFAULT_XLOG_SEG_SIZE],
 static struct timeval start_t,
 			stop_t;
 static bool alarm_triggered = false;
+static pg_prng_state	prng_state;
 
 
 static void handle_args(int argc, char *argv[]);
@@ -117,6 +119,7 @@ main(int argc, char *argv[])
 	pqsignal(SIGHUP, signal_cleanup);
 #endif
 
+	pg_prng_strong_seed(&prng_state);
 	prepare_buf();
 
 	test_open();
@@ -233,7 +236,7 @@ prepare_buf(void)
 
 	/* write random data into buffer */
 	for (ops = 0; ops < DEFAULT_XLOG_SEG_SIZE; ops++)
-		full_buf[ops] = random();
+		full_buf[ops] = pg_prng_u32(&prng_state);
 
 	buf = (char *) TYPEALIGN(XLOG_BLCKSZ, full_buf);
 }
diff --git a/src/bin/pgbench/pgbench.c b/src/bin/pgbench/pgbench.c
index 433abd954b..64c7370ff5 100644
--- a/src/bin/pgbench/pgbench.c
+++ b/src/bin/pgbench/pgbench.c
@@ -58,6 +58,7 @@
 #endif
 
 #include "common/int.h"
+#include "common/pg_prng.h"
 #include "common/logging.h"
 #include "common/string.h"
 #include "common/username.h"
@@ -350,16 +351,8 @@ typedef struct StatsData
  */
 pg_time_usec_t epoch_shift;
 
-/*
- * Struct to keep random state.
- */
-typedef struct RandomState
-{
-	unsigned short xseed[3];
-} RandomState;
-
 /* Various random sequences are initialized from this one. */
-static RandomState base_random_sequence;
+static pg_prng_state	base_random_sequence;
 
 /* Synchronization barrier for start and connection */
 static THREAD_BARRIER_T barrier;
@@ -461,7 +454,7 @@ typedef struct
 	 * Separate randomness for each client. This is used for random functions
 	 * PGBENCH_RANDOM_* during the execution of the script.
 	 */
-	RandomState cs_func_rs;
+	pg_prng_state	 cs_func_rs;
 
 	int			use_file;		/* index in sql_script for this client */
 	int			command;		/* command number in script */
@@ -498,9 +491,9 @@ typedef struct
 	 * random state to make all of them independent of each other and
 	 * therefore deterministic at the thread level.
 	 */
-	RandomState ts_choose_rs;	/* random state for selecting a script */
-	RandomState ts_throttle_rs; /* random state for transaction throttling */
-	RandomState ts_sample_rs;	/* random state for log sampling */
+	pg_prng_state	ts_choose_rs;	/* random state for selecting a script */
+	pg_prng_state	ts_throttle_rs; /* random state for transaction throttling */
+	pg_prng_state	ts_sample_rs;	/* random state for log sampling */
 
 	int64		throttle_trigger;	/* previous/next throttling (us) */
 	FILE	   *logfile;		/* where to log, or NULL */
@@ -898,42 +891,28 @@ strtodouble(const char *str, bool errorOK, double *dv)
 }
 
 /*
- * Initialize a random state struct.
+ * Initialize a prng state struct.
  *
  * We derive the seed from base_random_sequence, which must be set up already.
  */
 static void
-initRandomState(RandomState *random_state)
+initRandomState(pg_prng_state *state)
 {
-	random_state->xseed[0] = (unsigned short)
-		(pg_jrand48(base_random_sequence.xseed) & 0xFFFF);
-	random_state->xseed[1] = (unsigned short)
-		(pg_jrand48(base_random_sequence.xseed) & 0xFFFF);
-	random_state->xseed[2] = (unsigned short)
-		(pg_jrand48(base_random_sequence.xseed) & 0xFFFF);
+	pg_prng_seed(state, pg_prng_u64(&base_random_sequence));
 }
 
+
 /*
- * Random number generator: uniform distribution from min to max inclusive.
+ * PRNG: uniform distribution from min to max inclusive.
  *
  * Although the limits are expressed as int64, you can't generate the full
  * int64 range in one call, because the difference of the limits mustn't
- * overflow int64.  In practice it's unwise to ask for more than an int32
- * range, because of the limited precision of pg_erand48().
+ * overflow int64. This is not checked.
  */
 static int64
-getrand(RandomState *random_state, int64 min, int64 max)
+getrand(pg_prng_state *state, int64 min, int64 max)
 {
-	/*
-	 * Odd coding is so that min and max have approximately the same chance of
-	 * being selected as do numbers between them.
-	 *
-	 * pg_erand48() is thread-safe and concurrent, which is why we use it
-	 * rather than random(), which in glibc is non-reentrant, and therefore
-	 * protected by a mutex, and therefore a bottleneck on machines with many
-	 * CPUs.
-	 */
-	return min + (int64) ((max - min + 1) * pg_erand48(random_state->xseed));
+	return min + (int64) pg_prng_u64_range(state, 0, max - min);
 }
 
 /*
@@ -942,8 +921,7 @@ getrand(RandomState *random_state, int64 min, int64 max)
  * value is exp(-parameter).
  */
 static int64
-getExponentialRand(RandomState *random_state, int64 min, int64 max,
-				   double parameter)
+getExponentialRand(pg_prng_state *state, int64 min, int64 max, double parameter)
 {
 	double		cut,
 				uniform,
@@ -953,7 +931,7 @@ getExponentialRand(RandomState *random_state, int64 min, int64 max,
 	Assert(parameter > 0.0);
 	cut = exp(-parameter);
 	/* erand in [0, 1), uniform in (0, 1] */
-	uniform = 1.0 - pg_erand48(random_state->xseed);
+	uniform = 1.0 - pg_prng_f64(state);
 
 	/*
 	 * inner expression in (cut, 1] (if parameter > 0), rand in [0, 1)
@@ -966,8 +944,7 @@ getExponentialRand(RandomState *random_state, int64 min, int64 max,
 
 /* random number generator: gaussian distribution from min to max inclusive */
 static int64
-getGaussianRand(RandomState *random_state, int64 min, int64 max,
-				double parameter)
+getGaussianRand(pg_prng_state *state, int64 min, int64 max, double parameter)
 {
 	double		stdev;
 	double		rand;
@@ -990,13 +967,13 @@ getGaussianRand(RandomState *random_state, int64 min, int64 max,
 	do
 	{
 		/*
-		 * pg_erand48 generates [0,1), but for the basic version of the
+		 * pg_prng_f64 generates [0,1), but for the basic version of the
 		 * Box-Muller transform the two uniformly distributed random numbers
 		 * are expected in (0, 1] (see
 		 * https://en.wikipedia.org/wiki/Box-Muller_transform)
 		 */
-		double		rand1 = 1.0 - pg_erand48(random_state->xseed);
-		double		rand2 = 1.0 - pg_erand48(random_state->xseed);
+		double		rand1 = 1.0 - pg_prng_f64(state);
+		double		rand2 = 1.0 - pg_prng_f64(state);
 
 		/* Box-Muller basic form transform */
 		double		var_sqrt = sqrt(-2.0 * log(rand1));
@@ -1026,7 +1003,7 @@ getGaussianRand(RandomState *random_state, int64 min, int64 max,
  * not be one.
  */
 static int64
-getPoissonRand(RandomState *random_state, double center)
+getPoissonRand(pg_prng_state *state, double center)
 {
 	/*
 	 * Use inverse transform sampling to generate a value > 0, such that the
@@ -1034,8 +1011,8 @@ getPoissonRand(RandomState *random_state, double center)
 	 */
 	double		uniform;
 
-	/* erand in [0, 1), uniform in (0, 1] */
-	uniform = 1.0 - pg_erand48(random_state->xseed);
+	/* pseudo-random value in [0, 1), uniform in (0, 1] */
+	uniform = 1.0 - pg_prng_f64(state);
 
 	return (int64) (-log(uniform) * center + 0.5);
 }
@@ -1048,7 +1025,7 @@ getPoissonRand(RandomState *random_state, double center)
  * This works for s > 1.0, but may perform badly for s very close to 1.0.
  */
 static int64
-computeIterativeZipfian(RandomState *random_state, int64 n, double s)
+computeIterativeZipfian(pg_prng_state *state, int64 n, double s)
 {
 	double		b = pow(2.0, s - 1.0);
 	double		x,
@@ -1063,8 +1040,8 @@ computeIterativeZipfian(RandomState *random_state, int64 n, double s)
 	while (true)
 	{
 		/* random variates */
-		u = pg_erand48(random_state->xseed);
-		v = pg_erand48(random_state->xseed);
+		u = pg_prng_f64(state);
+		v = pg_prng_f64(state);
 
 		x = floor(pow(u, -1.0 / (s - 1.0)));
 
@@ -1078,14 +1055,14 @@ computeIterativeZipfian(RandomState *random_state, int64 n, double s)
 
 /* random number generator: zipfian distribution from min to max inclusive */
 static int64
-getZipfianRand(RandomState *random_state, int64 min, int64 max, double s)
+getZipfianRand(pg_prng_state *state, int64 min, int64 max, double s)
 {
 	int64		n = max - min + 1;
 
 	/* abort if parameter is invalid */
 	Assert(MIN_ZIPFIAN_PARAM <= s && s <= MAX_ZIPFIAN_PARAM);
 
-	return min - 1 + computeIterativeZipfian(random_state, n, s);
+	return min - 1 + computeIterativeZipfian(state, n, s);
 }
 
 /*
@@ -1142,7 +1119,7 @@ getHashMurmur2(int64 val, uint64 seed)
  * For small sizes, this generates each of the (size!) possible permutations
  * of integers in the range [0, size) with roughly equal probability.  Once
  * the size is larger than 20, the number of possible permutations exceeds the
- * number of distinct states of the internal pseudorandom number generators,
+ * number of distinct states of the internal pseudorandom number generator,
  * and so not all possible permutations can be generated, but the permutations
  * chosen should continue to give the appearance of being random.
  *
@@ -1152,25 +1129,19 @@ getHashMurmur2(int64 val, uint64 seed)
 static int64
 permute(const int64 val, const int64 isize, const int64 seed)
 {
-	RandomState random_state1;
-	RandomState random_state2;
-	uint64		size;
-	uint64		v;
-	int			masklen;
-	uint64		mask;
-	int			i;
+	/* using a high-end PRNG is probably overkill */
+	pg_prng_state	state;
+	uint64			size;
+	uint64			v;
+	int				masklen;
+	uint64			mask;
+	int				i;
 
 	if (isize < 2)
 		return 0;				/* nothing to permute */
 
-	/* Initialize a pair of random states using the seed */
-	random_state1.xseed[0] = seed & 0xFFFF;
-	random_state1.xseed[1] = (seed >> 16) & 0xFFFF;
-	random_state1.xseed[2] = (seed >> 32) & 0xFFFF;
-
-	random_state2.xseed[0] = (((uint64) seed) >> 48) & 0xFFFF;
-	random_state2.xseed[1] = seed & 0xFFFF;
-	random_state2.xseed[2] = (seed >> 16) & 0xFFFF;
+	/* Initialize prng state using the seed */
+	pg_prng_seed(&state, (uint64) seed);
 
 	/* Computations are performed on unsigned values */
 	size = (uint64) isize;
@@ -1216,8 +1187,8 @@ permute(const int64 val, const int64 isize, const int64 seed)
 					t;
 
 		/* Random multiply (by an odd number), XOR and rotate of lower half */
-		m = (uint64) getrand(&random_state1, 0, mask) | 1;
-		r = (uint64) getrand(&random_state2, 0, mask);
+		m = (pg_prng_u64(&state) & mask) | 1;
+		r = pg_prng_u64(&state) & mask;
 		if (v <= mask)
 		{
 			v = ((v * m) ^ r) & mask;
@@ -1225,8 +1196,8 @@ permute(const int64 val, const int64 isize, const int64 seed)
 		}
 
 		/* Random multiply (by an odd number), XOR and rotate of upper half */
-		m = (uint64) getrand(&random_state1, 0, mask) | 1;
-		r = (uint64) getrand(&random_state2, 0, mask);
+		m = (pg_prng_u64(&state) & mask) | 1;
+		r = pg_prng_u64(&state) & mask;
 		t = size - 1 - v;
 		if (t <= mask)
 		{
@@ -1236,7 +1207,7 @@ permute(const int64 val, const int64 isize, const int64 seed)
 		}
 
 		/* Random offset */
-		r = (uint64) getrand(&random_state2, 0, size - 1);
+		r = pg_prng_u64(&state) % (size - 1);
 		v = (v + r) % size;
 	}
 
@@ -3827,7 +3798,7 @@ doLog(TState *thread, CState *st,
 	 * to the random sample.
 	 */
 	if (sample_rate != 0.0 &&
-		pg_erand48(thread->ts_sample_rs.xseed) > sample_rate)
+		pg_prng_f64(&thread->ts_sample_rs) > sample_rate)
 		return;
 
 	/* should we aggregate the results or not? */
@@ -5763,12 +5734,11 @@ set_random_seed(const char *seed)
 
 	if (seed != NULL)
 		pg_log_info("setting random seed to %llu", (unsigned long long) iseed);
+
 	random_seed = iseed;
 
 	/* Fill base_random_sequence with low-order bits of seed */
-	base_random_sequence.xseed[0] = iseed & 0xFFFF;
-	base_random_sequence.xseed[1] = (iseed >> 16) & 0xFFFF;
-	base_random_sequence.xseed[2] = (iseed >> 32) & 0xFFFF;
+	pg_prng_seed(&base_random_sequence, (uint64_t) iseed);
 
 	return true;
 }
@@ -6439,9 +6409,7 @@ main(int argc, char **argv)
 	/* set default seed for hash functions */
 	if (lookupVariable(&state[0], "default_seed") == NULL)
 	{
-		uint64		seed =
-		((uint64) pg_jrand48(base_random_sequence.xseed) & 0xFFFFFFFF) |
-		(((uint64) pg_jrand48(base_random_sequence.xseed) & 0xFFFFFFFF) << 32);
+		uint64		seed = pg_prng_u64(&base_random_sequence);
 
 		for (i = 0; i < nclients; i++)
 			if (!putVariableInt(&state[i], "startup", "default_seed", (int64) seed))
diff --git a/src/bin/pgbench/t/001_pgbench_with_server.pl b/src/bin/pgbench/t/001_pgbench_with_server.pl
index ef53f6b2d9..13c9204a3d 100644
--- a/src/bin/pgbench/t/001_pgbench_with_server.pl
+++ b/src/bin/pgbench/t/001_pgbench_with_server.pl
@@ -427,9 +427,9 @@ pgbench(
 
 		# After explicit seeding, the four random checks (1-3,20) are
 		# deterministic
-		qr{command=1.: int 13\b},      # uniform random
-		qr{command=2.: int 116\b},     # exponential random
-		qr{command=3.: int 1498\b},    # gaussian random
+		qr{command=1.: int 17\b},      # uniform random
+		qr{command=2.: int 108\b},     # exponential random
+		qr{command=3.: int 1452\b},    # gaussian random
 		qr{command=4.: int 4\b},
 		qr{command=5.: int 5\b},
 		qr{command=6.: int 6\b},
@@ -496,6 +496,7 @@ pgbench(
 		qr{command=109.: boolean true\b},
 		qr{command=110.: boolean true\b},
 		qr{command=111.: boolean true\b},
+		qr{command=113.: boolean true\b},
 	],
 	'pgbench expressions',
 	{
@@ -639,8 +640,17 @@ SELECT :v0, :v1, :v2, :v3;
 \set t debug(0 <= :p and :p < :size and :p = permute(:v + :size, :size) and :p <> permute(:v + 1, :size))
 -- actual values
 \set t debug(permute(:v, 1) = 0)
-\set t debug(permute(0, 2, 5432) = 0 and permute(1, 2, 5432) = 1 and \
-             permute(0, 2, 5435) = 1 and permute(1, 2, 5435) = 0)
+\set t debug(permute(0, 2, 5431) = 1 and permute(1, 2, 5431) = 0 and \
+             permute(0, 2, 5432) = 0 and permute(1, 2, 5432) = 1)
+-- 63 bits tests for checking permute portability across architectures
+\set size debug(:max - 10)
+\set t debug(permute(:size-1, :size, 5432) = 4352241160009873020 and \
+             permute(:size-2, :size, 5432) = 4990004119691638710 and \
+             permute(:size-3, :size, 5432) = 5868029867256127549 and \
+             permute(:size-4, :size, 5432) = 1238830324886341378 and \
+             permute(:size-5, :size, 5432) = 7415914367102906897 and \
+             permute(:size-6, :size, 5432) = 3214501037984818995 and \
+             permute(:size-7, :size, 5432) =  600660351261124695)
 }
 	});
 
diff --git a/src/common/Makefile b/src/common/Makefile
index 880722fcf5..31c0dd366d 100644
--- a/src/common/Makefile
+++ b/src/common/Makefile
@@ -66,6 +66,7 @@ OBJS_COMMON = \
 	md5_common.o \
 	pg_get_line.o \
 	pg_lzcompress.o \
+	pg_prng.o \
 	pgfnames.o \
 	psprintf.o \
 	relpath.o \
diff --git a/src/common/pg_prng.c b/src/common/pg_prng.c
new file mode 100644
index 0000000000..df2054af79
--- /dev/null
+++ b/src/common/pg_prng.c
@@ -0,0 +1,244 @@
+/*
+ * Pseudo-Random Number Generator
+ *
+ * Copyright (c) 2021-2021, PostgreSQL Global Development Group
+ *
+ * Previous version was the 1988 (?) rand48 standard with 48 bits state LCG,
+ * designed for running on 32 bits or even 16 bits architectures, and to produce
+ * 32 bit ints and floats (i.e. *not* doubles).
+ *
+ * The implied 16-bits unpacking/packing may have a detrimental performance impact
+ * on modern 64 bits architectures.
+ *
+ * We (probably) want:
+ * - one reasonable default PRNG for all pg internal uses.
+ * - NOT to invent a new design!
+ * - something fast, close to rand48 (which basically does 2 arithmetic ops)
+ *   no need for something cryptographic though, which would imply slow
+ * - to produce 64 bits integers & doubles with a 52 bits mantissa
+ *   so state size > 64 bits.
+ * - a small state though, because we might generate quite a few of them
+ *   for different purposes so state size <= 256 or even <= 128 bits
+ * - the state to be aligned to whatever, so state size = 128 bits
+ * - 64 bits operations for efficiency on modern architectures,
+ *   but NOT 128 bits operations.
+ * - not to depend on special hardware for speed (eg MMX/SSE/AES).
+ * - not something with obvious known and relevant defects.
+ * - not something with "rights" attached.
+ *
+ * These constraints reduce a lot the available options from
+ * https://en.wikipedia.org/wiki/List_of_random_number_generators
+ *
+ * LCG
+ * - POSIX rand48: m = 2^48, a = 25214903917, c = 11, extract 47...16
+ * - MMIX by Donald Knuth: m = 2^64, a = 6364136223846793005, c = 1442695040888963407
+ * - very bad on low bits, which MUST NOT BE USED
+ *   a 128 bits would do, but no clear standards, and it would imply 128-bit ops,
+ *   see PCG below.
+ *
+ * PCG Family (https://www.pcg-random.org/)
+ * - this is basically an LCG with an improved outpout function
+ *   so as to avoid typical LCG issues and pass stats tests.
+ * - recommands state size to be twice the output size,
+ *   which seems a reasonable requirement.
+ * - this implies 128 bit ops for our target parameters,
+ *   otherwise it is a fairly good candidate for simplicity,
+ *   efficiency and quality.
+ *
+ * Xor-Shift-Rotate PRNGs:
+ * - a generic annoying feature of this generator class is that there is one
+ *   special all-zero state which must not be used, inducing a constraint on
+ *   initialization, and when the generator get close to it (i.e. many zeros
+ *   in the state) it takes some iterations to recover, with small lumps
+ *   of close/related/bad numbers generated in the process.
+ * Xoroshiro128+
+ * - fails statistical linearity tests in the low bits.
+ * Xoroshiro128**
+ *   https://prng.di.unimi.it/xoroshiro128starstar.c
+ * - mild and irrelevant issues: close to zero state, stats issues after some transforms
+ * Xoshiro256**
+ * - it looks good, but some issues (no big deal for pg usage IMO)
+ *   https://www.pcg-random.org/posts/a-quick-look-at-xoshiro256.html
+ *   mild problems getting out of closes-to-zero state
+ *
+ * MT19937-64
+ * + default in many places, standard
+ * - huge 2.5 KiB state (but TinyMT, 127 bits state space)
+ * - slow (but SFMT, twice as fast)
+ * - vulnerabilities on tinyMT?
+ *
+ * WELL
+ * - large state, 32-bit oriented
+ *
+ * ACORN Family (https://en.wikipedia.org/wiki/ACORN_(PRNG))
+ * - Fortran / double oriented, no C implementation found?!
+ * - medium large state "In practice we recommend using k > 10, M = 2^60 (for general application)
+ *   or M = 2^120 (for demanding applications requiring high-quality pseudo-random numbers
+ *   that will consistently pass all the tests in standard test packages such as TestU01)
+ *   and choose any odd value less than M for the seed."
+ *   k = 11 => 88 bytes/704-bits state, too large:-(
+ *
+ * Splitmix?
+ * Others?
+ *
+ * The conclusion is that we use xor-shift-rotate generator below.
+ */
+
+#include "c.h"
+#include "common/pg_prng.h"
+#include "port/pg_bitutils.h"
+#include <math.h>
+
+/* global state */
+pg_prng_state	pg_global_prng_state;
+
+#define FIRST_BIT_MASK UINT64CONST(0x8000000000000000)
+#define RIGHT_HALF_MASK UINT64CONST(0x00000000FFFFFFFF)
+#define DMANTISSA_MASK UINT64CONST(0x000FFFFFFFFFFFFF)
+
+/* 64-bits rotate left */
+static inline uint64
+rotl(const uint64 x, const int bits)
+{
+	return (x << bits) | (x >> (64 - bits));
+}
+
+/* another 64-bits generator is used for state initialization or iterations */
+static uint64
+splitmix64(uint64 * state)
+{
+	/* state update */
+	uint64	val = (*state += UINT64CONST(0x9E3779B97f4A7C15));
+
+	/* value extraction */
+	val = (val ^ (val >> 30)) * UINT64CONST(0xBF58476D1CE4E5B9);
+	val = (val ^ (val >> 27)) * UINT64CONST(0x94D049BB133111EB);
+
+	return val ^ (val >> 31);
+}
+
+/* seed prng state from a 64 bits integer, ensuring non zero */
+void
+pg_prng_seed(pg_prng_state *state, uint64 seed)
+{
+	state->s0 = splitmix64(&seed);
+	state->s1 = splitmix64(&seed);
+}
+
+/* seed with 53 bits (mantissa & sign) from a float */
+void
+pg_prng_fseed(pg_prng_state *state, double fseed)
+{
+	uint64 seed = (int64) (((double) DMANTISSA_MASK) * fseed);
+	pg_prng_seed(state, seed);
+}
+
+/* strong random seeding */
+bool
+pg_prng_strong_seed(pg_prng_state *state)
+{
+	bool ok = pg_strong_random((void *) state, sizeof(pg_prng_state));
+
+	/* avoid zero with Donald Knuth's LCG parameters */
+	if (unlikely(state->s0 == 0 && state->s1 == 0))
+	{
+		/* should it warn that something is amiss if we get there? */
+		pg_prng_state def = PG_PRNG_DEFAULT_STATE;
+		*state = def;
+	}
+
+	return ok;
+}
+
+/* generator & state update */
+static uint64
+xoroshiro128ss(pg_prng_state *state)
+{
+	const uint64	s0 = state->s0,
+					sx = state->s1 ^ s0,
+					val = rotl(s0 * 5, 7) * 9;
+
+	/* update state */
+	state->s0 = rotl(s0, 24) ^ sx ^ (sx << 16);
+	state->s1 = rotl(sx, 37);
+
+	return val;
+}
+
+/* u64 generator */
+uint64
+pg_prng_u64(pg_prng_state *state)
+{
+	return xoroshiro128ss(state);
+}
+
+/*
+ * select in a range with bitmask rejection.
+ *
+ * if range is empty, rmin is returned.
+ *
+ * the prng may advance by several states or none,
+ * depending on the range value.
+ */
+uint64
+pg_prng_u64_range(pg_prng_state *state, uint64 rmin, uint64 rmax)
+{
+	uint64 val;
+
+	if (likely(rmax > rmin))
+	{
+		uint64 range = rmax - rmin;
+
+		/* bit position is between 0 and 63, so rshift >= 0 */
+		uint32 rshift = 63 - pg_leftmost_one_pos64(range);
+
+		do
+		{
+			val = xoroshiro128ss(state) >> rshift;
+		}
+		while (unlikely(val > range));
+	}
+	else
+		val = 0;
+
+	return rmin + val;
+}
+
+/* i64 generator */
+int64
+pg_prng_i64(pg_prng_state *state)
+{
+	return (int64) xoroshiro128ss(state);
+}
+
+/* u32 generator */
+uint32
+pg_prng_u32(pg_prng_state *state)
+{
+	const uint64 v = xoroshiro128ss(state);
+	return (uint32) (((v >> 32) ^ v) & RIGHT_HALF_MASK);
+}
+
+/* i32 generator */
+int32
+pg_prng_i32(pg_prng_state *state)
+{
+	const uint64 v = xoroshiro128ss(state);
+	return (int32) (((v >> 32) ^ v) & RIGHT_HALF_MASK);
+}
+
+/* double generator */
+double
+pg_prng_f64(pg_prng_state *state)
+{
+	uint64 v = xoroshiro128ss(state);
+	return ldexp((double) (v & DMANTISSA_MASK), -52);
+}
+
+/* bool generator */
+bool
+pg_prng_bool(pg_prng_state *state)
+{
+	uint64 v = xoroshiro128ss(state);
+	return (v & FIRST_BIT_MASK) == FIRST_BIT_MASK;
+}
diff --git a/src/include/common/pg_prng.h b/src/include/common/pg_prng.h
new file mode 100644
index 0000000000..55f0e3d6cb
--- /dev/null
+++ b/src/include/common/pg_prng.h
@@ -0,0 +1,37 @@
+/*-------------------------------------------------------------------------
+ *
+ * PRNG: internal Pseudo-Random Number Generator
+ *
+ * Copyright (c) 2021-2021, PostgreSQL Global Development Group
+ *
+ * src/include/common/pg_prng.h
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef PG_PRNG_H
+#define PG_PRNG_H
+
+/* 128 bits state */
+typedef struct pg_prng_state {
+	uint64	s0, s1;
+} pg_prng_state;
+
+/* global pseudo-random state */
+extern pg_prng_state	pg_global_prng_state;
+
+/* use Donald Knuth's LCG constants for default state */
+#define PG_PRNG_DEFAULT_STATE \
+	{ UINT64CONST(0x5851F42D4C957F2D), UINT64CONST(0x14057B7EF767814F) }
+
+extern void pg_prng_seed(pg_prng_state *state, uint64 seed);
+extern void pg_prng_fseed(pg_prng_state *state, double fseed);
+extern bool pg_prng_strong_seed(pg_prng_state *state);
+extern uint64 pg_prng_u64(pg_prng_state *state);
+extern uint64 pg_prng_u64_range(pg_prng_state *state, uint64 rmin, uint64 rmax);
+extern int64 pg_prng_i64(pg_prng_state *state);
+extern uint32 pg_prng_u32(pg_prng_state *state);
+extern int32 pg_prng_i32(pg_prng_state *state);
+extern double pg_prng_f64(pg_prng_state *state);
+extern bool pg_prng_bool(pg_prng_state *state);
+
+#endif							/* PG_PRNG_H */
diff --git a/src/include/optimizer/geqo.h b/src/include/optimizer/geqo.h
index 24dcdfb6cc..b28e4f084a 100644
--- a/src/include/optimizer/geqo.h
+++ b/src/include/optimizer/geqo.h
@@ -22,6 +22,7 @@
 #ifndef GEQO_H
 #define GEQO_H
 
+#include "common/pg_prng.h"
 #include "nodes/pathnodes.h"
 #include "optimizer/geqo_gene.h"
 
@@ -72,8 +73,8 @@ extern double Geqo_seed;		/* 0 .. 1 */
  */
 typedef struct
 {
-	List	   *initial_rels;	/* the base relations we are joining */
-	unsigned short random_state[3]; /* state for pg_erand48() */
+	List		   *initial_rels;	/* the base relations we are joining */
+	pg_prng_state	random_state;   /* PRNG state */
 } GeqoPrivateData;
 
 
diff --git a/src/include/port.h b/src/include/port.h
index 82f63de325..ef84d00ea0 100644
--- a/src/include/port.h
+++ b/src/include/port.h
@@ -356,11 +356,6 @@ extern int	gettimeofday(struct timeval *tp, struct timezone *tzp);
 #define pgoff_t off_t
 #endif
 
-extern double pg_erand48(unsigned short xseed[3]);
-extern long pg_lrand48(void);
-extern long pg_jrand48(unsigned short xseed[3]);
-extern void pg_srand48(long seed);
-
 #ifndef HAVE_FLS
 extern int	fls(int mask);
 #endif
@@ -446,10 +441,6 @@ extern size_t strlcpy(char *dst, const char *src, size_t siz);
 extern size_t strnlen(const char *str, size_t maxlen);
 #endif
 
-#if !defined(HAVE_RANDOM)
-extern long random(void);
-#endif
-
 #ifndef HAVE_SETENV
 extern int	setenv(const char *name, const char *value, int overwrite);
 #endif
@@ -458,10 +449,6 @@ extern int	setenv(const char *name, const char *value, int overwrite);
 extern int	unsetenv(const char *name);
 #endif
 
-#ifndef HAVE_SRANDOM
-extern void srandom(unsigned int seed);
-#endif
-
 #ifndef HAVE_DLOPEN
 extern void *dlopen(const char *file, int mode);
 extern void *dlsym(void *handle, const char *symbol);
diff --git a/src/include/utils/sampling.h b/src/include/utils/sampling.h
index a58d14281b..c0b1c6a645 100644
--- a/src/include/utils/sampling.h
+++ b/src/include/utils/sampling.h
@@ -13,15 +13,14 @@
 #ifndef SAMPLING_H
 #define SAMPLING_H
 
+#include "common/pg_prng.h"
 #include "storage/block.h"		/* for typedef BlockNumber */
 
 
 /* Random generator for sampling code */
-typedef unsigned short SamplerRandomState[3];
-
 extern void sampler_random_init_state(long seed,
-									  SamplerRandomState randstate);
-extern double sampler_random_fract(SamplerRandomState randstate);
+									  pg_prng_state *randstate);
+extern double sampler_random_fract(pg_prng_state *randstate);
 
 /* Block sampling methods */
 
@@ -32,7 +31,7 @@ typedef struct
 	int			n;				/* desired sample size */
 	BlockNumber t;				/* current block number */
 	int			m;				/* blocks selected so far */
-	SamplerRandomState randstate;	/* random generator state */
+	pg_prng_state randstate;	/* random generator state */
 } BlockSamplerData;
 
 typedef BlockSamplerData *BlockSampler;
@@ -46,8 +45,9 @@ extern BlockNumber BlockSampler_Next(BlockSampler bs);
 
 typedef struct
 {
-	double		W;
-	SamplerRandomState randstate;	/* random generator state */
+	double			W;
+	pg_prng_state	randstate;	/* random generator state */
+	bool			randstate_initialized;
 } ReservoirStateData;
 
 typedef ReservoirStateData *ReservoirState;
diff --git a/src/port/Makefile b/src/port/Makefile
index 52dbf5783f..b3754d8940 100644
--- a/src/port/Makefile
+++ b/src/port/Makefile
@@ -42,7 +42,6 @@ OBJS = \
 	$(PG_CRC32C_OBJS) \
 	bsearch_arg.o \
 	chklocale.o \
-	erand48.o \
 	inet_net_ntop.o \
 	noblock.o \
 	path.o \
diff --git a/src/port/erand48.c b/src/port/erand48.c
deleted file mode 100644
index a82ea94220..0000000000
--- a/src/port/erand48.c
+++ /dev/null
@@ -1,136 +0,0 @@
-/*-------------------------------------------------------------------------
- *
- * erand48.c
- *
- * This file supplies pg_erand48() and related functions, which except
- * for the names are just like the POSIX-standard erand48() family.
- * (We don't supply the full set though, only the ones we have found use
- * for in Postgres.  In particular, we do *not* implement lcong48(), so
- * that there is no need for the multiplier and addend to be variable.)
- *
- * We used to test for an operating system version rather than
- * unconditionally using our own, but (1) some versions of Cygwin have a
- * buggy erand48() that always returns zero and (2) as of 2011, glibc's
- * erand48() is strangely coded to be almost-but-not-quite thread-safe,
- * which doesn't matter for the backend but is important for pgbench.
- *
- * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group
- *
- * Portions Copyright (c) 1993 Martin Birgmeier
- * All rights reserved.
- *
- * You may redistribute unmodified or modified versions of this source
- * code provided that the above copyright notice and this and the
- * following conditions are retained.
- *
- * This software is provided ``as is'', and comes with no warranties
- * of any kind. I shall in no event be liable for anything that happens
- * to anyone/anything when using this software.
- *
- * IDENTIFICATION
- *	  src/port/erand48.c
- *
- *-------------------------------------------------------------------------
- */
-
-#include "c.h"
-
-#include <math.h>
-
-/* These values are specified by POSIX */
-#define RAND48_MULT		UINT64CONST(0x0005deece66d)
-#define RAND48_ADD		UINT64CONST(0x000b)
-
-/* POSIX specifies 0x330e's use in srand48, but the other bits are arbitrary */
-#define RAND48_SEED_0	(0x330e)
-#define RAND48_SEED_1	(0xabcd)
-#define RAND48_SEED_2	(0x1234)
-
-static unsigned short _rand48_seed[3] = {
-	RAND48_SEED_0,
-	RAND48_SEED_1,
-	RAND48_SEED_2
-};
-
-
-/*
- * Advance the 48-bit value stored in xseed[] to the next "random" number.
- *
- * Also returns the value of that number --- without masking it to 48 bits.
- * If caller uses the result, it must mask off the bits it wants.
- */
-static uint64
-_dorand48(unsigned short xseed[3])
-{
-	/*
-	 * We do the arithmetic in uint64; any type wider than 48 bits would work.
-	 */
-	uint64		in;
-	uint64		out;
-
-	in = (uint64) xseed[2] << 32 | (uint64) xseed[1] << 16 | (uint64) xseed[0];
-
-	out = in * RAND48_MULT + RAND48_ADD;
-
-	xseed[0] = out & 0xFFFF;
-	xseed[1] = (out >> 16) & 0xFFFF;
-	xseed[2] = (out >> 32) & 0xFFFF;
-
-	return out;
-}
-
-
-/*
- * Generate a random floating-point value using caller-supplied state.
- * Values are uniformly distributed over the interval [0.0, 1.0).
- */
-double
-pg_erand48(unsigned short xseed[3])
-{
-	uint64		x = _dorand48(xseed);
-
-	return ldexp((double) (x & UINT64CONST(0xFFFFFFFFFFFF)), -48);
-}
-
-/*
- * Generate a random non-negative integral value using internal state.
- * Values are uniformly distributed over the interval [0, 2^31).
- */
-long
-pg_lrand48(void)
-{
-	uint64		x = _dorand48(_rand48_seed);
-
-	return (x >> 17) & UINT64CONST(0x7FFFFFFF);
-}
-
-/*
- * Generate a random signed integral value using caller-supplied state.
- * Values are uniformly distributed over the interval [-2^31, 2^31).
- */
-long
-pg_jrand48(unsigned short xseed[3])
-{
-	uint64		x = _dorand48(xseed);
-
-	return (int32) ((x >> 16) & UINT64CONST(0xFFFFFFFF));
-}
-
-/*
- * Initialize the internal state using the given seed.
- *
- * Per POSIX, this uses only 32 bits from "seed" even if "long" is wider.
- * Hence, the set of possible seed values is smaller than it could be.
- * Better practice is to use caller-supplied state and initialize it with
- * random bits obtained from a high-quality source of random bits.
- *
- * Note: POSIX specifies a function seed48() that allows all 48 bits
- * of the internal state to be set, but we don't currently support that.
- */
-void
-pg_srand48(long seed)
-{
-	_rand48_seed[0] = RAND48_SEED_0;
-	_rand48_seed[1] = (unsigned short) seed;
-	_rand48_seed[2] = (unsigned short) (seed >> 16);
-}
diff --git a/src/port/random.c b/src/port/random.c
deleted file mode 100644
index 2dd59a0829..0000000000
--- a/src/port/random.c
+++ /dev/null
@@ -1,25 +0,0 @@
-/*-------------------------------------------------------------------------
- *
- * random.c
- *	  random() wrapper
- *
- * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group
- * Portions Copyright (c) 1994, Regents of the University of California
- *
- *
- * IDENTIFICATION
- *	  src/port/random.c
- *
- *-------------------------------------------------------------------------
- */
-
-#include "c.h"
-
-#include <math.h>
-
-
-long
-random(void)
-{
-	return pg_lrand48();
-}
diff --git a/src/port/srandom.c b/src/port/srandom.c
deleted file mode 100644
index cf1007b2ef..0000000000
--- a/src/port/srandom.c
+++ /dev/null
@@ -1,25 +0,0 @@
-/*-------------------------------------------------------------------------
- *
- * srandom.c
- *	  srandom() wrapper
- *
- * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group
- * Portions Copyright (c) 1994, Regents of the University of California
- *
- *
- * IDENTIFICATION
- *	  src/port/srandom.c
- *
- *-------------------------------------------------------------------------
- */
-
-#include "c.h"
-
-#include <math.h>
-
-
-void
-srandom(unsigned int seed)
-{
-	pg_srand48((long int) seed);
-}
diff --git a/src/test/modules/test_bloomfilter/test_bloomfilter.c b/src/test/modules/test_bloomfilter/test_bloomfilter.c
index 96c5011428..69425bd6fc 100644
--- a/src/test/modules/test_bloomfilter/test_bloomfilter.c
+++ b/src/test/modules/test_bloomfilter/test_bloomfilter.c
@@ -13,6 +13,7 @@
 #include "postgres.h"
 
 #include "fmgr.h"
+#include "common/pg_prng.h"
 #include "lib/bloomfilter.h"
 #include "miscadmin.h"
 
@@ -85,7 +86,7 @@ create_and_test_bloom(int power, int64 nelements, int callerseed)
 	 * random seed can be recreated through callerseed if the need arises.
 	 * (Don't assume that RAND_MAX cannot exceed PG_INT32_MAX.)
 	 */
-	seed = callerseed < 0 ? random() % PG_INT32_MAX : callerseed;
+	seed = callerseed < 0 ? pg_prng_i32(&pg_global_prng_state) % PG_INT32_MAX : callerseed;
 
 	/* Create Bloom filter, populate it, and report on false positive rate */
 	filter = bloom_create(nelements, bloom_work_mem, seed);
diff --git a/src/test/modules/test_integerset/test_integerset.c b/src/test/modules/test_integerset/test_integerset.c
index 21c6f49b37..3e8cb7a005 100644
--- a/src/test/modules/test_integerset/test_integerset.c
+++ b/src/test/modules/test_integerset/test_integerset.c
@@ -12,6 +12,7 @@
  */
 #include "postgres.h"
 
+#include "common/pg_prng.h"
 #include "fmgr.h"
 #include "lib/integerset.h"
 #include "miscadmin.h"
@@ -99,12 +100,16 @@ static void check_with_filler(IntegerSet *intset, uint64 x, uint64 value, uint64
 static void test_single_value_and_filler(uint64 value, uint64 filler_min, uint64 filler_max);
 static void test_huge_distances(void);
 
+static pg_prng_state	pr_state;
+
 /*
  * SQL-callable entry point to perform all tests.
  */
 Datum
 test_integerset(PG_FUNCTION_ARGS)
 {
+	pg_prng_strong_seed(&pr_state);
+
 	/* Tests for various corner cases */
 	test_empty();
 	test_huge_distances();
@@ -248,8 +253,7 @@ test_pattern(const test_spec *spec)
 		 * only a small part of the integer space is used.  We would very
 		 * rarely hit values that are actually in the set.
 		 */
-		x = (pg_lrand48() << 31) | pg_lrand48();
-		x = x % (last_int + 1000);
+		x = pg_prng_u64(&pr_state) % (last_int + 1000);
 
 		/* Do we expect this value to be present in the set? */
 		if (x >= last_int)
@@ -571,7 +575,7 @@ test_huge_distances(void)
 	 */
 	while (num_values < 1000)
 	{
-		val += pg_lrand48();
+		val += pg_prng_u32(&pr_state);
 		values[num_values++] = val;
 	}
 
diff --git a/src/test/modules/test_rbtree/test_rbtree.c b/src/test/modules/test_rbtree/test_rbtree.c
index 713ebd1b26..59a571185e 100644
--- a/src/test/modules/test_rbtree/test_rbtree.c
+++ b/src/test/modules/test_rbtree/test_rbtree.c
@@ -14,6 +14,7 @@
 #include "postgres.h"
 
 #include "fmgr.h"
+#include "common/pg_prng.h"
 #include "lib/rbtree.h"
 #include "utils/memutils.h"
 
@@ -108,7 +109,7 @@ GetPermutation(int size)
 	 */
 	for (i = 1; i < size; i++)
 	{
-		int			j = random() % (i + 1);
+		int			j = pg_prng_u32(&pg_global_prng_state) % (i + 1);
 
 		if (j < i)				/* avoid fetching undefined data if j=i */
 			permutation[i] = permutation[j];
@@ -320,7 +321,7 @@ testdelete(int size, int delsize)
 
 	for (i = 0; i < delsize; i++)
 	{
-		int			k = random() % size;
+		int			k = pg_prng_u32(&pg_global_prng_state) % size;
 
 		while (chosen[k])
 			k = (k + 1) % size;
diff --git a/src/tools/msvc/Mkvcbuild.pm b/src/tools/msvc/Mkvcbuild.pm
index 4362bd44fd..aa048d949f 100644
--- a/src/tools/msvc/Mkvcbuild.pm
+++ b/src/tools/msvc/Mkvcbuild.pm
@@ -99,9 +99,9 @@ sub mkvcbuild
 	$solution = CreateSolution($vsVersion, $config);
 
 	our @pgportfiles = qw(
-	  chklocale.c explicit_bzero.c fls.c getpeereid.c getrusage.c inet_aton.c random.c
-	  srandom.c getaddrinfo.c gettimeofday.c inet_net_ntop.c kill.c open.c
-	  erand48.c snprintf.c strlcat.c strlcpy.c dirmod.c noblock.c path.c
+	  chklocale.c explicit_bzero.c fls.c getpeereid.c getrusage.c inet_aton.c
+	  getaddrinfo.c gettimeofday.c inet_net_ntop.c kill.c open.c
+	  snprintf.c strlcat.c strlcpy.c dirmod.c noblock.c path.c
 	  dirent.c dlopen.c getopt.c getopt_long.c link.c
 	  pread.c preadv.c pwrite.c pwritev.c pg_bitutils.c
 	  pg_strong_random.c pgcheckdir.c pgmkdirp.c pgsleep.c pgstrcasecmp.c
@@ -127,9 +127,9 @@ sub mkvcbuild
 	  config_info.c controldata_utils.c d2s.c encnames.c exec.c
 	  f2s.c file_perm.c file_utils.c hashfn.c ip.c jsonapi.c
 	  keywords.c kwlookup.c link-canary.c md5_common.c
-	  pg_get_line.c pg_lzcompress.c pgfnames.c psprintf.c relpath.c rmtree.c
-	  saslprep.c scram-common.c string.c stringinfo.c unicode_norm.c username.c
-	  wait_error.c wchar.c);
+	  pg_get_line.c pg_lzcompress.c pg_prng.c pgfnames.c psprintf.c relpath.c
+	  rmtree.c saslprep.c scram-common.c string.c stringinfo.c unicode_norm.c
+	  username.c wait_error.c wchar.c);
 
 	if ($solution->{options}->{openssl})
 	{
diff --git a/src/tools/testint128.c b/src/tools/testint128.c
index 71c345969a..43d569aeb5 100644
--- a/src/tools/testint128.c
+++ b/src/tools/testint128.c
@@ -27,6 +27,7 @@
 #endif
 
 #include "common/int128.h"
+#include "common/pg_prng.h"
 
 /*
  * We assume the parts of this union are laid out compatibly.
@@ -61,27 +62,11 @@ my_int128_compare(int128 x, int128 y)
 	return 0;
 }
 
-/*
- * Get a random uint64 value.
- * We don't assume random() is good for more than 16 bits.
- */
-static uint64
-get_random_uint64(void)
-{
-	uint64		x;
-
-	x = (uint64) (random() & 0xFFFF) << 48;
-	x |= (uint64) (random() & 0xFFFF) << 32;
-	x |= (uint64) (random() & 0xFFFF) << 16;
-	x |= (uint64) (random() & 0xFFFF);
-	return x;
-}
-
 /*
  * Main program.
  *
  * Generates a lot of random numbers and tests the implementation for each.
- * The results should be reproducible, since we don't call srandom().
+ * The results should be reproducible, since we fix the prng state (hmmm...).
  *
  * You can give a loop count if you don't like the default 1B iterations.
  */
@@ -90,6 +75,8 @@ main(int argc, char **argv)
 {
 	long		count;
 
+	pg_prng_seed(&pg_global_prng_state, 0);
+
 	if (argc >= 2)
 		count = strtol(argv[1], NULL, 0);
 	else
@@ -97,9 +84,9 @@ main(int argc, char **argv)
 
 	while (count-- > 0)
 	{
-		int64		x = get_random_uint64();
-		int64		y = get_random_uint64();
-		int64		z = get_random_uint64();
+		int64		x = pg_prng_u64(&pg_global_prng_state);
+		int64		y = pg_prng_u64(&pg_global_prng_state);
+		int64		z = pg_prng_u64(&pg_global_prng_state);
 		test128		t1;
 		test128		t2;
 

Reply via email to