diff --git a/src/test/modules/test_barrier/Makefile b/src/test/modules/test_barrier/Makefile
new file mode 100644
index 0000000..9f330b6
--- /dev/null
+++ b/src/test/modules/test_barrier/Makefile
@@ -0,0 +1,18 @@
+# src/test/modules/test_barrier/Makefile
+
+MODULES = test_barrier
+
+EXTENSION = test_barrier
+DATA = test_barrier--1.0.sql
+PGFILEDESC = "test_barrier -- some tests for barrier.c"
+
+ifdef USE_PGXS
+PG_CONFIG = pg_config
+PGXS := $(shell $(PG_CONFIG) --pgxs)
+include $(PGXS)
+else
+subdir = src/test/modules/test_barrier
+top_builddir = ../../../..
+include $(top_builddir)/src/Makefile.global
+include $(top_srcdir)/contrib/contrib-global.mk
+endif
diff --git a/src/test/modules/test_barrier/test_barrier--1.0.sql b/src/test/modules/test_barrier/test_barrier--1.0.sql
new file mode 100644
index 0000000..822915f
--- /dev/null
+++ b/src/test/modules/test_barrier/test_barrier--1.0.sql
@@ -0,0 +1,13 @@
+\echo Use "CREATE EXTENSION test_barrier" to load this file. \quit
+
+CREATE FUNCTION test_barrier_alternate(workers int, loops int)
+RETURNS void
+AS 'MODULE_PATHNAME'
+LANGUAGE C;
+
+CREATE FUNCTION test_barrier_reattach_random(workers int, end_phase int)
+RETURNS void
+AS 'MODULE_PATHNAME'
+LANGUAGE C;
+
+
diff --git a/src/test/modules/test_barrier/test_barrier.c b/src/test/modules/test_barrier/test_barrier.c
new file mode 100644
index 0000000..07127bb
--- /dev/null
+++ b/src/test/modules/test_barrier/test_barrier.c
@@ -0,0 +1,211 @@
+#include "postgres.h"
+
+#include "fmgr.h"
+#include "funcapi.h"
+#include "miscadmin.h"
+#include "pgstat.h"
+#include "postmaster/bgworker.h"
+#include "storage/barrier.h"
+#include "storage/dsm.h"
+#include "storage/proc.h"
+#include "utils/builtins.h"
+#include "utils/resowner.h"
+
+#include <stdlib.h>
+#include <unistd.h>
+
+PG_MODULE_MAGIC;
+
+PG_FUNCTION_INFO_V1(test_barrier_alternate);
+PG_FUNCTION_INFO_V1(test_barrier_reattach_random);
+
+extern Datum test_barrier_main(Datum);
+
+typedef enum test_mode
+{
+	TEST_MODE_ALTERNATE,
+	TEST_MODE_REATTACH_RANDOM
+} test_mode;
+
+typedef struct test_barrier_alternate_state
+{
+	Barrier barrier1;
+	Barrier barrier2;
+	int loops;
+} test_barrier_alternate_state;
+
+typedef struct test_barrier_reattach_random_state
+{
+	Barrier barrier;
+	int end_phase;
+} test_barrier_reattach_random_state;
+
+typedef struct test_barrier_state
+{
+	test_mode mode;
+	union
+	{
+		test_barrier_alternate_state alternate_state;
+		test_barrier_reattach_random_state reattach_random_state;
+	};
+} test_barrier_state;
+
+/*
+ * Wait at barrier1 and then barrier2, state->loops times.
+ */
+static void
+do_test_barrier_alternate(test_barrier_alternate_state *state)
+{
+	int i;
+
+	for (i = 0; i < state->loops; ++i)
+	{
+		BarrierWait(&state->barrier1, PG_WAIT_EXTENSION);
+		BarrierWait(&state->barrier2, PG_WAIT_EXTENSION);
+	}
+}
+
+/*
+ * Attach, wait a random numer of times, then detach, repeatedly until
+ * state->end_phase is reached.
+ */
+static void
+do_test_barrier_reattach_random(test_barrier_reattach_random_state *state)
+{
+	bool done = false;
+	int expected_phase;
+	int i;
+	int nwaits;
+
+	/* Make sure each backend uses a different pseudo-random sequence. */
+	srand48(getpid());
+
+	while (!done)
+	{
+		expected_phase = BarrierAttach(&state->barrier);
+		nwaits = (int) (lrand48() % 8);
+		for (i = 0; i < nwaits; ++i)
+		{
+			if (expected_phase == state->end_phase)
+			{
+				done = true;
+				break;
+			}
+
+			BarrierWait(&state->barrier, PG_WAIT_EXTENSION);
+			++expected_phase;
+			Assert(BarrierPhase(&state->barrier) == expected_phase);
+		}
+		BarrierDetach(&state->barrier);
+	}
+}
+
+Datum
+test_barrier_main(Datum arg)
+{
+	dsm_segment *segment;
+	test_barrier_state *state;
+
+	BackgroundWorkerUnblockSignals();
+
+	CurrentResourceOwner = ResourceOwnerCreate(NULL, "test_barrier_main toplevel");
+
+	segment = dsm_attach(DatumGetInt32(arg));
+	state = (test_barrier_state *) dsm_segment_address(segment);
+	switch (state->mode)
+	{
+	case TEST_MODE_ALTERNATE:
+		do_test_barrier_alternate(&state->alternate_state);
+		break;
+	case TEST_MODE_REATTACH_RANDOM:
+		do_test_barrier_reattach_random(&state->reattach_random_state);
+		break;
+	default:
+		Assert(0);
+	}
+	dsm_detach(segment);
+
+	return (Datum) 0;
+}
+
+static void
+launch_test(test_mode mode, int workers, int n)
+{
+	BackgroundWorkerHandle **handles;
+	test_barrier_state *state;
+	dsm_segment *segment;
+	int i;
+
+	handles = palloc(sizeof(BackgroundWorkerHandle *) * workers);
+
+	segment = dsm_create(sizeof(test_barrier_state), 0);
+	state = (test_barrier_state *) dsm_segment_address(segment);
+
+	/* Initialize state. */
+	state->mode = mode;
+	switch (mode)
+	{
+	case TEST_MODE_ALTERNATE:
+		/* Initialize a static barrier for 'workers' workers. */
+		state->alternate_state.loops = n;
+		BarrierInit(&state->alternate_state.barrier1, workers);
+		BarrierInit(&state->alternate_state.barrier2, workers);
+		break;
+	case TEST_MODE_REATTACH_RANDOM:
+		/* Initialize a dynamic barrier.  They'll attach and detach. */
+		state->reattach_random_state.end_phase = n;
+		BarrierInit(&state->reattach_random_state.barrier, 0);
+		break;
+	default:
+		Assert(0);
+	}
+
+	/* Start workers. */
+	for (i = 0; i < workers; ++i)
+	{
+		BackgroundWorker bgw;
+
+		snprintf(bgw.bgw_name, sizeof(bgw.bgw_name), "worker%d", i);
+		bgw.bgw_flags = BGWORKER_SHMEM_ACCESS;
+		bgw.bgw_start_time = BgWorkerStart_ConsistentState;
+		bgw.bgw_restart_time = BGW_NEVER_RESTART;
+		bgw.bgw_main = NULL;
+		snprintf(bgw.bgw_library_name, sizeof(bgw.bgw_library_name),
+				 "test_barrier");
+		snprintf(bgw.bgw_function_name, sizeof(bgw.bgw_function_name),
+				 "test_barrier_main");
+		bgw.bgw_main_arg = Int32GetDatum(dsm_segment_handle(segment));
+		bgw.bgw_notify_pid = MyProcPid;
+
+		if (!RegisterDynamicBackgroundWorker(&bgw, &handles[i]))
+			elog(ERROR, "Can't start worker");
+	}
+
+	/* Wait for workers to complete. */
+	for (i = 0; i < workers; ++i)
+		WaitForBackgroundWorkerShutdown(handles[i]);
+
+	dsm_detach(segment);
+}
+
+Datum
+test_barrier_reattach_random(PG_FUNCTION_ARGS)
+{
+	int workers = PG_GETARG_INT32(0);
+	int end_phase = PG_GETARG_INT32(1);
+
+	launch_test(TEST_MODE_REATTACH_RANDOM, workers, end_phase);
+
+	return (Datum) 0;
+}
+
+Datum
+test_barrier_alternate(PG_FUNCTION_ARGS)
+{
+	int workers = PG_GETARG_INT32(0);
+	int loops = PG_GETARG_INT32(1);
+
+	launch_test(TEST_MODE_ALTERNATE, workers, loops);
+
+	return (Datum) 0;
+}
diff --git a/src/test/modules/test_barrier/test_barrier.control b/src/test/modules/test_barrier/test_barrier.control
new file mode 100644
index 0000000..1cfe3bc
--- /dev/null
+++ b/src/test/modules/test_barrier/test_barrier.control
@@ -0,0 +1,4 @@
+comment = 'test_barrier'
+default_version = '1.0'
+module_pathname = '$libdir/test_barrier'
+relocatable = true
