/*! \file linuxlist_atomic.h * * Atomic versions of doubly linked list implementation. */ #pragma once /*! \defgroup linuxlist Simple doubly linked list implementation * @{ * \file linuxlist.h */ #include /*! Initialize a llist_head to point back to itself. * \param[in] ptr llist_head to be initialized. */ #define INIT_LLIST_HEAD_AT(ptr) do { \ CRITICAL_SECTION_ENTER(); \ (ptr)->next = (ptr); (ptr)->prev = (ptr); \ CRITICAL_SECTION_LEAVE(); \ } while (0) /*! Add a new entry into a linked list (at head). * \param _new the entry to be added. * \param head llist_head to prepend the element to. * * Insert a new entry after the specified head. * This is good for implementing stacks. */ static inline void llist_add_at(struct llist_head *_new, struct llist_head *head) { CRITICAL_SECTION_ENTER() __llist_add(_new, head, head->next); CRITICAL_SECTION_LEAVE() } /*! Add a new entry into a linked list (at tail). * \param _new the entry to be added. * \param head llist_head to append the element to. * * Insert a new entry before the specified head. * This is useful for implementing queues. */ static inline void llist_add_tail_at(struct llist_head *_new, struct llist_head *head) { CRITICAL_SECTION_ENTER() __llist_add(_new, head->prev, head); CRITICAL_SECTION_LEAVE() } /*! Delete a single entry from a linked list. * \param entry the element to delete. * * Note: llist_empty on entry does not return true after this, the entry is * in an undefined state. */ static inline void llist_del_at(struct llist_head *entry) { CRITICAL_SECTION_ENTER() __llist_del(entry->prev, entry->next); entry->next = (struct llist_head *)LLIST_POISON1; entry->prev = (struct llist_head *)LLIST_POISON2; CRITICAL_SECTION_LEAVE() } /*! Delete a single entry from a linked list and reinitialize it. * \param entry the element to delete and reinitialize. */ static inline void llist_del_init_at(struct llist_head *entry) { CRITICAL_SECTION_ENTER() __llist_del(entry->prev, entry->next); INIT_LLIST_HEAD(entry); CRITICAL_SECTION_LEAVE() } /*! Delete from one llist and add as another's head. * \param llist the entry to move. * \param head the head that will precede our entry. */ static inline void llist_move_at(struct llist_head *llist, struct llist_head *head) { CRITICAL_SECTION_ENTER() __llist_del(llist->prev, llist->next); llist_add(llist, head); CRITICAL_SECTION_LEAVE() } /*! Delete from one llist and add as another's tail. * \param llist the entry to move. * \param head the head that will follow our entry. */ static inline void llist_move_tail_at(struct llist_head *llist, struct llist_head *head) { CRITICAL_SECTION_ENTER() __llist_del(llist->prev, llist->next); llist_add_tail(llist, head); CRITICAL_SECTION_LEAVE() } /*! Join two linked lists. * \param llist the new linked list to add. * \param head the place to add llist within the other list. */ static inline void llist_splice_at(struct llist_head *llist, struct llist_head *head) { CRITICAL_SECTION_ENTER() if (!llist_empty(llist)) __llist_splice(llist, head); CRITICAL_SECTION_LEAVE() } /*! Join two llists and reinitialise the emptied llist. * \param llist the new linked list to add. * \param head the place to add it within the first llist. * * The llist is reinitialised. */ static inline void llist_splice_init_at(struct llist_head *llist, struct llist_head *head) { CRITICAL_SECTION_ENTER() if (!llist_empty(llist)) { __llist_splice(llist, head); INIT_LLIST_HEAD(llist); } CRITICAL_SECTION_LEAVE() } /*! Count number of llist items by iterating. * \param head the llist head to count items of. * \returns Number of items. * * This function is not efficient, mostly useful for small lists and non time * critical cases like unit tests. */ static inline unsigned int llist_count_at(const struct llist_head *head) { struct llist_head *entry; unsigned int i = 0; CRITICAL_SECTION_ENTER() llist_for_each(entry, head) i++; CRITICAL_SECTION_LEAVE() return i; } /*! * @} */