From cb9a0c7987466b130fbced01ab5d5481cf3a16df Mon Sep 17 00:00:00 2001
From: Robert Haas <rhaas@postgresql.org>
Date: Mon, 10 Mar 2014 10:17:19 -0400
Subject: [PATCH] Teach on_exit_reset() to discard pending cleanups for dsm.

If a postmaster child invokes fork() and then calls on_exit_reset, that
should be sufficient to let it exit() without breaking anything, but
dynamic shared memory broke that by not updating on_exit_reset() to
discard callbacks registered with dynamic shared memory segments.

Per investigation of a complaint from Tom Lane.
---
 src/backend/storage/ipc/dsm.c | 31 +++++++++++++++++++++++++++++++
 src/backend/storage/ipc/ipc.c |  1 +
 src/include/storage/dsm.h     |  1 +
 3 files changed, 33 insertions(+)

diff --git a/src/backend/storage/ipc/dsm.c b/src/backend/storage/ipc/dsm.c
index 327d6850971..31e592e06e7 100644
--- a/src/backend/storage/ipc/dsm.c
+++ b/src/backend/storage/ipc/dsm.c
@@ -979,6 +979,37 @@ cancel_on_dsm_detach(dsm_segment *seg, on_dsm_detach_callback function,
 	}
 }
 
+/*
+ * Discard all registered on-detach callbacks without executing them.
+ */
+void
+reset_on_dsm_detach(void)
+{
+	dlist_iter		iter;
+
+	dlist_foreach(iter, &dsm_segment_list)
+	{
+		dsm_segment *seg = dlist_container(dsm_segment, node, iter.cur);
+
+		/* Throw away explicit on-detach actions one by one. */
+		while (!slist_is_empty(&seg->on_detach))
+		{
+			slist_node *node;
+			dsm_segment_detach_callback *cb;
+
+			node = slist_pop_head_node(&seg->on_detach);
+			cb = slist_container(dsm_segment_detach_callback, node, node);
+			pfree(cb);
+		}
+
+		/*
+		 * Decrementing the reference count is a sort of implicit on-detach
+		 * action; make sure we don't do that, either.
+		 */
+		seg->control_slot = INVALID_CONTROL_SLOT;
+	}
+}
+
 /*
  * Create a segment descriptor.
  */
diff --git a/src/backend/storage/ipc/ipc.c b/src/backend/storage/ipc/ipc.c
index 9dc48c30b61..5dea0ed8ddb 100644
--- a/src/backend/storage/ipc/ipc.c
+++ b/src/backend/storage/ipc/ipc.c
@@ -400,4 +400,5 @@ on_exit_reset(void)
 	before_shmem_exit_index = 0;
 	on_shmem_exit_index = 0;
 	on_proc_exit_index = 0;
+	reset_on_dsm_detach();
 }
diff --git a/src/include/storage/dsm.h b/src/include/storage/dsm.h
index 71901bf8c5a..46d3cbdd8ab 100644
--- a/src/include/storage/dsm.h
+++ b/src/include/storage/dsm.h
@@ -43,5 +43,6 @@ extern void on_dsm_detach(dsm_segment *seg,
 			  on_dsm_detach_callback function, Datum arg);
 extern void cancel_on_dsm_detach(dsm_segment *seg,
 			  on_dsm_detach_callback function, Datum arg);
+extern void reset_on_dsm_detach(void);
 
 #endif   /* DSM_H */
-- 
GitLab