151 lines
4.0 KiB
C
151 lines
4.0 KiB
C
/*! \file linuxlist_atomic.h
|
|
*
|
|
* Atomic versions of doubly linked list implementation.
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
/*! \defgroup linuxlist Simple doubly linked list implementation
|
|
* @{
|
|
* \file linuxlist.h */
|
|
|
|
#include <osmocom/core/linuxlist.h>
|
|
|
|
/*! 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;
|
|
}
|
|
|
|
/*!
|
|
* @}
|
|
*/
|