All of lore.kernel.org
 help / color / mirror / Atom feed
From: Kaitao Cheng <kaitao.cheng@linux.dev>
To: "David Laight" <david.laight.linux@gmail.com>,
	"Jani Nikula" <jani.nikula@linux.intel.com>,
	"Christian König" <christian.koenig@amd.com>,
	"David Hildenbrand" <david@kernel.org>,
	"Nathan Chancellor" <nathan@kernel.org>,
	"Andy Shevchenko" <andriy.shevchenko@linux.intel.com>,
	"Nicolas Schier" <nsc@kernel.org>
Cc: Christian Brauner <brauner@kernel.org>,
	"Paul E . McKenney" <paulmck@kernel.org>,
	David Howells <dhowells@redhat.com>,
	Simona Vetter <simona.vetter@ffwll.ch>,
	Neeraj Upadhyay <neeraj.upadhyay@kernel.org>,
	Luca Ceresoli <luca.ceresoli@bootlin.com>,
	Randy Dunlap <rdunlap@infradead.org>,
	Kaitao Cheng <chengkaitao@kylinos.cn>,
	Andrew Morton <akpm@linux-foundation.org>,
	Philipp Stanner <phasta@kernel.org>,
	Alex Williamson <alex@shazbot.org>,
	David Matlack <dmatlack@google.com>,
	Shuah Khan <skhan@linuxfoundation.org>,
	"Joy H . J . Lee" <rkr0k0r@gmail.com>,
	Peter Zijlstra <peterz@infradead.org>,
	Ian Rogers <irogers@google.com>,
	Namhyung Kim <namhyung@kernel.org>,
	Swapnil Sapkal <swapnil.sapkal@amd.com>,
	linux-kbuild@vger.kernel.org, linux-kernel@vger.kernel.org
Subject: [PATCH v4 3/4] tools/list: Add mutable iterator variants
Date: Thu, 30 Jul 2026 17:50:35 +0800	[thread overview]
Message-ID: <20260730095041.35715-4-kaitao.cheng@linux.dev> (raw)
In-Reply-To: <20260730095041.35715-1-kaitao.cheng@linux.dev>

From: Kaitao Cheng <chengkaitao@kylinos.cn>

The tools tree carries its own copy of the list helpers, but it does not
provide the mutable iterator variants available to in-kernel users. Tools
therefore still need to declare and pass a temporary cursor when removing
the current entry during iteration, even when the loop body never uses it.

This commit complements the work to add support for mutable iterator
variants. Add the list and hlist *_mutable() iterator variants to the
tools copy. Keep the temporary cursor in a uniquely named local variable
while preserving the removal-safe iteration semantics.

Keep the existing *_safe() variants for callers that need to access or
reset the temporary cursor, and clarify the distinction in their
documentation. Provide a __UNIQUE_ID fallback because the tools compiler
headers do not define it.

Signed-off-by: Kaitao Cheng <chengkaitao@kylinos.cn>
---
 tools/include/linux/compiler.h |   2 +
 tools/include/linux/list.h     | 184 +++++++++++++++++++++++++++++++--
 2 files changed, 180 insertions(+), 6 deletions(-)

diff --git a/tools/include/linux/compiler.h b/tools/include/linux/compiler.h
index f2f54b038168..9edbb09d67f3 100644
--- a/tools/include/linux/compiler.h
+++ b/tools/include/linux/compiler.h
@@ -242,6 +242,8 @@ static __always_inline void __write_once_size(volatile void *p, void *res, int s
 #define ___PASTE(a, b) a##b
 #define __PASTE(a, b) ___PASTE(a, b)
 
+#define __UNIQUE_ID(name) __PASTE(__UNIQUE_ID_, __PASTE(name, __PASTE(_, __COUNTER__)))
+
 #ifndef OPTIMIZER_HIDE_VAR
 /* Make the optimizer believe the variable can be manipulated arbitrarily. */
 #define OPTIMIZER_HIDE_VAR(var)						\
diff --git a/tools/include/linux/list.h b/tools/include/linux/list.h
index a692ff7aed5c..28e42aaee062 100644
--- a/tools/include/linux/list.h
+++ b/tools/include/linux/list.h
@@ -439,25 +439,59 @@ static inline void list_splice_tail_init(struct list_head *list,
 
 /**
  * list_for_each_safe - iterate over a list safe against removal of list entry
+ *	with a caller-provided temporary cursor
  * @pos:	the &struct list_head to use as a loop cursor.
  * @n:		another &struct list_head to use as temporary storage
  * @head:	the head for your list.
+ *
+ * If the caller does not need to access the temporary cursor, use
+ * list_for_each_mutable() instead.
  */
 #define list_for_each_safe(pos, n, head) \
 	for (pos = (head)->next, n = pos->next; pos != (head); \
 		pos = n, n = pos->next)
 
+#define __list_for_each_mutable(pos, tmp, head)				\
+	for (typeof(pos) tmp = (pos = (head)->next)->next;		\
+	     pos != (head); pos = tmp, tmp = pos->next)
+
 /**
- * list_for_each_prev_safe - iterate over a list backwards safe against removal of list entry
+ * list_for_each_mutable - iterate over a list safe against removal of the
+ *	current entry with an internal temporary cursor
+ * @pos:	the &struct list_head to use as a loop cursor.
+ * @head:	the head for your list.
+ */
+#define list_for_each_mutable(pos, head)				\
+	__list_for_each_mutable(pos, __UNIQUE_ID(next), head)
+
+/**
+ * list_for_each_prev_safe - iterate over a list backwards safe against removal
+ *	of the current entry with a caller-provided temporary cursor
  * @pos:	the &struct list_head to use as a loop cursor.
  * @n:		another &struct list_head to use as temporary storage
  * @head:	the head for your list.
+ *
+ * If the caller does not need to access the temporary cursor, use
+ * list_for_each_prev_mutable() instead.
  */
 #define list_for_each_prev_safe(pos, n, head) \
 	for (pos = (head)->prev, n = pos->prev; \
 	     pos != (head); \
 	     pos = n, n = pos->prev)
 
+#define __list_for_each_prev_mutable(pos, tmp, head)			\
+	for (typeof(pos) tmp = (pos = (head)->prev)->prev;		\
+	     pos != (head); pos = tmp, tmp = pos->prev)
+
+/**
+ * list_for_each_prev_mutable - iterate over a list backwards safe against
+ *	removal of the current entry with an internal temporary cursor
+ * @pos:	the &struct list_head to use as a loop cursor.
+ * @head:	the head for your list.
+ */
+#define list_for_each_prev_mutable(pos, head)				\
+	__list_for_each_prev_mutable(pos, __UNIQUE_ID(prev), head)
+
 /**
  * list_for_each_entry	-	iterate over list of given type
  * @pos:	the type * to use as a loop cursor.
@@ -532,11 +566,15 @@ static inline void list_splice_tail_init(struct list_head *list,
 	     pos = list_next_entry(pos, member))
 
 /**
- * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry
+ * list_for_each_entry_safe - iterate over list of given type safe against
+ *	removal of the current entry with a caller-provided temporary cursor
  * @pos:	the type * to use as a loop cursor.
  * @n:		another type * to use as temporary storage
  * @head:	the head for your list.
  * @member:	the name of the list_head within the struct.
+ *
+ * If the caller does not need to access the temporary cursor, use
+ * list_for_each_entry_mutable() instead.
  */
 #define list_for_each_entry_safe(pos, n, head, member)			\
 	for (pos = list_first_entry(head, typeof(*pos), member),	\
@@ -544,15 +582,35 @@ static inline void list_splice_tail_init(struct list_head *list,
 	     &pos->member != (head); 					\
 	     pos = n, n = list_next_entry(n, member))
 
+#define __list_for_each_entry_mutable(pos, tmp, head, member)		\
+	for (typeof(pos) tmp = list_next_entry(pos =			\
+		list_first_entry(head, typeof(*pos), member), member);	\
+	     &pos->member != (head);					\
+	     pos = tmp, tmp = list_next_entry(tmp, member))
+
+/**
+ * list_for_each_entry_mutable - iterate over a list safe against removal of
+ *	the current entry with an internal temporary cursor
+ * @pos:	the type * to use as a loop cursor.
+ * @head:	the head for your list.
+ * @member:	the name of the list_head within the struct.
+ */
+#define list_for_each_entry_mutable(pos, head, member)			\
+	__list_for_each_entry_mutable(pos, __UNIQUE_ID(next), head, member)
+
 /**
  * list_for_each_entry_safe_continue - continue list iteration safe against removal
+ *	of the current entry with a caller-provided temporary cursor
  * @pos:	the type * to use as a loop cursor.
  * @n:		another type * to use as temporary storage
  * @head:	the head for your list.
  * @member:	the name of the list_head within the struct.
  *
  * Iterate over list of given type, continuing after current point,
- * safe against removal of list entry.
+ * safe against removal of the current entry.
+ *
+ * If the caller does not need to access the temporary cursor, use
+ * list_for_each_entry_mutable_continue() instead.
  */
 #define list_for_each_entry_safe_continue(pos, n, head, member) 		\
 	for (pos = list_next_entry(pos, member), 				\
@@ -560,30 +618,78 @@ static inline void list_splice_tail_init(struct list_head *list,
 	     &pos->member != (head);						\
 	     pos = n, n = list_next_entry(n, member))
 
+#define __list_for_each_entry_mutable_continue(pos, tmp, head, member)	\
+	for (typeof(pos) tmp = list_next_entry(pos =			\
+		list_next_entry(pos, member), member);			\
+	     &pos->member != (head);					\
+	     pos = tmp, tmp = list_next_entry(tmp, member))
+
+/**
+ * list_for_each_entry_mutable_continue - continue list iteration safe against
+ *	removal of the current entry with an internal temporary cursor
+ * @pos:	the type * to use as a loop cursor.
+ * @head:	the head for your list.
+ * @member:	the name of the list_head within the struct.
+ *
+ * Iterate over list of given type, continuing after current point,
+ * safe against removal of the current entry.
+ */
+#define list_for_each_entry_mutable_continue(pos, head, member)		\
+	__list_for_each_entry_mutable_continue(pos,			\
+					       __UNIQUE_ID(next),	\
+					       head, member)
+
 /**
  * list_for_each_entry_safe_from - iterate over list from current point safe against removal
+ *	of the current entry with a caller-provided temporary cursor
  * @pos:	the type * to use as a loop cursor.
  * @n:		another type * to use as temporary storage
  * @head:	the head for your list.
  * @member:	the name of the list_head within the struct.
  *
  * Iterate over list of given type from current point, safe against
- * removal of list entry.
+ * removal of the current entry.
+ *
+ * If the caller does not need to access the temporary cursor, use
+ * list_for_each_entry_mutable_from() instead.
  */
 #define list_for_each_entry_safe_from(pos, n, head, member) 			\
 	for (n = list_next_entry(pos, member);					\
 	     &pos->member != (head);						\
 	     pos = n, n = list_next_entry(n, member))
 
+#define __list_for_each_entry_mutable_from(pos, tmp, head, member)	\
+	for (typeof(pos) tmp = list_next_entry(pos, member);		\
+	     &pos->member != (head);					\
+	     pos = tmp, tmp = list_next_entry(tmp, member))
+
+/**
+ * list_for_each_entry_mutable_from - iterate over list from current point safe
+ *	against removal of the current entry with an internal temporary cursor
+ * @pos:	the type * to use as a loop cursor.
+ * @head:	the head for your list.
+ * @member:	the name of the list_head within the struct.
+ *
+ * Iterate over list of given type from current point, safe against
+ * removal of the current entry.
+ */
+#define list_for_each_entry_mutable_from(pos, head, member)		\
+	__list_for_each_entry_mutable_from(pos, __UNIQUE_ID(next),	\
+					   head, member)
+
 /**
  * list_for_each_entry_safe_reverse - iterate backwards over list safe against removal
+ *	of the current entry with a caller-provided temporary cursor
  * @pos:	the type * to use as a loop cursor.
  * @n:		another type * to use as temporary storage
  * @head:	the head for your list.
  * @member:	the name of the list_head within the struct.
  *
  * Iterate backwards over list of given type, safe against removal
- * of list entry.
+ * of the current entry.
+ *
+ * If the caller does not need to access the temporary cursor, use
+ * list_for_each_entry_mutable_reverse() instead.
  */
 #define list_for_each_entry_safe_reverse(pos, n, head, member)		\
 	for (pos = list_last_entry(head, typeof(*pos), member),		\
@@ -591,6 +697,27 @@ static inline void list_splice_tail_init(struct list_head *list,
 	     &pos->member != (head); 					\
 	     pos = n, n = list_prev_entry(n, member))
 
+#define __list_for_each_entry_mutable_reverse(pos, tmp, head, member)	\
+	for (typeof(pos) tmp = list_prev_entry(pos =			\
+		list_last_entry(head, typeof(*pos), member), member);	\
+	     &pos->member != (head);					\
+	     pos = tmp, tmp = list_prev_entry(tmp, member))
+
+/**
+ * list_for_each_entry_mutable_reverse - iterate backwards over list safe
+ *	against removal of the current entry with an internal temporary cursor
+ * @pos:	the type * to use as a loop cursor.
+ * @head:	the head for your list.
+ * @member:	the name of the list_head within the struct.
+ *
+ * Iterate backwards over list of given type, safe against removal
+ * of the current entry.
+ */
+#define list_for_each_entry_mutable_reverse(pos, head, member)		\
+	__list_for_each_entry_mutable_reverse(pos,			\
+					      __UNIQUE_ID(prev),		\
+					      head, member)
+
 /**
  * list_safe_reset_next - reset a stale list_for_each_entry_safe loop
  * @pos:	the loop cursor used in the list_for_each_entry_safe loop
@@ -717,10 +844,33 @@ static inline void hlist_move_list(struct hlist_head *old,
 #define hlist_for_each(pos, head) \
 	for (pos = (head)->first; pos ; pos = pos->next)
 
+/**
+ * hlist_for_each_safe - iterate over a hlist safe against removal of the
+ *	current entry with a caller-provided temporary cursor
+ * @pos:	the &struct hlist_node to use as a loop cursor.
+ * @n:		another &struct hlist_node to use as temporary storage.
+ * @head:	the head for your hlist.
+ *
+ * If the caller does not need to access the temporary cursor, use
+ * hlist_for_each_mutable() instead.
+ */
 #define hlist_for_each_safe(pos, n, head) \
 	for (pos = (head)->first; pos && ({ n = pos->next; 1; }); \
 	     pos = n)
 
+#define __hlist_for_each_mutable(pos, tmp, head)			\
+	for (typeof(pos) tmp = (pos = (head)->first) ? pos->next : NULL;\
+	     pos; pos = tmp, tmp = pos ? pos->next : NULL)
+
+/**
+ * hlist_for_each_mutable - iterate over a hlist safe against removal of the
+ *	current entry with an internal temporary cursor
+ * @pos:	the &struct hlist_node to use as a loop cursor.
+ * @head:	the head for your hlist.
+ */
+#define hlist_for_each_mutable(pos, head)				\
+	__hlist_for_each_mutable(pos, __UNIQUE_ID(next), head)
+
 #define hlist_entry_safe(ptr, type, member) \
 	({ typeof(ptr) ____ptr = (ptr); \
 	   ____ptr ? hlist_entry(____ptr, type, member) : NULL; \
@@ -757,17 +907,39 @@ static inline void hlist_move_list(struct hlist_head *old,
 	     pos = hlist_entry_safe((pos)->member.next, typeof(*(pos)), member))
 
 /**
- * hlist_for_each_entry_safe - iterate over list of given type safe against removal of list entry
+ * hlist_for_each_entry_safe - iterate over list of given type safe against
+ *	removal of the current entry with a caller-provided temporary cursor
  * @pos:	the type * to use as a loop cursor.
  * @n:		another &struct hlist_node to use as temporary storage
  * @head:	the head for your list.
  * @member:	the name of the hlist_node within the struct.
+ *
+ * If the caller does not need to access the temporary cursor, use
+ * hlist_for_each_entry_mutable() instead.
  */
 #define hlist_for_each_entry_safe(pos, n, head, member) 		\
 	for (pos = hlist_entry_safe((head)->first, typeof(*pos), member);\
 	     pos && ({ n = pos->member.next; 1; });			\
 	     pos = hlist_entry_safe(n, typeof(*pos), member))
 
+#define __hlist_for_each_entry_mutable(pos, tmp, head, member)		\
+	for (struct hlist_node *tmp = (pos =				\
+		hlist_entry_safe((head)->first, typeof(*pos), member)) ? \
+		pos->member.next : NULL;					\
+	     pos;							\
+	     pos = hlist_entry_safe(tmp, typeof(*pos), member),		\
+		tmp = pos ? pos->member.next : NULL)
+
+/**
+ * hlist_for_each_entry_mutable - iterate over hlist safe against removal of
+ *	the current entry with an internal temporary cursor
+ * @pos:	the type * to use as a loop cursor.
+ * @head:	the head for your hlist.
+ * @member:	the name of the hlist_node within the struct.
+ */
+#define hlist_for_each_entry_mutable(pos, head, member)			\
+	__hlist_for_each_entry_mutable(pos, __UNIQUE_ID(next), head, member)
+
 /**
  * list_del_range - deletes range of entries from list.
  * @begin: first element in the range to delete from the list.
-- 
2.43.0


  parent reply	other threads:[~2026-07-30  9:52 UTC|newest]

Thread overview: 5+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-07-30  9:50 [PATCH v4 0/4] Prepare mutable list iterators to cache cursor state Kaitao Cheng
2026-07-30  9:50 ` [PATCH v4 1/4] list: Add mutable iterator variants Kaitao Cheng
2026-07-30  9:50 ` [PATCH v4 2/4] llist: " Kaitao Cheng
2026-07-30  9:50 ` Kaitao Cheng [this message]
2026-07-30  9:50 ` [PATCH v4 4/4] scripts/list: " Kaitao Cheng

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260730095041.35715-4-kaitao.cheng@linux.dev \
    --to=kaitao.cheng@linux.dev \
    --cc=akpm@linux-foundation.org \
    --cc=alex@shazbot.org \
    --cc=andriy.shevchenko@linux.intel.com \
    --cc=brauner@kernel.org \
    --cc=chengkaitao@kylinos.cn \
    --cc=christian.koenig@amd.com \
    --cc=david.laight.linux@gmail.com \
    --cc=david@kernel.org \
    --cc=dhowells@redhat.com \
    --cc=dmatlack@google.com \
    --cc=irogers@google.com \
    --cc=jani.nikula@linux.intel.com \
    --cc=linux-kbuild@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=luca.ceresoli@bootlin.com \
    --cc=namhyung@kernel.org \
    --cc=nathan@kernel.org \
    --cc=neeraj.upadhyay@kernel.org \
    --cc=nsc@kernel.org \
    --cc=paulmck@kernel.org \
    --cc=peterz@infradead.org \
    --cc=phasta@kernel.org \
    --cc=rdunlap@infradead.org \
    --cc=rkr0k0r@gmail.com \
    --cc=simona.vetter@ffwll.ch \
    --cc=skhan@linuxfoundation.org \
    --cc=swapnil.sapkal@amd.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.