diff options
Diffstat (limited to 'roms/ipxe/src/include/ipxe/list.h')
-rw-r--r-- | roms/ipxe/src/include/ipxe/list.h | 476 |
1 files changed, 476 insertions, 0 deletions
diff --git a/roms/ipxe/src/include/ipxe/list.h b/roms/ipxe/src/include/ipxe/list.h new file mode 100644 index 00000000..581ec980 --- /dev/null +++ b/roms/ipxe/src/include/ipxe/list.h @@ -0,0 +1,476 @@ +#ifndef _IPXE_LIST_H +#define _IPXE_LIST_H + +/** @file + * + * Linked lists + * + * This linked list handling code is based on the Linux kernel's + * list.h. + */ + +FILE_LICENCE ( GPL2_ONLY ); + +#include <stddef.h> +#include <assert.h> + +/** A doubly-linked list entry (or list head) */ +struct list_head { + /** Next list entry */ + struct list_head *next; + /** Previous list entry */ + struct list_head *prev; +}; + +/** + * Initialise a static list head + * + * @v list List head + */ +#define LIST_HEAD_INIT( list ) { &(list), &(list) } + +/** + * Declare a static list head + * + * @v list List head + */ +#define LIST_HEAD( list ) \ + struct list_head list = LIST_HEAD_INIT ( list ) + +/** + * Initialise a list head + * + * @v list List head + */ +#define INIT_LIST_HEAD( list ) do { \ + (list)->next = (list); \ + (list)->prev = (list); \ + } while ( 0 ) + +/** + * Check a list entry or list head is valid + * + * @v list List entry or head + */ +#define list_check( list ) ( { \ + assert ( (list) != NULL ); \ + assert ( (list)->prev != NULL ); \ + assert ( (list)->next != NULL ); \ + assert ( (list)->next->prev == (list) ); \ + assert ( (list)->prev->next == (list) ); \ + } ) + +/** + * Add a new entry to the head of a list + * + * @v new New entry to be added + * @v head List head, or entry after which to add the new entry + */ +#define list_add( new, head ) do { \ + list_check ( (head) ); \ + extern_list_add ( (new), (head) ); \ + list_check ( (head) ); \ + list_check ( (new) ); \ + } while ( 0 ) +static inline void inline_list_add ( struct list_head *new, + struct list_head *head ) { + struct list_head *prev = head; + struct list_head *next = head->next; + next->prev = (new); + (new)->next = next; + (new)->prev = prev; + prev->next = (new); +} +extern void extern_list_add ( struct list_head *new, + struct list_head *head ); + +/** + * Add a new entry to the tail of a list + * + * @v new New entry to be added + * @v head List head, or entry before which to add the new entry + */ +#define list_add_tail( new, head ) do { \ + list_check ( (head) ); \ + extern_list_add_tail ( (new), (head) ); \ + list_check ( (head) ); \ + list_check ( (new) ); \ + } while ( 0 ) +static inline void inline_list_add_tail ( struct list_head *new, + struct list_head *head ) { + struct list_head *prev = head->prev; + struct list_head *next = head; + next->prev = (new); + (new)->next = next; + (new)->prev = prev; + prev->next = (new); +} +extern void extern_list_add_tail ( struct list_head *new, + struct list_head *head ); + +/** + * Delete an entry from a list + * + * @v list List entry + * + * Note that list_empty() on entry does not return true after this; + * the entry is in an undefined state. + */ +#define list_del( list ) do { \ + list_check ( (list) ); \ + inline_list_del ( (list) ); \ + } while ( 0 ) +static inline void inline_list_del ( struct list_head *list ) { + struct list_head *next = (list)->next; + struct list_head *prev = (list)->prev; + next->prev = prev; + prev->next = next; +} +extern void extern_list_del ( struct list_head *list ); + +/** + * Test whether a list is empty + * + * @v list List head + */ +#define list_empty( list ) ( { \ + list_check ( (list) ); \ + inline_list_empty ( (list) ); } ) +static inline int inline_list_empty ( const struct list_head *list ) { + return ( list->next == list ); +} +extern int extern_list_empty ( const struct list_head *list ); + +/** + * Test whether a list has just one entry + * + * @v list List to test + */ +#define list_is_singular( list ) ( { \ + list_check ( (list) ); \ + inline_list_is_singular ( (list) ); } ) +static inline int inline_list_is_singular ( const struct list_head *list ) { + return ( ( ! list_empty ( list ) ) && ( list->next == list->prev ) ); +} +extern int extern_list_is_singular ( const struct list_head *list ); + +/** + * Test whether an entry is the last entry in list + * + * @v list List entry to test + * @v head List head + */ +#define list_is_last( list, head ) ( { \ + list_check ( (list) ); \ + list_check ( (head) ); \ + inline_list_is_last ( (list), (head) ); } ) +static inline int inline_list_is_last ( const struct list_head *list, + const struct list_head *head ) { + return ( list->next == head ); +} +extern int extern_list_is_last ( const struct list_head *list, + const struct list_head *head ); + +/** + * Cut a list into two + * + * @v new A new list to contain all removed entries + * @v list An existing list + * @v entry An entry within the existing list + * + * All entries from @c list up to and including @c entry are moved to + * @c new, which should be an empty list. @c entry may be equal to @c + * list, in which case no entries are moved. + */ +#define list_cut_position( new, list, entry ) do { \ + list_check ( (new) ); \ + assert ( list_empty ( (new) ) ); \ + list_check ( (list) ); \ + list_check ( (entry) ); \ + extern_list_cut_position ( (new), (list), (entry) ); \ + } while ( 0 ) +static inline void inline_list_cut_position ( struct list_head *new, + struct list_head *list, + struct list_head *entry ) { + struct list_head *first = entry->next; + + if ( list != entry ) { + new->next = list->next; + new->next->prev = new; + new->prev = entry; + new->prev->next = new; + list->next = first; + list->next->prev = list; + } +} +extern void extern_list_cut_position ( struct list_head *new, + struct list_head *list, + struct list_head *entry ); + +/** + * Move all entries from one list into another list + * + * @v list List of entries to add + * @v entry Entry after which to add the new entries + * + * All entries from @c list are inserted after @c entry. Note that @c + * list is left in an undefined state; use @c list_splice_init() if + * you want @c list to become an empty list. + */ +#define list_splice( list, entry ) do { \ + list_check ( (list) ); \ + list_check ( (entry) ); \ + extern_list_splice ( (list), (entry) ); \ + } while ( 0 ) +static inline void inline_list_splice ( const struct list_head *list, + struct list_head *entry ) { + struct list_head *first = list->next; + struct list_head *last = list->prev; + + if ( ! list_empty ( list ) ) { + last->next = entry->next; + last->next->prev = last; + first->prev = entry; + first->prev->next = first; + } +} +extern void extern_list_splice ( const struct list_head *list, + struct list_head *entry ); + +/** + * Move all entries from one list into another list + * + * @v list List of entries to add + * @v entry Entry before which to add the new entries + * + * All entries from @c list are inserted before @c entry. Note that @c + * list is left in an undefined state; use @c list_splice_tail_init() if + * you want @c list to become an empty list. + */ +#define list_splice_tail( list, entry ) do { \ + list_check ( (list) ); \ + list_check ( (entry) ); \ + extern_list_splice_tail ( (list), (entry) ); \ + } while ( 0 ) +static inline void inline_list_splice_tail ( const struct list_head *list, + struct list_head *entry ) { + struct list_head *first = list->next; + struct list_head *last = list->prev; + + if ( ! list_empty ( list ) ) { + first->prev = entry->prev; + first->prev->next = first; + last->next = entry; + last->next->prev = last; + } +} +extern void extern_list_splice_tail ( const struct list_head *list, + struct list_head *entry ); + +/** + * Move all entries from one list into another list and reinitialise empty list + * + * @v list List of entries to add + * @v entry Entry after which to add the new entries + * + * All entries from @c list are inserted after @c entry. + */ +#define list_splice_init( list, entry ) do { \ + list_check ( (list) ); \ + list_check ( (entry) ); \ + extern_list_splice_init ( (list), (entry) ); \ + } while ( 0 ) +static inline void inline_list_splice_init ( struct list_head *list, + struct list_head *entry ) { + list_splice ( list, entry ); + INIT_LIST_HEAD ( list ); +} +extern void extern_list_splice_init ( struct list_head *list, + struct list_head *entry ); + +/** + * Move all entries from one list into another list and reinitialise empty list + * + * @v list List of entries to add + * @v entry Entry before which to add the new entries + * + * All entries from @c list are inserted before @c entry. + */ +#define list_splice_tail_init( list, entry ) do { \ + list_check ( (list) ); \ + list_check ( (entry) ); \ + extern_list_splice_tail_init ( (list), (entry) ); \ + } while ( 0 ) + +static inline void inline_list_splice_tail_init ( struct list_head *list, + struct list_head *entry ) { + list_splice_tail ( list, entry ); + INIT_LIST_HEAD ( list ); +} +extern void extern_list_splice_tail_init ( struct list_head *list, + struct list_head *entry ); + +/** + * Get the container of a list entry + * + * @v list List entry + * @v type Containing type + * @v member Name of list field within containing type + * @ret container Containing object + */ +#define list_entry( list, type, member ) ( { \ + list_check ( (list) ); \ + container_of ( list, type, member ); } ) + +/** + * Get the container of the first entry in a list + * + * @v list List head + * @v type Containing type + * @v member Name of list field within containing type + * @ret first First list entry, or NULL + */ +#define list_first_entry( list, type, member ) \ + ( list_empty ( (list) ) ? \ + ( type * ) NULL : \ + list_entry ( (list)->next, type, member ) ) + +/** + * Get the container of the last entry in a list + * + * @v list List head + * @v type Containing type + * @v member Name of list field within containing type + * @ret first First list entry, or NULL + */ +#define list_last_entry( list, type, member ) \ + ( list_empty ( (list) ) ? \ + ( type * ) NULL : \ + list_entry ( (list)->prev, type, member ) ) + +/** + * Iterate over a list + * + * @v pos Iterator + * @v head List head + */ +#define list_for_each( pos, head ) \ + for ( list_check ( (head) ), \ + pos = (head)->next; \ + pos != (head); \ + pos = (pos)->next ) + +/** + * Iterate over entries in a list + * + * @v pos Iterator + * @v head List head + * @v member Name of list field within iterator's type + */ +#define list_for_each_entry( pos, head, member ) \ + for ( list_check ( (head) ), \ + pos = list_entry ( (head)->next, typeof ( *pos ), member ); \ + &pos->member != (head); \ + pos = list_entry ( pos->member.next, typeof ( *pos ), member ) ) + +/** + * Iterate over entries in a list in reverse order + * + * @v pos Iterator + * @v head List head + * @v member Name of list field within iterator's type + */ +#define list_for_each_entry_reverse( pos, head, member ) \ + for ( list_check ( (head) ), \ + pos = list_entry ( (head)->prev, typeof ( *pos ), member ); \ + &pos->member != (head); \ + pos = list_entry ( pos->member.prev, typeof ( *pos ), member ) ) + +/** + * Iterate over entries in a list, safe against deletion of the current entry + * + * @v pos Iterator + * @v tmp Temporary value (of same type as iterator) + * @v head List head + * @v member Name of list field within iterator's type + */ +#define list_for_each_entry_safe( pos, tmp, head, member ) \ + for ( list_check ( (head) ), \ + pos = list_entry ( (head)->next, typeof ( *pos ), member ), \ + tmp = list_entry ( pos->member.next, typeof ( *tmp ), member ); \ + &pos->member != (head); \ + pos = tmp, \ + tmp = list_entry ( tmp->member.next, typeof ( *tmp ), member ) ) + +/** + * Iterate over entries in a list, starting after current position + * + * @v pos Iterator + * @v head List head + * @v member Name of list field within iterator's type + */ +#define list_for_each_entry_continue( pos, head, member ) \ + for ( list_check ( (head) ), \ + pos = list_entry ( pos->member.next, typeof ( *pos ), member ); \ + &pos->member != (head); \ + pos = list_entry ( pos->member.next, typeof ( *pos ), member ) ) + +/** + * Iterate over entries in a list in reverse, starting after current position + * + * @v pos Iterator + * @v head List head + * @v member Name of list field within iterator's type + */ +#define list_for_each_entry_continue_reverse( pos, head, member ) \ + for ( list_check ( (head) ), \ + pos = list_entry ( pos->member.prev, typeof ( *pos ), member ); \ + &pos->member != (head); \ + pos = list_entry ( pos->member.prev, typeof ( *pos ), member ) ) + +/** + * Test if list contains a specified entry + * + * @v entry Entry + * @v head List head + * @ret present List contains specified entry + */ +#define list_contains( entry, head ) ( { \ + list_check ( (head) ); \ + list_check ( (entry) ); \ + extern_list_contains ( (entry), (head) ); } ) +static inline int inline_list_contains ( struct list_head *entry, + struct list_head *head ) { + struct list_head *tmp; + + list_for_each ( tmp, head ) { + if ( tmp == entry ) + return 1; + } + return 0; +} +extern int extern_list_contains ( struct list_head *entry, + struct list_head *head ); + +/** + * Test if list contains a specified entry + * + * @v entry Entry + * @v head List head + * @ret present List contains specified entry + */ +#define list_contains_entry( entry, head, member ) \ + list_contains ( &(entry)->member, (head) ) + +/** + * Check list contains a specified entry + * + * @v entry Entry + * @v head List head + * @v member Name of list field within iterator's type + */ +#define list_check_contains_entry( entry, head, member ) do { \ + assert ( list_contains_entry ( (entry), (head), member ) ); \ + } while ( 0 ) + +#endif /* _IPXE_LIST_H */ |