Browse Source

list_del_init/list_node_init: for multiple list_del() calls.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Rusty Russell 11 years ago
parent
commit
ec8654d94d
2 changed files with 48 additions and 2 deletions
  1. 34 1
      ccan/list/list.h
  2. 14 1
      ccan/list/test/run.c

+ 34 - 1
ccan/list/list.h

@@ -145,6 +145,18 @@ static inline void list_head_init(struct list_head *h)
 	h->n.next = h->n.prev = &h->n;
 	h->n.next = h->n.prev = &h->n;
 }
 }
 
 
+/**
+ * list_node_init - initialize a list_node
+ * @n: the list_node to link to itself.
+ *
+ * You don't need to use this normally!  But it lets you list_del(@n)
+ * safely.
+ */
+static inline void list_node_init(struct list_node *n)
+{
+	n->next = n->prev = n;
+}
+
 /**
 /**
  * list_add - add an entry at the start of a linked list.
  * list_add - add an entry at the start of a linked list.
  * @h: the list_head to add the node to
  * @h: the list_head to add the node to
@@ -237,7 +249,7 @@ static inline bool list_empty_nodebug(const struct list_head *h)
  * another list, but not deleted again.
  * another list, but not deleted again.
  *
  *
  * See also:
  * See also:
- *	list_del_from()
+ *	list_del_from(), list_del_init()
  *
  *
  * Example:
  * Example:
  *	list_del(&child->list);
  *	list_del(&child->list);
@@ -255,6 +267,27 @@ static inline void list_del_(struct list_node *n, const char* abortstr)
 #endif
 #endif
 }
 }
 
 
+/**
+ * list_del_init - delete a node, and reset it so it can be deleted again.
+ * @n: the list_node to be deleted.
+ *
+ * list_del(@n) or list_del_init() again after this will be safe,
+ * which can be useful in some cases.
+ *
+ * See also:
+ *	list_del_from(), list_del()
+ *
+ * Example:
+ *	list_del_init(&child->list);
+ *	parent->num_children--;
+ */
+#define list_del_init(n) list_del_init_(n, LIST_LOC)
+static inline void list_del_init_(struct list_node *n, const char *abortstr)
+{
+	list_del_(n, abortstr);
+	list_node_init(n);
+}
+
 /**
 /**
  * list_del_from - delete an entry from a known linked list.
  * list_del_from - delete an entry from a known linked list.
  * @h: the list_head the node is in.
  * @h: the list_head the node is in.

+ 14 - 1
ccan/list/test/run.c

@@ -25,7 +25,7 @@ int main(int argc, char *argv[])
 	opaque_t *q, *nq;
 	opaque_t *q, *nq;
 	struct list_head opaque_list = LIST_HEAD_INIT(opaque_list);
 	struct list_head opaque_list = LIST_HEAD_INIT(opaque_list);
 
 
-	plan_tests(68);
+	plan_tests(70);
 	/* Test LIST_HEAD, LIST_HEAD_INIT, list_empty and check_list */
 	/* Test LIST_HEAD, LIST_HEAD_INIT, list_empty and check_list */
 	ok1(list_empty(&static_list));
 	ok1(list_empty(&static_list));
 	ok1(list_check(&static_list, NULL));
 	ok1(list_check(&static_list, NULL));
@@ -155,6 +155,19 @@ int main(int argc, char *argv[])
 	ok1(i == 3);
 	ok1(i == 3);
 	ok1(list_empty(&parent.children));
 	ok1(list_empty(&parent.children));
 
 
+	/* Test list_node_init: safe to list_del after this. */
+	list_node_init(&c->list);
+	list_del(&c->list);
+
+	/* Test list_del_init */
+	list_add(&parent.children, &c->list);
+	ok1(!list_empty(&parent.children));
+	list_del_init(&c->list);
+	ok1(list_empty(&parent.children));
+	/* We can call this as many times as we like. */
+	list_del_init(&c->list);
+	list_del_init(&c->list);
+
 	/* Test list_for_each_off. */
 	/* Test list_for_each_off. */
 	list_add_tail(&opaque_list,
 	list_add_tail(&opaque_list,
 		      (struct list_node *)create_opaque_blob());
 		      (struct list_node *)create_opaque_blob());