>From 0dfa542f457ebd71640830a993e3a428720b4179 Mon Sep 17 00:00:00 2001
From: Andres Freund <andres@anarazel.de>
Date: Wed, 24 Jul 2013 19:34:10 +0200
Subject: [PATCH 1/2] Add slist_delete_current()

---
 src/backend/lib/ilist.c                     |  2 +-
 src/backend/postmaster/bgworker.c           |  5 ++++-
 src/backend/postmaster/postmaster.c         |  4 ++--
 src/include/lib/ilist.h                     | 32 +++++++++++++++++++++++++----
 src/include/postmaster/bgworker_internals.h |  2 +-
 5 files changed, 36 insertions(+), 9 deletions(-)

diff --git a/src/backend/lib/ilist.c b/src/backend/lib/ilist.c
index 957a118..dddb6eb 100644
--- a/src/backend/lib/ilist.c
+++ b/src/backend/lib/ilist.c
@@ -28,7 +28,7 @@
  *
  * It is not allowed to delete a 'node' which is is not in the list 'head'
  *
- * Caution: this is O(n)
+ * Caution: this is O(n), use slist_delete_current() while iterating.
  */
 void
 slist_delete(slist_head *head, slist_node *node)
diff --git a/src/backend/postmaster/bgworker.c b/src/backend/postmaster/bgworker.c
index ada24e9..9967b69 100644
--- a/src/backend/postmaster/bgworker.c
+++ b/src/backend/postmaster/bgworker.c
@@ -272,10 +272,13 @@ BackgroundWorkerStateChange(void)
  * the postmaster.
  */
 void
-ForgetBackgroundWorker(RegisteredBgWorker *rw)
+ForgetBackgroundWorker(slist_mutable_iter *cur)
 {
+	RegisteredBgWorker *rw;
 	BackgroundWorkerSlot *slot;
 
+	rw = slist_container(RegisteredBgWorker, rw_lnode, cur->cur);
+
 	Assert(rw->rw_shmem_slot < max_worker_processes);
 	slot = &BackgroundWorkerData->slot[rw->rw_shmem_slot];
 	slot->in_use = false;
diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c
index b6b8111..0342be7 100644
--- a/src/backend/postmaster/postmaster.c
+++ b/src/backend/postmaster/postmaster.c
@@ -1452,7 +1452,7 @@ DetermineSleepTime(struct timeval * timeout)
 
 			if (rw->rw_worker.bgw_restart_time == BGW_NEVER_RESTART)
 			{
-				ForgetBackgroundWorker(rw);
+				ForgetBackgroundWorker(&siter);
 				continue;
 			}
 
@@ -5643,7 +5643,7 @@ StartOneBackgroundWorker(void)
 		{
 			if (rw->rw_worker.bgw_restart_time == BGW_NEVER_RESTART)
 			{
-				ForgetBackgroundWorker(rw);
+				ForgetBackgroundWorker(&iter);
 				continue;
 			}
 
diff --git a/src/include/lib/ilist.h b/src/include/lib/ilist.h
index 73f4115..f8f0458 100644
--- a/src/include/lib/ilist.h
+++ b/src/include/lib/ilist.h
@@ -211,7 +211,9 @@ typedef struct slist_head
  * Used as state in slist_foreach(). To get the current element of the
  * iteration use the 'cur' member.
  *
- * Do *not* manipulate the list while iterating!
+ * It's allowed to modify the list while iterating, with the sole exception of
+ * deleting the iterator's current node which may not be deleted unless the
+ * iteration is not continued afterwards.
  *
  * NB: this wouldn't really need to be an extra struct, we could use a
  * slist_node * directly. We prefer a separate type for consistency.
@@ -226,11 +228,12 @@ typedef struct slist_iter
  *
  * Used as state in slist_foreach_modify().
  *
- * Iterations using this are allowed to remove the current node and to add
- * more nodes ahead of the current node.
+ * The only modification allowed while iterating is to remove the current node
+ * either via slist_delete() or slist_delete_current().
  */
 typedef struct slist_mutable_iter
 {
+	slist_node *prev;			/* prev node, for deletions */
 	slist_node *cur;			/* current element */
 	slist_node *next;			/* next node we'll iterate to */
 } slist_mutable_iter;
@@ -243,7 +246,7 @@ typedef struct slist_mutable_iter
 
 /* Prototypes for functions too big to be inline */
 
-/* Caution: this is O(n) */
+/* Caution: this is O(n), use slist_delete_current() while iterating */
 extern void slist_delete(slist_head *head, slist_node *node);
 
 #ifdef ILIST_DEBUG
@@ -578,6 +581,7 @@ extern slist_node *slist_pop_head_node(slist_head *head);
 extern bool slist_has_next(slist_head *head, slist_node *node);
 extern slist_node *slist_next_node(slist_head *head, slist_node *node);
 extern slist_node *slist_head_node(slist_head *head);
+extern void slist_delete_current(slist_mutable_iter *cur);
 
 /* slist macro support function */
 extern void *slist_head_element_off(slist_head *head, size_t off);
@@ -679,6 +683,22 @@ slist_head_node(slist_head *head)
 {
 	return (slist_node *) slist_head_element_off(head, 0);
 }
+
+/*
+ * Delete the iterator's current element while preserving integrity of the
+ * underlying list.
+ */
+STATIC_IF_INLINE void
+slist_delete_current(slist_mutable_iter *cur)
+{
+	/*
+	 * cur->prev will point to the slist_head's 'head' field when the iteration
+	 * is at the first element of the list allowing us to treat perform
+	 * deletion of the first element without a special case.
+	 */
+	cur->prev->next = cur->next;
+}
+
 #endif   /* PG_USE_INLINE || ILIST_INCLUDE_DEFINITIONS */
 
 /*
@@ -726,9 +746,13 @@ slist_head_node(slist_head *head)
 #define slist_foreach_modify(iter, lhead)									\
 	for (AssertVariableIsOfTypeMacro(iter, slist_mutable_iter),				\
 		 AssertVariableIsOfTypeMacro(lhead, slist_head *),					\
+		 (iter).prev = &(lhead)->head,										\
 		 (iter).cur = (lhead)->head.next,									\
 		 (iter).next = (iter).cur ? (iter).cur->next : NULL;				\
+																			\
 		 (iter).cur != NULL;												\
+																			\
+		 (iter).prev = (iter).cur,											\
 		 (iter).cur = (iter).next,											\
 		 (iter).next = (iter).next ? (iter).next->next : NULL)
 
diff --git a/src/include/postmaster/bgworker_internals.h b/src/include/postmaster/bgworker_internals.h
index 6484cfb..478a1ff 100644
--- a/src/include/postmaster/bgworker_internals.h
+++ b/src/include/postmaster/bgworker_internals.h
@@ -39,7 +39,7 @@ extern slist_head BackgroundWorkerList;
 extern Size BackgroundWorkerShmemSize(void);
 extern void BackgroundWorkerShmemInit(void);
 extern void BackgroundWorkerStateChange(void);
-extern void ForgetBackgroundWorker(RegisteredBgWorker *);
+extern void ForgetBackgroundWorker(slist_mutable_iter *cur);
 
 #ifdef EXEC_BACKEND
 extern BackgroundWorker *BackgroundWorkerEntry(int slotno);
-- 
1.8.3.251.g1462b67

