Harald Welte | c175f66 | 2019-05-23 20:30:43 +0200 | [diff] [blame] | 1 | /*! \file linuxlist_atomic.h |
| 2 | * |
| 3 | * Atomic versions of doubly linked list implementation. |
| 4 | */ |
| 5 | |
| 6 | #pragma once |
| 7 | |
| 8 | /*! \defgroup linuxlist Simple doubly linked list implementation |
| 9 | * @{ |
| 10 | * \file linuxlist.h */ |
| 11 | |
| 12 | #include <osmocom/core/linuxlist.h> |
| 13 | |
| 14 | /*! Initialize a llist_head to point back to itself. |
| 15 | * \param[in] ptr llist_head to be initialized. |
| 16 | */ |
| 17 | #define INIT_LLIST_HEAD_AT(ptr) do { \ |
| 18 | CRITICAL_SECTION_ENTER(); \ |
| 19 | (ptr)->next = (ptr); (ptr)->prev = (ptr); \ |
| 20 | CRITICAL_SECTION_LEAVE(); \ |
| 21 | } while (0) |
| 22 | |
| 23 | /*! Add a new entry into a linked list (at head). |
| 24 | * \param _new the entry to be added. |
| 25 | * \param head llist_head to prepend the element to. |
| 26 | * |
| 27 | * Insert a new entry after the specified head. |
| 28 | * This is good for implementing stacks. |
| 29 | */ |
| 30 | static inline void llist_add_at(struct llist_head *_new, struct llist_head *head) |
| 31 | { |
| 32 | CRITICAL_SECTION_ENTER() |
| 33 | __llist_add(_new, head, head->next); |
| 34 | CRITICAL_SECTION_LEAVE() |
| 35 | } |
| 36 | |
| 37 | /*! Add a new entry into a linked list (at tail). |
| 38 | * \param _new the entry to be added. |
| 39 | * \param head llist_head to append the element to. |
| 40 | * |
| 41 | * Insert a new entry before the specified head. |
| 42 | * This is useful for implementing queues. |
| 43 | */ |
| 44 | static inline void llist_add_tail_at(struct llist_head *_new, struct llist_head *head) |
| 45 | { |
| 46 | CRITICAL_SECTION_ENTER() |
| 47 | __llist_add(_new, head->prev, head); |
| 48 | CRITICAL_SECTION_LEAVE() |
| 49 | } |
| 50 | |
| 51 | /*! Delete a single entry from a linked list. |
| 52 | * \param entry the element to delete. |
| 53 | * |
| 54 | * Note: llist_empty on entry does not return true after this, the entry is |
| 55 | * in an undefined state. |
| 56 | */ |
| 57 | static inline void llist_del_at(struct llist_head *entry) |
| 58 | { |
| 59 | CRITICAL_SECTION_ENTER() |
| 60 | __llist_del(entry->prev, entry->next); |
| 61 | entry->next = (struct llist_head *)LLIST_POISON1; |
| 62 | entry->prev = (struct llist_head *)LLIST_POISON2; |
| 63 | CRITICAL_SECTION_LEAVE() |
| 64 | } |
| 65 | |
| 66 | /*! Delete a single entry from a linked list and reinitialize it. |
| 67 | * \param entry the element to delete and reinitialize. |
| 68 | */ |
| 69 | static inline void llist_del_init_at(struct llist_head *entry) |
| 70 | { |
| 71 | CRITICAL_SECTION_ENTER() |
| 72 | __llist_del(entry->prev, entry->next); |
| 73 | INIT_LLIST_HEAD(entry); |
| 74 | CRITICAL_SECTION_LEAVE() |
| 75 | } |
| 76 | |
| 77 | /*! Delete from one llist and add as another's head. |
| 78 | * \param llist the entry to move. |
| 79 | * \param head the head that will precede our entry. |
| 80 | */ |
| 81 | static inline void llist_move_at(struct llist_head *llist, struct llist_head *head) |
| 82 | { |
| 83 | CRITICAL_SECTION_ENTER() |
| 84 | __llist_del(llist->prev, llist->next); |
| 85 | llist_add(llist, head); |
| 86 | CRITICAL_SECTION_LEAVE() |
| 87 | } |
| 88 | |
| 89 | /*! Delete from one llist and add as another's tail. |
| 90 | * \param llist the entry to move. |
| 91 | * \param head the head that will follow our entry. |
| 92 | */ |
| 93 | static inline void llist_move_tail_at(struct llist_head *llist, struct llist_head *head) |
| 94 | { |
| 95 | CRITICAL_SECTION_ENTER() |
| 96 | __llist_del(llist->prev, llist->next); |
| 97 | llist_add_tail(llist, head); |
| 98 | CRITICAL_SECTION_LEAVE() |
| 99 | } |
| 100 | |
| 101 | /*! Join two linked lists. |
| 102 | * \param llist the new linked list to add. |
| 103 | * \param head the place to add llist within the other list. |
| 104 | */ |
| 105 | static inline void llist_splice_at(struct llist_head *llist, struct llist_head *head) |
| 106 | { |
| 107 | CRITICAL_SECTION_ENTER() |
| 108 | if (!llist_empty(llist)) |
| 109 | __llist_splice(llist, head); |
| 110 | CRITICAL_SECTION_LEAVE() |
| 111 | } |
| 112 | |
| 113 | /*! Join two llists and reinitialise the emptied llist. |
| 114 | * \param llist the new linked list to add. |
| 115 | * \param head the place to add it within the first llist. |
| 116 | * |
| 117 | * The llist is reinitialised. |
| 118 | */ |
| 119 | static inline void llist_splice_init_at(struct llist_head *llist, |
| 120 | struct llist_head *head) |
| 121 | { |
| 122 | CRITICAL_SECTION_ENTER() |
| 123 | if (!llist_empty(llist)) { |
| 124 | __llist_splice(llist, head); |
| 125 | INIT_LLIST_HEAD(llist); |
| 126 | } |
| 127 | CRITICAL_SECTION_LEAVE() |
| 128 | } |
| 129 | |
| 130 | /*! Count number of llist items by iterating. |
| 131 | * \param head the llist head to count items of. |
| 132 | * \returns Number of items. |
| 133 | * |
| 134 | * This function is not efficient, mostly useful for small lists and non time |
| 135 | * critical cases like unit tests. |
| 136 | */ |
| 137 | static inline unsigned int llist_count_at(const struct llist_head *head) |
| 138 | { |
| 139 | struct llist_head *entry; |
| 140 | unsigned int i = 0; |
| 141 | CRITICAL_SECTION_ENTER() |
| 142 | llist_for_each(entry, head) |
| 143 | i++; |
| 144 | CRITICAL_SECTION_LEAVE() |
| 145 | return i; |
| 146 | } |
| 147 | |
| 148 | /*! |
| 149 | * @} |
| 150 | */ |