hlist.h 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319
  1. /*
  2. * Copyright (c) 2017 Richard Braun.
  3. *
  4. * This program is free software: you can redistribute it and/or modify
  5. * it under the terms of the GNU General Public License as published by
  6. * the Free Software Foundation, either version 3 of the License, or
  7. * (at your option) any later version.
  8. *
  9. * This program is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License
  15. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  16. *
  17. * Upstream site with license notes :
  18. * http://git.sceen.net/rbraun/librbraun.git/
  19. *
  20. *
  21. * Doubly-linked list specialized for forward traversals and O(1) removals.
  22. */
  23. #ifndef KERN_HLIST_H
  24. #define KERN_HLIST_H
  25. #include <stdbool.h>
  26. #include <stddef.h>
  27. #include <kern/hlist_types.h>
  28. #include <kern/macros.h>
  29. #include <kern/rcu.h>
  30. struct hlist;
  31. struct hlist_node;
  32. // Static list initializer.
  33. #define HLIST_INITIALIZER(list) { NULL }
  34. // Initialize a list.
  35. static inline void
  36. hlist_init (struct hlist *list)
  37. {
  38. list->first = NULL;
  39. }
  40. /*
  41. * Initialize a list node.
  42. *
  43. * A node is in no list when its pprev member points to NULL.
  44. */
  45. static inline void
  46. hlist_node_init (struct hlist_node *node)
  47. {
  48. node->pprev = NULL;
  49. }
  50. // Return true if node is in no list.
  51. static inline bool
  52. hlist_node_unlinked (const struct hlist_node *node)
  53. {
  54. return (!node->pprev);
  55. }
  56. // Return the first node of a list.
  57. static inline struct hlist_node*
  58. hlist_first (const struct hlist *list)
  59. {
  60. return (list->first);
  61. }
  62. // Return the node next to the given node.
  63. static inline struct hlist_node*
  64. hlist_next (const struct hlist_node *node)
  65. {
  66. return (node->next);
  67. }
  68. // Return true if node is invalid and denotes the end of the list.
  69. static inline bool
  70. hlist_end (const struct hlist_node *node)
  71. {
  72. return (!node);
  73. }
  74. // Return true if list is empty.
  75. static inline bool
  76. hlist_empty (const struct hlist *list)
  77. {
  78. return (!list->first);
  79. }
  80. // Return true if list contains exactly one node.
  81. static inline bool
  82. hlist_singular (const struct hlist *list)
  83. {
  84. return (!hlist_empty (list) && hlist_end (list->first->next));
  85. }
  86. /*
  87. * Set the new head of a list.
  88. *
  89. * After completion, old_head is stale.
  90. */
  91. static inline void
  92. hlist_set_head (struct hlist *new_head, const struct hlist *old_head)
  93. {
  94. *new_head = *old_head;
  95. if (!hlist_empty (new_head))
  96. new_head->first->pprev = &new_head->first;
  97. }
  98. // Insert a node at the head of a list.
  99. static inline void
  100. hlist_insert_head (struct hlist *list, struct hlist_node *node)
  101. {
  102. struct hlist_node *first = list->first;
  103. node->next = first;
  104. node->pprev = &list->first;
  105. if (first != NULL)
  106. first->pprev = &node->next;
  107. list->first = node;
  108. }
  109. // Insert a node before another node.
  110. static inline void
  111. hlist_insert_before (struct hlist_node *node, struct hlist_node *next)
  112. {
  113. node->next = next;
  114. node->pprev = next->pprev;
  115. next->pprev = &node->next;
  116. *node->pprev = node;
  117. }
  118. // Insert a node after another node.
  119. static inline void
  120. hlist_insert_after (struct hlist_node *node, struct hlist_node *prev)
  121. {
  122. node->next = prev->next;
  123. node->pprev = &prev->next;
  124. if (node->next != NULL)
  125. node->next->pprev = &node->next;
  126. prev->next = node;
  127. }
  128. // Remove a node from a list.
  129. static inline void
  130. hlist_remove (struct hlist_node *node)
  131. {
  132. if (node->next != NULL)
  133. node->next->pprev = node->pprev;
  134. *node->pprev = node->next;
  135. }
  136. /*
  137. * Macro that evaluates to the address of the structure containing the
  138. * given node based on the given type and member.
  139. */
  140. #define hlist_entry(node, type, member) structof (node, type, member)
  141. // Get the first entry of a list.
  142. #define hlist_first_entry(list, type, member) \
  143. MACRO_BEGIN \
  144. struct hlist_node *first_ = (list)->first; \
  145. hlist_end (first_) ? NULL : hlist_entry (first_, type, member); \
  146. MACRO_END
  147. // Get the entry next to the given entry.
  148. #define hlist_next_entry(entry, member) \
  149. MACRO_BEGIN \
  150. struct hlist_node *next_ = (entry)->member.next; \
  151. hlist_end (next_) ? NULL : hlist_entry (next_, typeof (*entry), member); \
  152. MACRO_END
  153. /*
  154. * Forge a loop to process all nodes of a list.
  155. *
  156. * The node must not be altered during the loop.
  157. */
  158. #define hlist_for_each(list, node) \
  159. for (struct hlist_node *node = hlist_first (list); \
  160. !hlist_end (node); \
  161. node = hlist_next (node))
  162. // Forge a loop to process all nodes of a list.
  163. #define hlist_for_each_safe(list, node, tmp) \
  164. for (struct hlist_node *node = hlist_first (list), \
  165. *tmp = hlist_end (node) ? NULL : hlist_next (node); \
  166. !hlist_end (node); \
  167. node = tmp, \
  168. tmp = hlist_end (node) ? NULL : hlist_next (node))
  169. /*
  170. * Forge a loop to process all entries of a list.
  171. *
  172. * The entry node must not be altered during the loop.
  173. */
  174. #define hlist_for_each_entry(list, entry, member) \
  175. for (entry = hlist_first_entry (list, typeof (*entry), member); \
  176. entry; \
  177. entry = hlist_next_entry (entry, member))
  178. // Forge a loop to process all entries of a list.
  179. #define hlist_for_each_entry_safe(list, entry, tmp, member) \
  180. for (entry = hlist_first_entry (list, typeof (*entry), member), \
  181. tmp = entry ? hlist_next_entry (entry, member) : NULL; \
  182. entry; \
  183. entry = tmp, \
  184. tmp = entry ? hlist_next_entry (entry, member) : NULL) \
  185. /*
  186. * Lockless variants
  187. *
  188. * The hlist_end() function may be used from read-side critical sections.
  189. */
  190. // Return the first node of a list.
  191. static inline struct hlist_node*
  192. hlist_rcu_first (const struct hlist *list)
  193. {
  194. return (rcu_load (&list->first));
  195. }
  196. // Return the node next to the given node.
  197. static inline struct hlist_node*
  198. hlist_rcu_next (const struct hlist_node *node)
  199. {
  200. return (rcu_load (&node->next));
  201. }
  202. // Insert a node at the head of a list.
  203. static inline void
  204. hlist_rcu_insert_head (struct hlist *list, struct hlist_node *node)
  205. {
  206. struct hlist_node *first = list->first;
  207. node->next = first;
  208. node->pprev = &list->first;
  209. if (first)
  210. first->pprev = &node->next;
  211. rcu_store (&list->first, node);
  212. }
  213. // Insert a node before another node.
  214. static inline void
  215. hlist_rcu_insert_before (struct hlist_node *node, struct hlist_node *next)
  216. {
  217. node->next = next;
  218. node->pprev = next->pprev;
  219. next->pprev = &node->next;
  220. rcu_store (node->pprev, node);
  221. }
  222. // Insert a node after another node.
  223. static inline void
  224. hlist_rcu_insert_after (struct hlist_node *node, struct hlist_node *prev)
  225. {
  226. node->next = prev->next;
  227. node->pprev = &prev->next;
  228. if (node->next)
  229. node->next->pprev = &node->next;
  230. rcu_store (&prev->next, node);
  231. }
  232. // Remove a node from a list.
  233. static inline void
  234. hlist_rcu_remove (struct hlist_node *node)
  235. {
  236. if (node->next)
  237. node->next->pprev = node->pprev;
  238. rcu_store (node->pprev, node->next);
  239. }
  240. /*
  241. * Macro that evaluates to the address of the structure containing the
  242. * given node based on the given type and member.
  243. */
  244. #define hlist_rcu_entry(node, type, member) \
  245. structof (rcu_load (&(node)), type, member)
  246. // Get the first entry of a list.
  247. #define hlist_rcu_first_entry(list, type, member) \
  248. MACRO_BEGIN \
  249. struct hlist_node *first_ = hlist_rcu_first (list); \
  250. hlist_end (first_) ? NULL : hlist_entry (first_, type, member); \
  251. MACRO_END
  252. // Get the entry next to the given entry.
  253. #define hlist_rcu_next_entry(entry, member) \
  254. MACRO_BEGIN \
  255. struct hlist_node *next_ = hlist_rcu_next (&entry->member); \
  256. hlist_end (next_) ? NULL : hlist_entry (next_, typeof (*entry), member); \
  257. MACRO_END
  258. // Forge a loop to process all nodes of a list.
  259. #define hlist_rcu_for_each(list, node) \
  260. for (struct hlist_node *node = hlist_rcu_first (list); \
  261. !hlist_end (node); \
  262. node = hlist_rcu_next (node))
  263. // Forge a loop to process all entries of a list.
  264. #define hlist_rcu_for_each_entry(list, entry, member) \
  265. for (entry = hlist_rcu_first_entry (list, typeof (*entry), member); \
  266. entry != NULL; \
  267. entry = hlist_rcu_next_entry (entry, member))
  268. #endif