diff options
author | Antonio Borneo <borneo.antonio@gmail.com> | 2024-03-09 17:53:16 +0100 |
---|---|---|
committer | Antonio Borneo <borneo.antonio@gmail.com> | 2024-03-24 13:41:03 +0000 |
commit | a213afad09e50402be8d02298f48757ff4e2e1cf (patch) | |
tree | e30dbb2b747c8d11d4fa65f171e41b8c41a6e91a /src/helper/list.h | |
parent | 35e4c4616f5a924313e85290f56f84f7a8534801 (diff) | |
download | riscv-openocd-a213afad09e50402be8d02298f48757ff4e2e1cf.zip riscv-openocd-a213afad09e50402be8d02298f48757ff4e2e1cf.tar.gz riscv-openocd-a213afad09e50402be8d02298f48757ff4e2e1cf.tar.bz2 |
helper/list: Replace Linux code with FreeBSD one
The file list.h was originally taken from the Linux kernel code,
thus under license GPL-2.0-only. This locks OpenOCD to follow the
same license, even if the majority of OpenOCD files are licensed
as GPL-2.0-or-later.
A similar file is also present in FreeBSD code base under the more
permissive license BSD-2-Clause.
Drop the code from Linux kernel and replace it with the code from
FreeBSD 13.3.0.
Adapt the code to OpenOCD coding style by fixing the majority of
issues identified by checkpatch.
Add the OpenOCD specific macros and comments.
Unfortunately this causes the lost of all the doxygen comments.
Checkpatch-ignore: MACRO_ARG_REUSE, MACRO_ARG_PRECEDENCE
Change-Id: I6d86752c50158f3174c4e8c4add81e9998d01e0e
Signed-off-by: Antonio Borneo <borneo.antonio@gmail.com>
Reviewed-on: https://review.openocd.org/c/openocd/+/8172
Tested-by: jenkins
Diffstat (limited to 'src/helper/list.h')
-rw-r--r-- | src/helper/list.h | 934 |
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 */ |