ilist.h debugging improvements.
authorAndres Freund <[email protected]>
Mon, 25 May 2020 10:02:56 +0000 (03:02 -0700)
committerAndres Freund <[email protected]>
Mon, 11 Jan 2021 23:09:14 +0000 (15:09 -0800)
Author:
Reviewed-By:
Discussion: https://postgr.es/m/
Backpatch:

src/backend/lib/ilist.c
src/include/lib/ilist.h

index e9a07c14f7b5b038443273e81f9f535b039f9cba..d6aeb89d823b4c890b15d9a585661afe557741e6 100644 (file)
@@ -51,20 +51,19 @@ slist_delete(slist_head *head, slist_node *node)
    slist_check(head);
 }
 
-#ifdef ILIST_DEBUG
 /*
  * Verify integrity of a doubly linked list
  */
-void
-dlist_check(dlist_head *head)
+dlist_head*
+dlist_check_force(dlist_head *head)
 {
    dlist_node *cur;
 
    if (head == NULL)
-       elog(ERROR, "doubly linked list head address is NULL");
+       elog(PANIC, "doubly linked list head address is NULL");
 
    if (head->head.next == NULL && head->head.prev == NULL)
-       return;                 /* OK, initialized as zeroes */
+       return head;                    /* OK, initialized as zeroes */
 
    /* iterate in forward direction */
    for (cur = head->head.next; cur != &head->head; cur = cur->next)
@@ -74,7 +73,7 @@ dlist_check(dlist_head *head)
            cur->prev == NULL ||
            cur->prev->next != cur ||
            cur->next->prev != cur)
-           elog(ERROR, "doubly linked list is corrupted");
+           elog(PANIC, "doubly linked list is corrupted");
    }
 
    /* iterate in backward direction */
@@ -85,20 +84,22 @@ dlist_check(dlist_head *head)
            cur->prev == NULL ||
            cur->prev->next != cur ||
            cur->next->prev != cur)
-           elog(ERROR, "doubly linked list is corrupted");
+           elog(PANIC, "doubly linked list is corrupted");
    }
+
+   return head;
 }
 
 /*
  * Verify integrity of a singly linked list
  */
-void
-slist_check(slist_head *head)
+slist_head *
+slist_check_force(slist_head *head)
 {
    slist_node *cur;
 
    if (head == NULL)
-       elog(ERROR, "singly linked list head address is NULL");
+       elog(PANIC, "singly linked list head address is NULL");
 
    /*
     * there isn't much we can test in a singly linked list except that it
@@ -106,6 +107,20 @@ slist_check(slist_head *head)
     */
    for (cur = head->head.next; cur != NULL; cur = cur->next)
        ;
+
+   return head;
 }
 
-#endif                         /* ILIST_DEBUG */
+bool
+dlist_is_member(dlist_head *head, dlist_node *node)
+{
+   dlist_iter iter;
+
+   dlist_foreach(iter, head)
+   {
+       if (iter.cur == node)
+           return true;
+   }
+
+   return false;
+}
index aa196428ed92c05c37e57a089b4c44e48846a4c9..2930e4d4eda79f80e5278dea42773d77841df48c 100644 (file)
@@ -254,9 +254,18 @@ typedef struct slist_mutable_iter
 /* Caution: this is O(n); consider using slist_delete_current() instead */
 extern void slist_delete(slist_head *head, slist_node *node);
 
+extern dlist_head* dlist_check_force(dlist_head *head);
+extern slist_head* slist_check_force(slist_head *head);
+
 #ifdef ILIST_DEBUG
-extern void dlist_check(dlist_head *head);
-extern void slist_check(slist_head *head);
+static inline dlist_head* dlist_check(dlist_head *head)
+{
+   return dlist_check_force(head);
+}
+static inline slist_head* slist_check(slist_head *head)
+{
+   return slist_check_force(head);
+}
 #else
 /*
  * These seemingly useless casts to void are here to keep the compiler quiet
@@ -264,7 +273,10 @@ extern void slist_check(slist_head *head);
  * in which functions the only point of passing the list head pointer is to be
  * able to run these checks.
  */
-#define dlist_check(head)  ((void) (head))
+static inline dlist_head *dlist_check(dlist_head *head)
+{
+   return head;
+}
 #define slist_check(head)  ((void) (head))
 #endif                         /* ILIST_DEBUG */
 
@@ -293,12 +305,23 @@ dlist_is_empty(dlist_head *head)
    return head->head.next == NULL || head->head.next == &(head->head);
 }
 
+/*
+ * Is node member of the list?
+ *
+ * NB: This is O(N)!
+ */
+extern bool dlist_is_member(dlist_head *head, dlist_node *node);
+
 /*
  * Insert a node at the beginning of the list.
  */
 static inline void
 dlist_push_head(dlist_head *head, dlist_node *node)
 {
+#ifdef ILIST_DEBUG
+   Assert(!dlist_is_member(head, node));
+#endif
+
    if (head->head.next == NULL)    /* convert NULL header to circular */
        dlist_init(head);
 
@@ -316,6 +339,11 @@ dlist_push_head(dlist_head *head, dlist_node *node)
 static inline void
 dlist_push_tail(dlist_head *head, dlist_node *node)
 {
+#ifdef ILIST_DEBUG
+   Assert(!dlist_is_member(head, node));
+#endif
+   dlist_check(head);
+
    if (head->head.next == NULL)    /* convert NULL header to circular */
        dlist_init(head);
 
@@ -361,6 +389,20 @@ dlist_delete(dlist_node *node)
    node->next->prev = node->prev;
 }
 
+/*
+ * Delete 'node' from its list (it must be in one).
+ */
+static inline void
+dlist_delete_from(dlist_head *head, dlist_node *node)
+{
+   dlist_check(head);
+#ifdef ILIST_DEBUG
+   Assert(dlist_is_member(head, node));
+#endif
+   node->prev->next = node->next;
+   node->next->prev = node->prev;
+}
+
 /*
  * Remove and return the first node from a list (there must be one).
  */
@@ -369,9 +411,17 @@ dlist_pop_head_node(dlist_head *head)
 {
    dlist_node *node;
 
+   dlist_check(head);
+
+#ifdef ILIST_DEBUG
    Assert(!dlist_is_empty(head));
+#endif
+
    node = head->head.next;
    dlist_delete(node);
+
+   dlist_check(head);
+
    return node;
 }
 
@@ -507,7 +557,7 @@ dlist_tail_node(dlist_head *head)
 #define dlist_foreach(iter, lhead)                                         \
    for (AssertVariableIsOfTypeMacro(iter, dlist_iter),                     \
         AssertVariableIsOfTypeMacro(lhead, dlist_head *),                  \
-        (iter).end = &(lhead)->head,                                       \
+        (iter).end = &dlist_check(lhead)->head,                            \
         (iter).cur = (iter).end->next ? (iter).end->next : (iter).end;     \
         (iter).cur != (iter).end;                                          \
         (iter).cur = (iter).cur->next)
@@ -524,7 +574,7 @@ dlist_tail_node(dlist_head *head)
 #define dlist_foreach_modify(iter, lhead)                                  \
    for (AssertVariableIsOfTypeMacro(iter, dlist_mutable_iter),             \
         AssertVariableIsOfTypeMacro(lhead, dlist_head *),                  \
-        (iter).end = &(lhead)->head,                                       \
+        (iter).end = &dlist_check(lhead)->head,                            \
         (iter).cur = (iter).end->next ? (iter).end->next : (iter).end,     \
         (iter).next = (iter).cur->next;                                    \
         (iter).cur != (iter).end;                                          \