diff --git a/contrib/pingpong/Makefile b/contrib/pingpong/Makefile
new file mode 100644
index 0000000..c3a443c
--- /dev/null
+++ b/contrib/pingpong/Makefile
@@ -0,0 +1,17 @@
+# contrib/pingpong/Makefile
+
+MODULES = pingpong
+
+EXTENSION = pingpong
+DATA = pingpong--1.0.sql
+
+ifdef USE_PGXS
+PG_CONFIG = pg_config
+PGXS := $(shell $(PG_CONFIG) --pgxs)
+include $(PGXS)
+else
+subdir = contrib/pingpong
+top_builddir = ../..
+include $(top_builddir)/src/Makefile.global
+include $(top_srcdir)/contrib/contrib-global.mk
+endif
diff --git a/contrib/pingpong/pingpong--1.0.sql b/contrib/pingpong/pingpong--1.0.sql
new file mode 100644
index 0000000..75c2982
--- /dev/null
+++ b/contrib/pingpong/pingpong--1.0.sql
@@ -0,0 +1,7 @@
+/* contrib/pingpong/pingpong--1.0.sql */
+
+-- complain if script is sourced in psql, rather than via CREATE EXTENSION
+\echo Use "CREATE EXTENSION pingpong" to load this file. \quit
+
+CREATE FUNCTION pingpong(pg_catalog.int8) RETURNS pg_catalog.void STRICT
+	AS 'MODULE_PATHNAME' LANGUAGE C;
diff --git a/contrib/pingpong/pingpong.c b/contrib/pingpong/pingpong.c
new file mode 100644
index 0000000..597333f
--- /dev/null
+++ b/contrib/pingpong/pingpong.c
@@ -0,0 +1,165 @@
+/* -------------------------------------------------------------------------
+ *
+ * pingpong.c
+ *		Demonstration code that plays ping-pong with process latches.
+ *
+ * Copyright (C) 2013, PostgreSQL Global Development Group
+ *
+ * IDENTIFICATION
+ *		contrib/pingpong/pingpong.c
+ *
+ * -------------------------------------------------------------------------
+ */
+#include "postgres.h"
+
+#include "fmgr.h"
+#include "miscadmin.h"
+#include "postmaster/bgworker.h"
+#include "storage/barrier.h"
+#include "storage/ipc.h"
+#include "storage/latch.h"
+#include "storage/lwlock.h"
+#include "storage/proc.h"
+#include "storage/procarray.h"
+#include "storage/shmem.h"
+
+PG_MODULE_MAGIC;
+PG_FUNCTION_INFO_V1(pingpong);
+
+void		_PG_init(void);
+void		pingpong_main(Datum);
+Datum		pingpong(PG_FUNCTION_ARGS);
+
+/* flags set by signal handlers */
+static volatile sig_atomic_t got_sigterm = false;
+
+/*
+ * Signal handler for SIGTERM
+ *		Set a flag to let the main loop to terminate, and set our latch to wake
+ *		it up.
+ */
+static void
+pingpong_sigterm(SIGNAL_ARGS)
+{
+	int			save_errno = errno;
+
+	got_sigterm = true;
+	if (MyProc)
+		SetLatch(&MyProc->procLatch);
+
+	errno = save_errno;
+}
+
+void
+pingpong_main(Datum main_arg)
+{
+	PGPROC	   *proc;
+
+	/* Establish signal handlers before unblocking signals. */
+	pqsignal(SIGTERM, pingpong_sigterm);
+
+	/* We're now ready to receive signals */
+	BackgroundWorkerUnblockSignals();
+
+	/*
+	 * We need to do this in order to get our PGPROC to show up in the
+	 * ProcArray, so that the master can get hold of it.  XXX. Is there a
+	 * better way of doing this?
+	 */
+	InitProcessPhase2();
+
+	/* Find parent's PGPROC structure. */
+	proc = BackendPidGetProc(MyBgworkerEntry->bgw_notify_pid);
+
+	/* Play ping-pong until we're killed. */
+	while (!got_sigterm)
+	{
+		ResetLatch(&MyProc->procLatch);
+		pg_memory_barrier();
+		SetLatch(&proc->procLatch);
+		pg_memory_barrier();
+		WaitLatch(&MyProc->procLatch, WL_LATCH_SET, 0);
+	}
+
+	proc_exit(1);
+}
+
+/*
+ * Dynamically launch an SPI worker.
+ */
+Datum
+pingpong(PG_FUNCTION_ARGS)
+{
+	int64		count = PG_GETARG_INT64(0);
+	BackgroundWorker worker;
+	BackgroundWorkerHandle *handle;
+	BgwHandleStatus	status;
+	pid_t		pid;
+	PGPROC	   *proc;
+
+	worker.bgw_flags = BGWORKER_SHMEM_ACCESS
+		| BGWORKER_EPHEMERAL | BGWORKER_PRECIOUS;
+	worker.bgw_start_time = BgWorkerStart_RecoveryFinished;
+	worker.bgw_restart_time = BGW_NEVER_RESTART;
+	worker.bgw_main = NULL;		/* new worker might not have library loaded */
+	sprintf(worker.bgw_library_name, "pingpong");
+	sprintf(worker.bgw_function_name, "pingpong_main");
+	snprintf(worker.bgw_name, BGW_MAXLEN, "pingpong");
+	worker.bgw_main_arg = (Datum) 0;
+	/* set bgw_notify_pid so that we can use WaitForBackgroundWorkerStartup */
+	worker.bgw_notify_pid = MyProcPid;
+
+	/* Register background worker. */
+	if (!RegisterDynamicBackgroundWorker(&worker, &handle))
+		ereport(ERROR,
+				(errcode(ERRCODE_INSUFFICIENT_RESOURCES),
+				 errmsg("could not register background process"),
+				 errhint("You may need to increase max_worker_processes.")));
+
+	/* Wait until it starts so we can get the PID. */
+	status = WaitForBackgroundWorkerStartup(handle, &pid);
+
+	if (status == BGWH_STOPPED)
+		ereport(ERROR,
+				(errcode(ERRCODE_INSUFFICIENT_RESOURCES),
+				 errmsg("could not start background process"),
+				 errhint("More details may be available in the server log.")));
+	if (status == BGWH_POSTMASTER_DIED)
+		ereport(ERROR,
+				(errcode(ERRCODE_INSUFFICIENT_RESOURCES),
+				 errmsg("cannot start background processes without postmaster"),
+				 errhint("Kill all remaining database processes and restart the database.")));
+	Assert(status == BGWH_STARTED);
+
+	/*
+	 * Get the PGPROC for the background process.  Unfortunately, we don't
+	 * actually know that the client has gotten as far as acquiring a PGPROC;
+	 * we only know that the postmaster managed to fork (or exec it).  But
+	 * the child will set our latch when it starts up, so we can just wait on
+	 * our latch.
+	 */
+	while ((proc = BackendPidGetProc(pid)) == NULL)
+	{
+		WaitLatch(&MyProc->procLatch, WL_LATCH_SET, 0);
+		pg_memory_barrier();
+		CHECK_FOR_INTERRUPTS();
+		ResetLatch(&MyProc->procLatch);
+	}
+
+	/* OK, we're ready to really do it. */
+	while (count > 0)
+	{
+		ResetLatch(&MyProc->procLatch);
+		pg_memory_barrier();
+		SetLatch(&proc->procLatch);
+		pg_memory_barrier();
+		WaitLatch(&MyProc->procLatch, WL_LATCH_SET, 0);
+		CHECK_FOR_INTERRUPTS();
+		--count;
+	}
+
+	/* We must clean up the background worker before returning. */
+	TerminateBackgroundWorker(handle);
+
+	PG_RETURN_VOID();
+}
diff --git a/contrib/pingpong/pingpong.control b/contrib/pingpong/pingpong.control
new file mode 100644
index 0000000..f8aa447
--- /dev/null
+++ b/contrib/pingpong/pingpong.control
@@ -0,0 +1,5 @@
+# pingpong extension
+comment = 'Play ping-pong with latches'
+default_version = '1.0'
+module_pathname = '$libdir/pingpong'
+relocatable = true
