blob: 8e0a5f073b69894ce6d848a05c25023c07ead119 [file] [log] [blame]
Harald Weltec175f662019-05-23 20:30:43 +02001/*! \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 */
30static 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 */
44static 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 */
57static 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 */
69static 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 */
81static 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 */
93static 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 */
105static 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 */
119static 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 */
137static 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 */