commit 7f4b3def67ffaecbfafe85e47f53c0a2af4939c1
Author: Thomas Munro <thomas.munro@enterprisedb.com>
Date:   Sun Aug 14 10:48:58 2016 +1200

    Barriers!

diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c
index f13f9c1..0f375c4 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -41,6 +41,7 @@
 #include "commands/tablespace.h"
 #include "miscadmin.h"
 #include "pgstat.h"
+#include "port/atomics.h"
 #include "postmaster/bgwriter.h"
 #include "postmaster/walwriter.h"
 #include "postmaster/startup.h"
@@ -51,7 +52,6 @@
 #include "replication/snapbuild.h"
 #include "replication/walreceiver.h"
 #include "replication/walsender.h"
-#include "storage/barrier.h"
 #include "storage/bufmgr.h"
 #include "storage/fd.h"
 #include "storage/ipc.h"
diff --git a/src/backend/main/main.c b/src/backend/main/main.c
index c018c90..3707998 100644
--- a/src/backend/main/main.c
+++ b/src/backend/main/main.c
@@ -33,8 +33,8 @@
 
 #include "bootstrap/bootstrap.h"
 #include "common/username.h"
+#include "port/atomics.h"
 #include "postmaster/postmaster.h"
-#include "storage/barrier.h"
 #include "storage/s_lock.h"
 #include "storage/spin.h"
 #include "tcop/tcopprot.h"
diff --git a/src/backend/postmaster/bgworker.c b/src/backend/postmaster/bgworker.c
index 699c934..857a47e 100644
--- a/src/backend/postmaster/bgworker.c
+++ b/src/backend/postmaster/bgworker.c
@@ -16,9 +16,9 @@
 
 #include "miscadmin.h"
 #include "libpq/pqsignal.h"
+#include "port/atomics.h"
 #include "postmaster/bgworker_internals.h"
 #include "postmaster/postmaster.h"
-#include "storage/barrier.h"
 #include "storage/dsm.h"
 #include "storage/ipc.h"
 #include "storage/latch.h"
diff --git a/src/backend/storage/ipc/Makefile b/src/backend/storage/ipc/Makefile
index 8a55392..9dbdc26 100644
--- a/src/backend/storage/ipc/Makefile
+++ b/src/backend/storage/ipc/Makefile
@@ -8,7 +8,7 @@ subdir = src/backend/storage/ipc
 top_builddir = ../../../..
 include $(top_builddir)/src/Makefile.global
 
-OBJS = dsm_impl.o dsm.o ipc.o ipci.o latch.o pmsignal.o procarray.o \
+OBJS = barrier.o dsm_impl.o dsm.o ipc.o ipci.o latch.o pmsignal.o procarray.o \
 	procsignal.o  shmem.o shmqueue.o shm_mq.o shm_toc.o sinval.o \
 	sinvaladt.o standby.o
 
diff --git a/src/backend/storage/ipc/barrier.c b/src/backend/storage/ipc/barrier.c
new file mode 100644
index 0000000..8ea5aff
--- /dev/null
+++ b/src/backend/storage/ipc/barrier.c
@@ -0,0 +1,92 @@
+/*-------------------------------------------------------------------------
+ *
+ * barrier.c
+ *	  Barriers for synchronizing workers.
+ *
+ * Portions Copyright (c) 2016, PostgreSQL Global Development Group
+ *
+ * This simple mechanism allows for simple cases of phase-based
+ * fork/join-style cooperation by a static set of workers.
+ *
+ * IDENTIFICATION
+ *	  src/backend/storage/ipc/barrier.c
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#include "storage/barrier.h"
+
+/*
+ * Initialize this barrier, setting the number of workers that we will wait
+ * for at each computation phase.
+ */
+void
+BarrierInit(Barrier *barrier, int num_workers)
+{
+	SpinLockInit(&barrier->mutex);
+	barrier->num_workers = num_workers;
+	barrier->num_arrived = 0;
+	barrier->sense = false;
+	ConditionVariableInit(&barrier->condition_variable);
+}
+
+/*
+ * Wait for all workers to arrive at this barrier, and then return in all
+ * workers.
+ *
+ * Returns true in one arbitrarily selected worker (currently the last one to
+ * arrive).  Returns false in all others.  The differing return code can be
+ * used to coordinate a phase of work that must be done in only one worker
+ * while the others wait.
+ *
+ * TODO: When Michael Paquier's patch at
+ * https://commitfest.postgresql.org/10/629/ lands, then this function should
+ * take an event ID and it should be passed through the conditional variable
+ * wait and thence to the WaitLatch so that we can see joinpoint names show up
+ * in all their glory in pg_stat_activity!
+ *
+ * TODO: How should conditions like postmaster death, or being killed by the a
+ * parallel context owner/leader (if there is one), be handled?  Should this
+ * component be usable in contexts other than parallel workers?
+ */
+bool
+BarrierWait(Barrier *barrier)
+{
+	bool sense;
+	bool release;
+
+	SpinLockAcquire(&barrier->mutex);
+	++barrier->num_arrived;
+	if (barrier->num_arrived == barrier->num_workers)
+	{
+		release = true;
+		barrier->num_arrived = 0;
+		barrier->sense = !barrier->sense;
+	}
+	else
+	{
+		release = false;
+		sense = barrier->sense;
+	}
+	SpinLockRelease(&barrier->mutex);
+
+	if (release)
+	{
+		ConditionVariableBroadcast(&barrier->condition_variable);
+		return true;
+	}
+
+	for (;;)
+	{
+		ConditionVariablePrepareToSleep(&barrier->condition_variable);
+		SpinLockAcquire(&barrier->mutex);
+		release = barrier->sense != sense;
+		SpinLockRelease(&barrier->mutex);
+		if (release)
+			break;
+		ConditionVariableSleep();
+	}
+	ConditionVariableCancelSleep();
+
+	return false;
+}
diff --git a/src/backend/storage/ipc/latch.c b/src/backend/storage/ipc/latch.c
index 9def8a1..0268d35 100644
--- a/src/backend/storage/ipc/latch.c
+++ b/src/backend/storage/ipc/latch.c
@@ -55,9 +55,9 @@
 #endif
 
 #include "miscadmin.h"
+#include "port/atomics.h"
 #include "portability/instr_time.h"
 #include "postmaster/postmaster.h"
-#include "storage/barrier.h"
 #include "storage/latch.h"
 #include "storage/pmsignal.h"
 #include "storage/shmem.h"
diff --git a/src/backend/storage/ipc/shm_toc.c b/src/backend/storage/ipc/shm_toc.c
index 55248c2..a065212 100644
--- a/src/backend/storage/ipc/shm_toc.c
+++ b/src/backend/storage/ipc/shm_toc.c
@@ -13,7 +13,7 @@
 
 #include "postgres.h"
 
-#include "storage/barrier.h"
+#include "port/atomics.h"
 #include "storage/shm_toc.h"
 #include "storage/spin.h"
 
diff --git a/src/backend/storage/lmgr/s_lock.c b/src/backend/storage/lmgr/s_lock.c
index 599940c..6f81838 100644
--- a/src/backend/storage/lmgr/s_lock.c
+++ b/src/backend/storage/lmgr/s_lock.c
@@ -51,7 +51,7 @@
 #include <unistd.h>
 
 #include "storage/s_lock.h"
-#include "storage/barrier.h"
+#include "port/atomics.h"
 
 
 #define MIN_SPINS_PER_DELAY 10
diff --git a/src/include/pgstat.h b/src/include/pgstat.h
index dc3320d..1f899a8 100644
--- a/src/include/pgstat.h
+++ b/src/include/pgstat.h
@@ -14,9 +14,9 @@
 #include "datatype/timestamp.h"
 #include "fmgr.h"
 #include "libpq/pqcomm.h"
+#include "port/atomics.h"
 #include "portability/instr_time.h"
 #include "postmaster/pgarch.h"
-#include "storage/barrier.h"
 #include "storage/proc.h"
 #include "utils/hsearch.h"
 #include "utils/relcache.h"
diff --git a/src/include/storage/barrier.h b/src/include/storage/barrier.h
index 6202e57..b3ebd43 100644
--- a/src/include/storage/barrier.h
+++ b/src/include/storage/barrier.h
@@ -1,7 +1,7 @@
 /*-------------------------------------------------------------------------
  *
  * barrier.h
- *	  Memory barrier operations.
+ *	  Barriers for synchronizing workers.
  *
  * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
@@ -14,10 +14,26 @@
 #define BARRIER_H
 
 /*
- * This used to be a separate file, full of compiler/architecture
- * dependent defines, but it's not included in the atomics.h
- * infrastructure and just kept for backward compatibility.
+ * For the header previously known as "barrier.h", please include
+ * "port/atomics.h", which deals with atomics, compiler barriers and memory
+ * barriers.
  */
-#include "port/atomics.h"
+
+#include "postgres.h"
+
+#include "storage/condition_variable.h"
+#include "storage/spin.h"
+
+typedef struct Barrier
+{
+	slock_t mutex;
+	bool sense;
+	int num_workers;
+	int num_arrived;
+	ConditionVariable condition_variable;
+} Barrier;
+
+extern void BarrierInit(Barrier *barrier, int num_workers);
+extern bool BarrierWait(Barrier *barrier);
 
 #endif   /* BARRIER_H */
