[PATCH v4 4/4] scripts/list: Add mutable iterator variants
Kaitao Cheng <[email protected]> Thu, 30 Jul 2026 17:50:36 +0800
| Newsgroups | org.kernel.vger.linux-kbuild,org.kernel.vger.linux-kernel |
|---|---|
| Message-ID | <[email protected]> |
From: Kaitao Cheng <[email protected]> The kernel has added mutable iterator variants, so sync the scripts/list implementation accordingly. The safe iterators require callers to declare and pass a temporary cursor even when the loop body only needs to remove the current entry. Add list_for_each_entry_mutable() and hlist_for_each_entry_mutable() so callers can use removal-safe iteration without exposing the temporary cursor. Keep the existing safe variants for users that need direct access to the cursor, and document the distinction. Add local __PASTE() and __UNIQUE_ID() helpers to generate the internal cursor name, matching the format used by include/linux/compiler.h. Signed-off-by: Kaitao Cheng <[email protected]> --- scripts/include/list.h | 56 ++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 54 insertions(+), 2 deletions(-) diff --git a/scripts/include/list.h b/scripts/include/list.h index 8bdcaadca709..ff1c84339344 100644 --- a/scripts/include/list.h +++ b/scripts/include/list.h @@ -9,6 +9,16 @@ /* Are two types/vars the same type (ignoring qualifiers)? */ #define __same_type(a, b) __builtin_types_compatible_p(typeof(a), typeof(b)) +#ifndef __PASTE +/* Indirect macros required for expanded argument pasting, eg. __LINE__. */ +#define ___PASTE(a, b) a##b +#define __PASTE(a, b) ___PASTE(a, b) +#endif + +#ifndef __UNIQUE_ID +#define __UNIQUE_ID(name) __PASTE(__UNIQUE_ID_, __PASTE(name, __PASTE(_, __COUNTER__))) +#endif + /** * container_of - cast a member of a structure out to the containing structure * @ptr: the pointer to the member. @@ -298,11 +308,15 @@ static inline int list_empty(const struct list_head *head) pos = list_prev_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 list 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), \ @@ -310,6 +324,22 @@ static inline int list_empty(const struct list_head *head) !list_entry_is_head(pos, head, member); \ 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); \ + !list_entry_is_head(pos, head, member); \ + pos = tmp, tmp = list_next_entry(tmp, member)) + +/** + * list_for_each_entry_mutable - iterate over a list safe against removal of + * list 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) + /* * Double linked lists with a single pointer list head. * Mostly useful for hash tables where the two pointer list head is @@ -414,15 +444,37 @@ static inline void hlist_add_head(struct hlist_node *n, struct hlist_head *h) 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 list entry with a caller-provided temporary cursor * @pos: the type * to use as a loop cursor. * @n: a &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 + * list 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) + #endif /* LIST_H */ -- 2.43.0