hlist.h 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321
  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. /*
  81. * Return true if list contains exactly one node.
  82. */
  83. static inline bool
  84. hlist_singular (const struct hlist *list)
  85. {
  86. return (!hlist_empty (list) && hlist_end (list->first->next));
  87. }
  88. /*
  89. * Set the new head of a list.
  90. *
  91. * After completion, old_head is stale.
  92. */
  93. static inline void
  94. hlist_set_head (struct hlist *new_head, const struct hlist *old_head)
  95. {
  96. *new_head = *old_head;
  97. if (!hlist_empty (new_head))
  98. new_head->first->pprev = &new_head->first;
  99. }
  100. // Insert a node at the head of a list.
  101. static inline void
  102. hlist_insert_head (struct hlist *list, struct hlist_node *node)
  103. {
  104. struct hlist_node *first = list->first;
  105. node->next = first;
  106. node->pprev = &list->first;
  107. if (first != NULL)
  108. first->pprev = &node->next;
  109. list->first = node;
  110. }
  111. // Insert a node before another node.
  112. static inline void
  113. hlist_insert_before (struct hlist_node *node, struct hlist_node *next)
  114. {
  115. node->next = next;
  116. node->pprev = next->pprev;
  117. next->pprev = &node->next;
  118. *node->pprev = node;
  119. }
  120. // Insert a node after another node.
  121. static inline void
  122. hlist_insert_after (struct hlist_node *node, struct hlist_node *prev)
  123. {
  124. node->next = prev->next;
  125. node->pprev = &prev->next;
  126. if (node->next != NULL)
  127. node->next->pprev = &node->next;
  128. prev->next = node;
  129. }
  130. // Remove a node from a list.
  131. static inline void
  132. hlist_remove (struct hlist_node *node)
  133. {
  134. if (node->next != NULL)
  135. node->next->pprev = node->pprev;
  136. *node->pprev = node->next;
  137. }
  138. /*
  139. * Macro that evaluates to the address of the structure containing the
  140. * given node based on the given type and member.
  141. */
  142. #define hlist_entry(node, type, member) structof (node, type, member)
  143. // Get the first entry of a list.
  144. #define hlist_first_entry(list, type, member) \
  145. MACRO_BEGIN \
  146. struct hlist_node *first_ = (list)->first; \
  147. hlist_end (first_) ? NULL : hlist_entry (first_, type, member); \
  148. MACRO_END
  149. // Get the entry next to the given entry.
  150. #define hlist_next_entry(entry, member) \
  151. MACRO_BEGIN \
  152. struct hlist_node *next_ = (entry)->member.next; \
  153. hlist_end (next_) ? NULL : hlist_entry (next_, typeof (*entry), member); \
  154. MACRO_END
  155. /*
  156. * Forge a loop to process all nodes of a list.
  157. *
  158. * The node must not be altered during the loop.
  159. */
  160. #define hlist_for_each(list, node) \
  161. for (struct hlist_node *node = hlist_first (list); \
  162. !hlist_end (node); \
  163. node = hlist_next (node))
  164. // Forge a loop to process all nodes of a list.
  165. #define hlist_for_each_safe(list, node, tmp) \
  166. for (struct hlist_node *node = hlist_first (list), \
  167. *tmp = hlist_end (node) ? NULL : hlist_next (node); \
  168. !hlist_end (node); \
  169. node = tmp, \
  170. tmp = hlist_end (node) ? NULL : hlist_next (node))
  171. /*
  172. * Forge a loop to process all entries of a list.
  173. *
  174. * The entry node must not be altered during the loop.
  175. */
  176. #define hlist_for_each_entry(list, entry, member) \
  177. for (entry = hlist_first_entry (list, typeof (*entry), member); \
  178. entry; \
  179. entry = hlist_next_entry (entry, member))
  180. // Forge a loop to process all entries of a list.
  181. #define hlist_for_each_entry_safe(list, entry, tmp, member) \
  182. for (entry = hlist_first_entry (list, typeof (*entry), member), \
  183. tmp = entry ? hlist_next_entry (entry, member) : NULL; \
  184. entry; \
  185. entry = tmp, \
  186. tmp = entry ? hlist_next_entry (entry, member) : NULL) \
  187. /*
  188. * Lockless variants
  189. *
  190. * The hlist_end() function may be used from read-side critical sections.
  191. */
  192. // Return the first node of a list.
  193. static inline struct hlist_node*
  194. hlist_rcu_first (const struct hlist *list)
  195. {
  196. return (rcu_load (&list->first));
  197. }
  198. // Return the node next to the given node.
  199. static inline struct hlist_node*
  200. hlist_rcu_next (const struct hlist_node *node)
  201. {
  202. return (rcu_load (&node->next));
  203. }
  204. // Insert a node at the head of a list.
  205. static inline void
  206. hlist_rcu_insert_head (struct hlist *list, struct hlist_node *node)
  207. {
  208. struct hlist_node *first = list->first;
  209. node->next = first;
  210. node->pprev = &list->first;
  211. if (first)
  212. first->pprev = &node->next;
  213. rcu_store (&list->first, node);
  214. }
  215. // Insert a node before another node.
  216. static inline void
  217. hlist_rcu_insert_before (struct hlist_node *node, struct hlist_node *next)
  218. {
  219. node->next = next;
  220. node->pprev = next->pprev;
  221. next->pprev = &node->next;
  222. rcu_store (node->pprev, node);
  223. }
  224. // Insert a node after another node.
  225. static inline void
  226. hlist_rcu_insert_after (struct hlist_node *node, struct hlist_node *prev)
  227. {
  228. node->next = prev->next;
  229. node->pprev = &prev->next;
  230. if (node->next)
  231. node->next->pprev = &node->next;
  232. rcu_store (&prev->next, node);
  233. }
  234. // Remove a node from a list.
  235. static inline void
  236. hlist_rcu_remove (struct hlist_node *node)
  237. {
  238. if (node->next)
  239. node->next->pprev = node->pprev;
  240. rcu_store (node->pprev, node->next);
  241. }
  242. /*
  243. * Macro that evaluates to the address of the structure containing the
  244. * given node based on the given type and member.
  245. */
  246. #define hlist_rcu_entry(node, type, member) \
  247. structof (rcu_load (&(node)), type, member)
  248. // Get the first entry of a list.
  249. #define hlist_rcu_first_entry(list, type, member) \
  250. MACRO_BEGIN \
  251. struct hlist_node *first_ = hlist_rcu_first (list); \
  252. hlist_end (first_) ? NULL : hlist_entry (first_, type, member); \
  253. MACRO_END
  254. // Get the entry next to the given entry.
  255. #define hlist_rcu_next_entry(entry, member) \
  256. MACRO_BEGIN \
  257. struct hlist_node *next_ = hlist_rcu_next (&entry->member); \
  258. hlist_end (next_) ? NULL : hlist_entry (next_, typeof (*entry), member); \
  259. MACRO_END
  260. // Forge a loop to process all nodes of a list.
  261. #define hlist_rcu_for_each(list, node) \
  262. for (struct hlist_node *node = hlist_rcu_first (list); \
  263. !hlist_end (node); \
  264. node = hlist_rcu_next (node))
  265. // Forge a loop to process all entries of a list.
  266. #define hlist_rcu_for_each_entry(list, entry, member) \
  267. for (entry = hlist_rcu_first_entry (list, typeof (*entry), member); \
  268. entry != NULL; \
  269. entry = hlist_rcu_next_entry (entry, member))
  270. #endif