aboutsummaryrefslogtreecommitdiff
path: root/src/helper/list.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/helper/list.h')
-rw-r--r--src/helper/list.h934
1 files changed, 225 insertions, 709 deletions
diff --git a/src/helper/list.h b/src/helper/list.h
index c9de056..eb8858e 100644
--- a/src/helper/list.h
+++ b/src/helper/list.h
@@ -1,15 +1,31 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
+/* SPDX-License-Identifier: BSD-2-Clause */
/*
- * The content of this file is mainly copied/inspired from Linux kernel
- * code in include/linux/list.h, include/linux/types.h
- * Last aligned with kernel v5.12:
- * - skip the functions hlist_unhashed_lockless() and __list_del_clearprev()
- * that are relevant only in kernel;
- * - Remove non-standard GCC extension "omitted conditional operand" from
- * list_prepare_entry;
- * - expand READ_ONCE, WRITE_ONCE, smp_load_acquire, smp_store_release;
- * - make comments compatible with doxygen.
+ * Copyright (c) 2010 Isilon Systems, Inc.
+ * Copyright (c) 2010 iX Systems, Inc.
+ * Copyright (c) 2010 Panasas, Inc.
+ * Copyright (c) 2013-2016 Mellanox Technologies, Ltd.
+ * Copyright (c) 2021-2024 by Antonio Borneo <borneo.antonio@gmail.com>
+ * All rights reserved.
+ */
+
+/*
+ * Circular doubly linked list implementation.
+ *
+ * The content of this file is mainly copied/inspired from FreeBSD code in:
+ * https://cgit.freebsd.org/src/tree/
+ * files:
+ * sys/compat/linuxkpi/common/include/linux/list.h
+ * sys/compat/linuxkpi/common/include/linux/types.h
+ *
+ * Last aligned with release/13.3.0:
+ *
+ * - Skip 'hlist_*' double linked lists with a single pointer list head.
+ * - Expand WRITE_ONCE().
+ * - Use TAB for indentation.
+ * - Put macro arguments within parenthesis.
+ * - Remove blank lines after an open brace '{'.
+ * - Remove multiple assignment.
*
* There is an example of using this file in contrib/list_example.c.
*/
@@ -17,155 +33,64 @@
#ifndef OPENOCD_HELPER_LIST_H
#define OPENOCD_HELPER_LIST_H
-/* begin local changes */
-#include <helper/types.h>
+/* begin OpenOCD changes */
-#define LIST_POISON1 NULL
-#define LIST_POISON2 NULL
+#include <helper/types.h>
struct list_head {
- struct list_head *next, *prev;
+ struct list_head *next;
+ struct list_head *prev;
};
-/* end local changes */
-
-/*
- * Circular doubly linked list implementation.
- *
- * Some of the internal functions ("__xxx") are useful when
- * manipulating whole lists rather than single entries, as
- * sometimes we already know the next/prev entries and we can
- * generate better code by using them directly rather than
- * using the generic single-entry routines.
- */
+/* end OpenOCD changes */
#define LIST_HEAD_INIT(name) { &(name), &(name) }
#define LIST_HEAD(name) \
struct list_head name = LIST_HEAD_INIT(name)
-/**
- * INIT_LIST_HEAD - Initialize a list_head structure
- * @param list list_head structure to be initialized.
- *
- * Initializes the list_head to point to itself. If it is a list header,
- * the result is an empty list.
- */
-static inline void INIT_LIST_HEAD(struct list_head *list)
+static inline void
+INIT_LIST_HEAD(struct list_head *list)
{
list->next = list;
list->prev = list;
}
-#ifdef CONFIG_DEBUG_LIST
-extern bool __list_add_valid(struct list_head *new,
- struct list_head *prev,
- struct list_head *next);
-extern bool __list_del_entry_valid(struct list_head *entry);
-#else
-static inline bool __list_add_valid(struct list_head *new,
- struct list_head *prev,
- struct list_head *next)
-{
- return true;
-}
-static inline bool __list_del_entry_valid(struct list_head *entry)
+static inline int
+list_empty(const struct list_head *head)
{
- return true;
+ return (head->next == head);
}
-#endif
-/*
- * Insert a new entry between two known consecutive entries.
- *
- * This is only for internal list manipulation where we know
- * the prev/next entries already!
- */
-static inline void __list_add(struct list_head *new,
- struct list_head *prev,
- struct list_head *next)
-{
- if (!__list_add_valid(new, prev, next))
- return;
-
- next->prev = new;
- new->next = next;
- new->prev = prev;
- prev->next = new;
-}
-
-/**
- * list_add - add a new entry
- * @param new new entry to be added
- * @param head list head to add it after
- *
- * Insert a new entry after the specified head.
- * This is good for implementing stacks.
- */
-static inline void list_add(struct list_head *new, struct list_head *head)
+static inline int
+list_empty_careful(const struct list_head *head)
{
- __list_add(new, head, head->next);
-}
-
+ struct list_head *next = head->next;
-/**
- * list_add_tail - add a new entry
- * @param new new entry to be added
- * @param head list head to add it before
- *
- * Insert a new entry before the specified head.
- * This is useful for implementing queues.
- */
-static inline void list_add_tail(struct list_head *new, struct list_head *head)
-{
- __list_add(new, head->prev, head);
+ return ((next == head) && (next == head->prev));
}
-/*
- * Delete a list entry by making the prev/next entries
- * point to each other.
- *
- * This is only for internal list manipulation where we know
- * the prev/next entries already!
- */
-static inline void __list_del(struct list_head *prev, struct list_head *next)
+static inline void
+__list_del(struct list_head *prev, struct list_head *next)
{
next->prev = prev;
prev->next = next;
}
-/* Ignore kernel __list_del_clearprev() */
-
-static inline void __list_del_entry(struct list_head *entry)
+static inline void
+__list_del_entry(struct list_head *entry)
{
- if (!__list_del_entry_valid(entry))
- return;
-
__list_del(entry->prev, entry->next);
}
-/**
- * list_del - deletes entry from list.
- * @param entry the element to delete from the list.
- * Note: list_empty() on entry does not return true after this, the entry is
- * in an undefined state.
- */
-static inline void list_del(struct list_head *entry)
+static inline void
+list_del(struct list_head *entry)
{
- __list_del_entry(entry);
- entry->next = LIST_POISON1;
- entry->prev = LIST_POISON2;
+ __list_del(entry->prev, entry->next);
}
-/**
- * list_replace - replace old entry by new one
- * @param old the element to be replaced
- * @param new the new element to insert
- *
- * If @a old was empty, it will be overwritten.
- */
-static inline void list_replace(struct list_head *old,
- struct list_head *new)
+static inline void
+list_replace(struct list_head *old, struct list_head *new)
{
new->next = old->next;
new->next->prev = new;
@@ -173,205 +98,189 @@ static inline void list_replace(struct list_head *old,
new->prev->next = new;
}
-/**
- * list_replace_init - replace old entry by new one and initialize the old one
- * @param old the element to be replaced
- * @param new the new element to insert
- *
- * If @a old was empty, it will be overwritten.
- */
-static inline void list_replace_init(struct list_head *old,
- struct list_head *new)
+static inline void
+list_replace_init(struct list_head *old, struct list_head *new)
{
list_replace(old, new);
INIT_LIST_HEAD(old);
}
-/**
- * list_swap - replace entry1 with entry2 and re-add entry1 at entry2's position
- * @param entry1 the location to place entry2
- * @param entry2 the location to place entry1
- */
-static inline void list_swap(struct list_head *entry1,
- struct list_head *entry2)
+static inline void
+linux_list_add(struct list_head *new, struct list_head *prev,
+ struct list_head *next)
{
- struct list_head *pos = entry2->prev;
-
- list_del(entry2);
- list_replace(entry1, entry2);
- if (pos == entry1)
- pos = entry2;
- list_add(entry1, pos);
+ next->prev = new;
+ new->next = next;
+ new->prev = prev;
+ prev->next = new;
}
-/**
- * list_del_init - deletes entry from list and reinitialize it.
- * @param entry the element to delete from the list.
- */
-static inline void list_del_init(struct list_head *entry)
+static inline void
+list_del_init(struct list_head *entry)
{
- __list_del_entry(entry);
+ list_del(entry);
INIT_LIST_HEAD(entry);
}
-/**
- * list_move - delete from one list and add as another's head
- * @param list the entry to move
- * @param head the head that will precede our entry
- */
-static inline void list_move(struct list_head *list, struct list_head *head)
+#define list_entry(ptr, type, field) container_of(ptr, type, field)
+
+#define list_first_entry(ptr, type, member) \
+ list_entry((ptr)->next, type, member)
+
+#define list_last_entry(ptr, type, member) \
+ list_entry((ptr)->prev, type, member)
+
+#define list_first_entry_or_null(ptr, type, member) \
+ (!list_empty(ptr) ? list_first_entry(ptr, type, member) : NULL)
+
+#define list_next_entry(ptr, member) \
+ list_entry(((ptr)->member.next), typeof(*(ptr)), member)
+
+#define list_safe_reset_next(ptr, n, member) \
+ (n) = list_next_entry(ptr, member)
+
+#define list_prev_entry(ptr, member) \
+ list_entry(((ptr)->member.prev), typeof(*(ptr)), member)
+
+#define list_for_each(p, head) \
+ for (p = (head)->next; p != (head); p = (p)->next)
+
+#define list_for_each_safe(p, n, head) \
+ for (p = (head)->next, n = (p)->next; p != (head); p = n, n = (p)->next)
+
+#define list_for_each_entry(p, h, field) \
+ for (p = list_entry((h)->next, typeof(*p), field); &(p)->field != (h); \
+ p = list_entry((p)->field.next, typeof(*p), field))
+
+#define list_for_each_entry_safe(p, n, h, field) \
+ for (p = list_entry((h)->next, typeof(*p), field), \
+ n = list_entry((p)->field.next, typeof(*p), field); &(p)->field != (h);\
+ p = n, n = list_entry(n->field.next, typeof(*n), field))
+
+#define list_for_each_entry_from(p, h, field) \
+ for ( ; &(p)->field != (h); \
+ p = list_entry((p)->field.next, typeof(*p), field))
+
+#define list_for_each_entry_continue(p, h, field) \
+ for (p = list_next_entry((p), field); &(p)->field != (h); \
+ p = list_next_entry((p), field))
+
+#define list_for_each_entry_safe_from(pos, n, head, member) \
+ for (n = list_entry((pos)->member.next, typeof(*pos), member); \
+ &(pos)->member != (head); \
+ pos = n, n = list_entry(n->member.next, typeof(*n), member))
+
+#define list_for_each_entry_reverse(p, h, field) \
+ for (p = list_entry((h)->prev, typeof(*p), field); &(p)->field != (h); \
+ p = list_entry((p)->field.prev, typeof(*p), field))
+
+#define list_for_each_entry_safe_reverse(p, n, h, field) \
+ for (p = list_entry((h)->prev, typeof(*p), field), \
+ n = list_entry((p)->field.prev, typeof(*p), field); &(p)->field != (h); \
+ p = n, n = list_entry(n->field.prev, typeof(*n), field))
+
+#define list_for_each_entry_continue_reverse(p, h, field) \
+ for (p = list_entry((p)->field.prev, typeof(*p), field); &(p)->field != (h); \
+ p = list_entry((p)->field.prev, typeof(*p), field))
+
+#define list_for_each_prev(p, h) for (p = (h)->prev; p != (h); p = (p)->prev)
+
+#define list_for_each_entry_from_reverse(p, h, field) \
+ for (; &p->field != (h); \
+ p = list_prev_entry(p, field))
+
+static inline void
+list_add(struct list_head *new, struct list_head *head)
{
- __list_del_entry(list);
- list_add(list, head);
+ linux_list_add(new, head, head->next);
}
-/**
- * list_move_tail - delete from one list and add as another's tail
- * @param list the entry to move
- * @param head the head that will follow our entry
- */
-static inline void list_move_tail(struct list_head *list,
- struct list_head *head)
+static inline void
+list_add_tail(struct list_head *new, struct list_head *head)
{
- __list_del_entry(list);
- list_add_tail(list, head);
+ linux_list_add(new, head->prev, head);
}
-/**
- * list_bulk_move_tail - move a subsection of a list to its tail
- * @param head the head that will follow our entry
- * @param first the first entry to move
- * @param last the last entry to move, can be the same as first
- *
- * Move all entries between @a first and including @a last before @a head.
- * All three entries must belong to the same linked list.
- */
-static inline void list_bulk_move_tail(struct list_head *head,
- struct list_head *first,
- struct list_head *last)
+static inline void
+list_move(struct list_head *list, struct list_head *head)
{
- first->prev->next = last->next;
- last->next->prev = first->prev;
-
- head->prev->next = first;
- first->prev = head->prev;
-
- last->next = head;
- head->prev = last;
+ list_del(list);
+ list_add(list, head);
}
-/**
- * list_is_first -- tests whether @a list is the first entry in list @a head
- * @param list the entry to test
- * @param head the head of the list
- */
-static inline int list_is_first(const struct list_head *list, const struct list_head *head)
+static inline void
+list_move_tail(struct list_head *entry, struct list_head *head)
{
- return list->prev == head;
+ list_del(entry);
+ list_add_tail(entry, head);
}
-/**
- * list_is_last - tests whether @a list is the last entry in list @a head
- * @param list the entry to test
- * @param head the head of the list
- */
-static inline int list_is_last(const struct list_head *list, const struct list_head *head)
+static inline void
+list_rotate_to_front(struct list_head *entry, struct list_head *head)
{
- return list->next == head;
+ list_move_tail(entry, head);
}
-/**
- * list_is_head - tests whether @a list is the list @a head
- * @param list the entry to test
- * @param head the head of the list
- */
-static inline int list_is_head(const struct list_head *list, const struct list_head *head)
+static inline void
+list_bulk_move_tail(struct list_head *head, struct list_head *first,
+ struct list_head *last)
{
- return list == head;
+ first->prev->next = last->next;
+ last->next->prev = first->prev;
+ head->prev->next = first;
+ first->prev = head->prev;
+ last->next = head;
+ head->prev = last;
}
-/**
- * list_empty - tests whether a list is empty
- * @param head the list to test.
- */
-static inline int list_empty(const struct list_head *head)
+static inline void
+linux_list_splice(const struct list_head *list, struct list_head *prev,
+ struct list_head *next)
{
- return head->next == head;
+ struct list_head *first;
+ struct list_head *last;
+
+ if (list_empty(list))
+ return;
+ first = list->next;
+ last = list->prev;
+ first->prev = prev;
+ prev->next = first;
+ last->next = next;
+ next->prev = last;
}
-/**
- * list_del_init_careful - deletes entry from list and reinitialize it.
- * @param entry the element to delete from the list.
- *
- * This is the same as list_del_init(), except designed to be used
- * together with list_empty_careful() in a way to guarantee ordering
- * of other memory operations.
- *
- * Any memory operations done before a list_del_init_careful() are
- * guaranteed to be visible after a list_empty_careful() test.
- */
-static inline void list_del_init_careful(struct list_head *entry)
+static inline void
+list_splice(const struct list_head *list, struct list_head *head)
{
- __list_del_entry(entry);
- entry->prev = entry;
- entry->next = entry;
+ linux_list_splice(list, head, head->next);
}
-/**
- * list_empty_careful - tests whether a list is empty and not being modified
- * @param head the list to test
- *
- * Description:
- * tests whether a list is empty _and_ checks that no other CPU might be
- * in the process of modifying either member (next or prev)
- *
- * NOTE: using list_empty_careful() without synchronization
- * can only be safe if the only activity that can happen
- * to the list entry is list_del_init(). Eg. it cannot be used
- * if another CPU could re-list_add() it.
- */
-static inline int list_empty_careful(const struct list_head *head)
+static inline void
+list_splice_tail(struct list_head *list, struct list_head *head)
{
- struct list_head *next = head->next;
- return (next == head) && (next == head->prev);
+ linux_list_splice(list, head->prev, head);
}
-/**
- * list_rotate_left - rotate the list to the left
- * @param head the head of the list
- */
-static inline void list_rotate_left(struct list_head *head)
+static inline void
+list_splice_init(struct list_head *list, struct list_head *head)
{
- struct list_head *first;
-
- if (!list_empty(head)) {
- first = head->next;
- list_move_tail(first, head);
- }
+ linux_list_splice(list, head, head->next);
+ INIT_LIST_HEAD(list);
}
-/**
- * list_rotate_to_front() - Rotate list to specific item.
- * @param list The desired new front of the list.
- * @param head The head of the list.
- *
- * Rotates list so that @a list becomes the new front of the list.
- */
-static inline void list_rotate_to_front(struct list_head *list,
- struct list_head *head)
+static inline void
+list_splice_tail_init(struct list_head *list, struct list_head *head)
{
- /*
- * Deletes the list head from the list denoted by @a head and
- * places it as the tail of @a list, this effectively rotates the
- * list so that @a list is at the front.
- */
- list_move_tail(head, list);
+ linux_list_splice(list, head->prev, head);
+ INIT_LIST_HEAD(list);
}
-/**
- * list_is_singular - tests whether a list has just one entry.
- * @param head the list to test.
+/*
+ * Double linked lists with a single pointer list head.
+ * IGNORED
*/
+
static inline int list_is_singular(const struct list_head *head)
{
return !list_empty(head) && (head->next == head->prev);
@@ -389,472 +298,79 @@ static inline void __list_cut_position(struct list_head *list,
new_first->prev = head;
}
-/**
- * list_cut_position - cut a list into two
- * @param list a new list to add all removed entries
- * @param head a list with entries
- * @param entry an entry within head, could be the head itself
- * and if so we won't cut the list
- *
- * This helper moves the initial part of @a head, up to and
- * including @a entry, from @a head to @a list. You should
- * pass on @a entry an element you know is on @a head. @a list
- * should be an empty list or a list you do not care about
- * losing its data.
- *
- */
static inline void list_cut_position(struct list_head *list,
struct list_head *head, struct list_head *entry)
{
if (list_empty(head))
return;
- if (list_is_singular(head) && !list_is_head(entry, head) && (entry != head->next))
+ if (list_is_singular(head) &&
+ (head->next != entry && head != entry))
return;
- if (list_is_head(entry, head))
+ if (entry == head)
INIT_LIST_HEAD(list);
else
__list_cut_position(list, head, entry);
}
-/**
- * list_cut_before - cut a list into two, before given entry
- * @param list a new list to add all removed entries
- * @param head a list with entries
- * @param entry an entry within head, could be the head itself
- *
- * This helper moves the initial part of @a head, up to but
- * excluding @a entry, from @a head to @a list. You should pass
- * in @a entry an element you know is on @a head. @a list should
- * be an empty list or a list you do not care about losing
- * its data.
- * If @a entry == @a head, all entries on @a head are moved to
- * @a list.
- */
-static inline void list_cut_before(struct list_head *list,
- struct list_head *head,
- struct list_head *entry)
+static inline int list_is_first(const struct list_head *list,
+ const struct list_head *head)
{
- if (head->next == entry) {
- INIT_LIST_HEAD(list);
- return;
- }
- list->next = head->next;
- list->next->prev = list;
- list->prev = entry->prev;
- list->prev->next = list;
- head->next = entry;
- entry->prev = head;
+ return (list->prev == head);
}
-static inline void __list_splice(const struct list_head *list,
- struct list_head *prev,
- struct list_head *next)
+static inline int list_is_last(const struct list_head *list,
+ const struct list_head *head)
{
- struct list_head *first = list->next;
- struct list_head *last = list->prev;
-
- first->prev = prev;
- prev->next = first;
-
- last->next = next;
- next->prev = last;
-}
-
-/**
- * list_splice - join two lists, this is designed for stacks
- * @param list the new list to add.
- * @param head the place to add it in the first list.
- */
-static inline void list_splice(const struct list_head *list,
- struct list_head *head)
-{
- if (!list_empty(list))
- __list_splice(list, head, head->next);
+ return list->next == head;
}
-/**
- * list_splice_tail - join two lists, each list being a queue
- * @param list the new list to add.
- * @param head the place to add it in the first list.
- */
-static inline void list_splice_tail(struct list_head *list,
- struct list_head *head)
+static inline size_t
+list_count_nodes(const struct list_head *list)
{
- if (!list_empty(list))
- __list_splice(list, head->prev, head);
-}
+ const struct list_head *lh;
+ size_t count;
-/**
- * list_splice_init - join two lists and reinitialise the emptied list.
- * @param list the new list to add.
- * @param head the place to add it in the first list.
- *
- * The list at @a list is reinitialised
- */
-static inline void list_splice_init(struct list_head *list,
- struct list_head *head)
-{
- if (!list_empty(list)) {
- __list_splice(list, head, head->next);
- INIT_LIST_HEAD(list);
+ count = 0;
+ list_for_each(lh, list) {
+ count++;
}
-}
-/**
- * list_splice_tail_init - join two lists and reinitialise the emptied list
- * @param list the new list to add.
- * @param head the place to add it in the first list.
- *
- * Each of the lists is a queue.
- * The list at @a list is reinitialised
- */
-static inline void list_splice_tail_init(struct list_head *list,
- struct list_head *head)
-{
- if (!list_empty(list)) {
- __list_splice(list, head->prev, head);
- INIT_LIST_HEAD(list);
- }
+ return (count);
}
-/**
- * list_entry - get the struct for this entry
- * @param ptr the &struct list_head pointer.
- * @param type the type of the struct this is embedded in.
- * @param member the name of the list_head within the struct.
- */
-#define list_entry(ptr, type, member) \
- container_of(ptr, type, member)
-
-/**
- * list_first_entry - get the first element from a list
- * @param ptr the list head to take the element from.
- * @param type the type of the struct this is embedded in.
- * @param member the name of the list_head within the struct.
- *
- * Note, that list is expected to be not empty.
- */
-#define list_first_entry(ptr, type, member) \
- list_entry((ptr)->next, type, member)
-
-/**
- * list_last_entry - get the last element from a list
- * @param ptr the list head to take the element from.
- * @param type the type of the struct this is embedded in.
- * @param member the name of the list_head within the struct.
- *
- * Note, that list is expected to be not empty.
- */
-#define list_last_entry(ptr, type, member) \
- list_entry((ptr)->prev, type, member)
-
-/**
- * list_first_entry_or_null - get the first element from a list
- * @param ptr the list head to take the element from.
- * @param type the type of the struct this is embedded in.
- * @param member the name of the list_head within the struct.
- *
- * Note that if the list is empty, it returns NULL.
- */
-#define list_first_entry_or_null(ptr, type, member) ({ \
- struct list_head *head__ = (ptr); \
- struct list_head *pos__ = head__->next; \
- pos__ != head__ ? list_entry(pos__, type, member) : NULL; \
-})
-
-/**
- * list_next_entry - get the next element in list
- * @param pos the type * to cursor
- * @param member the name of the list_head within the struct.
- */
-#define list_next_entry(pos, member) \
- list_entry((pos)->member.next, typeof(*(pos)), member)
-
-/**
- * list_next_entry_circular - get the next element in list
- * @param pos the type * to cursor.
- * @param head the list head to take the element from.
- * @param member the name of the list_head within the struct.
- *
- * Wraparound if pos is the last element (return the first element).
- * Note, that list is expected to be not empty.
- */
-#define list_next_entry_circular(pos, head, member) \
- (list_is_last(&(pos)->member, head) ? \
- list_first_entry(head, typeof(*(pos)), member) : list_next_entry(pos, member))
-
-/**
- * list_prev_entry - get the prev element in list
- * @param pos the type * to cursor
- * @param member the name of the list_head within the struct.
- */
-#define list_prev_entry(pos, member) \
- list_entry((pos)->member.prev, typeof(*(pos)), member)
-
-/**
- * list_prev_entry_circular - get the prev element in list
- * @param pos the type * to cursor.
- * @param head the list head to take the element from.
- * @param member the name of the list_head within the struct.
- *
- * Wraparound if pos is the first element (return the last element).
- * Note, that list is expected to be not empty.
- */
-#define list_prev_entry_circular(pos, head, member) \
- (list_is_first(&(pos)->member, head) ? \
- list_last_entry(head, typeof(*(pos)), member) : list_prev_entry(pos, member))
-
-/**
- * list_for_each - iterate over a list
- * @param pos the &struct list_head to use as a loop cursor.
- * @param head the head for your list.
- */
-#define list_for_each(pos, head) \
- for (pos = (head)->next; !list_is_head(pos, (head)); pos = pos->next)
-
-/* Ignore kernel list_for_each_rcu() */
-
-/**
- * list_for_each_continue - continue iteration over a list
- * @param pos the &struct list_head to use as a loop cursor.
- * @param head the head for your list.
- *
- * Continue to iterate over a list, continuing after the current position.
+/*
+ * Double linked lists with a single pointer list head.
+ * IGNORED
*/
-#define list_for_each_continue(pos, head) \
- for (pos = pos->next; pos != (head); pos = pos->next)
-/**
- * list_for_each_prev - iterate over a list backwards
- * @param pos the &struct list_head to use as a loop cursor.
- * @param head the head for your list.
- */
-#define list_for_each_prev(pos, head) \
- for (pos = (head)->prev; pos != (head); pos = pos->prev)
+/* begin OpenOCD extensions */
/**
- * list_for_each_safe - iterate over a list safe against removal of list entry
- * @param pos the &struct list_head to use as a loop cursor.
- * @param n another &struct list_head to use as temporary storage
- * @param head the head for your list.
- */
-#define list_for_each_safe(pos, n, head) \
- for (pos = (head)->next, n = pos->next; pos != (head); \
- pos = n, n = pos->next)
-
-/**
- * list_for_each_prev_safe - iterate over a list backwards safe against removal of list entry
- * @param pos the &struct list_head to use as a loop cursor.
- * @param n another &struct list_head to use as temporary storage
- * @param head the head for your list.
+ * list_for_each_entry_direction - iterate forward/backward over list of given type
+ * @param is_fwd the iterate direction, true for forward, false for backward.
+ * @param p the type * to use as a loop cursor.
+ * @param h the head of the list.
+ * @param field the name of the list_head within the struct.
*/
-#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_entry_direction(is_fwd, p, h, field) \
+ for (p = list_entry(is_fwd ? (h)->next : (h)->prev, typeof(*p), field); \
+ &(p)->field != (h); \
+ p = list_entry(is_fwd ? (p)->field.next : (p)->field.prev, typeof(*p), field))
/**
- * list_count_nodes - count nodes in the list
- * @param head the head for your list.
+ * list_rotate_left - rotate the list to the left
+ * @param h the head of the list
*/
-static inline size_t list_count_nodes(struct list_head *head)
+static inline void list_rotate_left(struct list_head *h)
{
- struct list_head *pos;
- size_t count = 0;
-
- list_for_each(pos, head)
- count++;
+ struct list_head *first;
- return count;
+ if (!list_empty(h)) {
+ first = h->next;
+ list_move_tail(first, h);
+ }
}
-/**
- * list_entry_is_head - test if the entry points to the head of the list
- * @param pos the type * to cursor
- * @param head the head for your list.
- * @param member the name of the list_head within the struct.
- */
-#define list_entry_is_head(pos, head, member) \
- (&pos->member == (head))
-
-/**
- * list_for_each_entry - iterate over list of given type
- * @param pos the type * to use as a loop cursor.
- * @param head the head for your list.
- * @param member the name of the list_head within the struct.
- */
-#define list_for_each_entry(pos, head, member) \
- for (pos = list_first_entry(head, typeof(*pos), member); \
- !list_entry_is_head(pos, head, member); \
- pos = list_next_entry(pos, member))
-
-/**
- * list_for_each_entry_reverse - iterate backwards over list of given type.
- * @param pos the type * to use as a loop cursor.
- * @param head the head for your list.
- * @param member the name of the list_head within the struct.
- */
-#define list_for_each_entry_reverse(pos, head, member) \
- for (pos = list_last_entry(head, typeof(*pos), member); \
- !list_entry_is_head(pos, head, member); \
- pos = list_prev_entry(pos, member))
-
-/**
- * list_for_each_entry_direction - iterate forward/backward over list of given type
- * @param forward the iterate direction, true for forward, false for backward.
- * @param pos the type * to use as a loop cursor.
- * @param head the head for your list.
- * @param member the name of the list_head within the struct.
- */
-#define list_for_each_entry_direction(forward, pos, head, member) \
- for (pos = forward ? list_first_entry(head, typeof(*pos), member) \
- : list_last_entry(head, typeof(*pos), member); \
- !list_entry_is_head(pos, head, member); \
- pos = forward ? list_next_entry(pos, member) \
- : list_prev_entry(pos, member))
-
-/**
- * list_prepare_entry - prepare a pos entry for use in list_for_each_entry_continue()
- * @param pos the type * to use as a start point
- * @param head the head of the list
- * @param member the name of the list_head within the struct.
- *
- * Prepares a pos entry for use as a start point in list_for_each_entry_continue().
- */
-#define list_prepare_entry(pos, head, member) \
- ((pos) ? (pos) : list_entry(head, typeof(*pos), member))
-
-/**
- * list_for_each_entry_continue - continue iteration over list of given type
- * @param pos the type * to use as a loop cursor.
- * @param head the head for your list.
- * @param member the name of the list_head within the struct.
- *
- * Continue to iterate over list of given type, continuing after
- * the current position.
- */
-#define list_for_each_entry_continue(pos, head, member) \
- for (pos = list_next_entry(pos, member); \
- !list_entry_is_head(pos, head, member); \
- pos = list_next_entry(pos, member))
-
-/**
- * list_for_each_entry_continue_reverse - iterate backwards from the given point
- * @param pos the type * to use as a loop cursor.
- * @param head the head for your list.
- * @param member the name of the list_head within the struct.
- *
- * Start to iterate over list of given type backwards, continuing after
- * the current position.
- */
-#define list_for_each_entry_continue_reverse(pos, head, member) \
- for (pos = list_prev_entry(pos, member); \
- !list_entry_is_head(pos, head, member); \
- pos = list_prev_entry(pos, member))
-
-/**
- * list_for_each_entry_from - iterate over list of given type from the current point
- * @param pos the type * to use as a loop cursor.
- * @param head the head for your list.
- * @param member the name of the list_head within the struct.
- *
- * Iterate over list of given type, continuing from current position.
- */
-#define list_for_each_entry_from(pos, head, member) \
- for (; !list_entry_is_head(pos, head, member); \
- pos = list_next_entry(pos, member))
-
-/**
- * list_for_each_entry_from_reverse - iterate backwards over list of given type
- * from the current point
- * @param pos the type * to use as a loop cursor.
- * @param head the head for your list.
- * @param member the name of the list_head within the struct.
- *
- * Iterate backwards over list of given type, continuing from current position.
- */
-#define list_for_each_entry_from_reverse(pos, head, member) \
- for (; !list_entry_is_head(pos, head, member); \
- pos = list_prev_entry(pos, member))
-
-/**
- * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry
- * @param pos the type * to use as a loop cursor.
- * @param n another type * to use as temporary storage
- * @param head the head for your list.
- * @param member the name of the list_head within the struct.
- */
-#define list_for_each_entry_safe(pos, n, head, member) \
- for (pos = list_first_entry(head, typeof(*pos), member), \
- n = list_next_entry(pos, member); \
- !list_entry_is_head(pos, head, member); \
- pos = n, n = list_next_entry(n, member))
-
-/**
- * list_for_each_entry_safe_continue - continue list iteration safe against removal
- * @param pos the type * to use as a loop cursor.
- * @param n another type * to use as temporary storage
- * @param head the head for your list.
- * @param 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.
- */
-#define list_for_each_entry_safe_continue(pos, n, head, member) \
- for (pos = list_next_entry(pos, member), \
- n = list_next_entry(pos, member); \
- !list_entry_is_head(pos, head, member); \
- pos = n, n = list_next_entry(n, member))
-
-/**
- * list_for_each_entry_safe_from - iterate over list from current point safe against removal
- * @param pos the type * to use as a loop cursor.
- * @param n another type * to use as temporary storage
- * @param head the head for your list.
- * @param 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.
- */
-#define list_for_each_entry_safe_from(pos, n, head, member) \
- for (n = list_next_entry(pos, member); \
- !list_entry_is_head(pos, head, member); \
- pos = n, n = list_next_entry(n, member))
-
-/**
- * list_for_each_entry_safe_reverse - iterate backwards over list safe against removal
- * @param pos the type * to use as a loop cursor.
- * @param n another type * to use as temporary storage
- * @param head the head for your list.
- * @param member the name of the list_head within the struct.
- *
- * Iterate backwards over list of given type, safe against removal
- * of list entry.
- */
-#define list_for_each_entry_safe_reverse(pos, n, head, member) \
- for (pos = list_last_entry(head, typeof(*pos), member), \
- n = list_prev_entry(pos, member); \
- !list_entry_is_head(pos, head, member); \
- pos = n, n = list_prev_entry(n, member))
-
-/**
- * list_safe_reset_next - reset a stale list_for_each_entry_safe loop
- * @param pos the loop cursor used in the list_for_each_entry_safe loop
- * @param n temporary storage used in list_for_each_entry_safe
- * @param member the name of the list_head within the struct.
- *
- * list_safe_reset_next is not safe to use in general if the list may be
- * modified concurrently (eg. the lock is dropped in the loop body). An
- * exception to this is if the cursor element (pos) is pinned in the list,
- * and list_safe_reset_next is called after re-taking the lock and before
- * completing the current iteration of the loop body.
- */
-#define list_safe_reset_next(pos, n, member) \
- n = list_next_entry(pos, member)
-
-/*
- * Double linked lists with a single pointer list head.
- * IGNORED
- */
+/* end OpenOCD extensions */
#endif /* OPENOCD_HELPER_LIST_H */