diff mbox

[1/2] list: add while_list_drain_entry

Message ID 20130605020341.GA27240@logfs.org (mailing list archive)
State New, archived
Headers show

Commit Message

Jörn Engel June 5, 2013, 2:03 a.m. UTC
I have seen a lot of boilerplate code that either follows the pattern of
	while (!list_empty(head)) {
		pos = list_entry(head->next, struct foo, list);
		list_del(pos->list);
		...
	}
or some variant thereof.

With this patch in, people can use
	while_list_drain_entry(pos, head, list) {
		...
	}

The patch also adds a while_list_drain variant, even though I have
only found a single user for that one so far.

Signed-off-by: Joern Engel <joern@logfs.org>
---
 include/linux/list.h |   18 ++++++++++++++++++
 1 file changed, 18 insertions(+)

Comments

David Sterba June 5, 2013, 2:32 p.m. UTC | #1
On Tue, Jun 04, 2013 at 10:03:41PM -0400, Jörn Engel wrote:
> I have seen a lot of boilerplate code that either follows the pattern of
> 	while (!list_empty(head)) {
> 		pos = list_entry(head->next, struct foo, list);
> 		list_del(pos->list);
> 		...
> 	}
> or some variant thereof.
> 
> With this patch in, people can use
> 	while_list_drain_entry(pos, head, list) {
> 		...
> 	}

The while_list_drain_entry way changes the semantics: the list link is
deleted before the {...} body starts, so it's not possible to access the
list anymore. None of the code you've converted uses this, from that
point it's safe, but if this is about to be a public interface, it
should be (at least) documented.

Macro trickery to postpone list_del after the {...} finishes does not
work if kfree/kmem_cache_free/rcu_string_free/... is used.


david
--
To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/include/linux/list.h b/include/linux/list.h
index 6a1f8df..ab39c7d 100644
--- a/include/linux/list.h
+++ b/include/linux/list.h
@@ -557,6 +557,24 @@  static inline void list_splice_tail_init(struct list_head *list,
 #define list_safe_reset_next(pos, n, member)				\
 	n = list_entry(pos->member.next, typeof(*pos), member)
 
+/**
+ * while_list_drain - removes an entry from the list until it is empty
+ * @pos:	the &struct list_head to use as a loop cursor.
+ * @head:	the head of your list.
+ */
+#define while_list_drain(pos, head) \
+	while (list_empty(head) ? 0 : (pos = (head)->next, list_del(pos), 1))
+
+/**
+ * while_list_drain_entry - removes an entry from the list until it is empty
+ * @pos:	the type * to use as loop cursor.
+ * @head:	the head of your list.
+ * @member:	the name of the list_struct within the struct
+ */
+#define while_list_drain_entry(pos, head, member) \
+	while (list_empty(head) && (pos = list_first_entry((head), \
+		typeof(*pos), member), list_del((head)->next), 1))
+
 /*
  * Double linked lists with a single pointer list head.
  * Mostly useful for hash tables where the two pointer list head is