PageRenderTime 26ms CodeModel.GetById 20ms RepoModel.GetById 1ms app.codeStats 0ms

/include/ntp_lists.h

https://gitlab.com/micromax/ntpsec
C Header | 443 lines | 282 code | 35 blank | 126 comment | 76 complexity | bbfc84774bc746cd7b71ec72224cde5d MD5 | raw file
  1. /*
  2. * ntp_lists.h - linked lists common code
  3. *
  4. * SLIST: singly-linked lists
  5. * ==========================
  6. *
  7. * These macros implement a simple singly-linked list template. Both
  8. * the listhead and per-entry next fields are declared as pointers to
  9. * the list entry struct type. Initialization to NULL is typically
  10. * implicit (for globals and statics) or handled by zeroing of the
  11. * containing structure.
  12. *
  13. * The name of the next link field is passed as an argument to allow
  14. * membership in several lists at once using multiple next link fields.
  15. *
  16. * When possible, placing the link field first in the entry structure
  17. * allows slightly smaller code to be generated on some platforms.
  18. *
  19. * LINK_SLIST(listhead, pentry, nextlink)
  20. * add entry at head
  21. *
  22. * LINK_TAIL_SLIST(listhead, pentry, nextlink, entrytype)
  23. * add entry at tail. This is O(n), if this is a common
  24. * operation the FIFO template may be more appropriate.
  25. *
  26. * LINK_SORT_SLIST(listhead, pentry, beforecur, nextlink, entrytype)
  27. * add entry in sorted order. beforecur is an expression comparing
  28. * pentry with the current list entry. The current entry can be
  29. * referenced within beforecur as L_S_S_CUR(), which is short for
  30. * LINK_SORT_SLIST_CUR(). beforecur is nonzero if pentry sorts
  31. * before L_S_S_CUR().
  32. *
  33. * UNLINK_HEAD_SLIST(punlinked, listhead, nextlink)
  34. * unlink first entry and point punlinked to it, or set punlinked
  35. * to NULL if the list is empty.
  36. *
  37. * UNLINK_SLIST(punlinked, listhead, ptounlink, nextlink, entrytype)
  38. * unlink entry pointed to by ptounlink. punlinked is set to NULL
  39. * if the entry is not found on the list, otherwise it is set to
  40. * ptounlink.
  41. *
  42. * UNLINK_EXPR_SLIST(punlinked, listhead, expr, nextlink, entrytype)
  43. * unlink entry where expression expr is nonzero. expr can refer
  44. * to the entry being tested using UNLINK_EXPR_SLIST_CURRENT(),
  45. * alias U_E_S_CUR(). See the implementation of UNLINK_SLIST()
  46. * below for an example. U_E_S_CUR() is NULL iff the list is empty.
  47. * punlinked is pointed to the removed entry or NULL if none
  48. * satisfy expr.
  49. *
  50. * FIFO: singly-linked lists plus tail pointer
  51. * ===========================================
  52. *
  53. * This is the same as FreeBSD's sys/queue.h STAILQ -- a singly-linked
  54. * list implementation with tail-pointer maintenance, so that adding
  55. * at the tail for first-in, first-out access is O(1).
  56. *
  57. * DECL_FIFO_ANCHOR(entrytype)
  58. * provides the type specification portion of the declaration for
  59. * a variable to refer to a FIFO queue (similar to listhead). The
  60. * anchor contains the head and indirect tail pointers. Example:
  61. *
  62. * #include "ntp_lists.h"
  63. *
  64. * typedef struct myentry_tag myentry;
  65. * struct myentry_tag {
  66. * myentry *next_link;
  67. * ...
  68. * };
  69. *
  70. * DECL_FIFO_ANCHOR(myentry) my_fifo;
  71. *
  72. * void somefunc(myentry *pentry)
  73. * {
  74. * LINK_FIFO(my_fifo, pentry, next_link);
  75. * }
  76. *
  77. * If DECL_FIFO_ANCHOR is used with stack or heap storage, it
  78. * should be initialized to NULL pointers using a = { NULL };
  79. * initializer or memset.
  80. *
  81. * HEAD_FIFO(anchor)
  82. * TAIL_FIFO(anchor)
  83. * Pointer to first/last entry, NULL if FIFO is empty.
  84. *
  85. * LINK_FIFO(anchor, pentry, nextlink)
  86. * add entry at tail.
  87. *
  88. * UNLINK_FIFO(punlinked, anchor, nextlink)
  89. * unlink head entry and point punlinked to it, or set punlinked
  90. * to NULL if the list is empty.
  91. *
  92. * CONCAT_FIFO(q1, q2, nextlink)
  93. * empty fifoq q2 moving its nodes to q1 following q1's existing
  94. * nodes.
  95. *
  96. * DLIST: doubly-linked lists
  97. * ==========================
  98. *
  99. * Elements on DLISTs always have non-NULL forward and back links,
  100. * because both link chains are circular. The beginning/end is marked
  101. * by the listhead, which is the same type as elements for simplicity.
  102. * An empty list's listhead has both links set to its own address.
  103. *
  104. *
  105. */
  106. #ifndef GUARD_NTP_LISTS_H
  107. #define GUARD_NTP_LISTS_H
  108. #include "ntp_types.h" /* true and false */
  109. #include "ntp_assert.h"
  110. #ifdef DEBUG
  111. # define NTP_DEBUG_LISTS
  112. #endif
  113. /*
  114. * If list debugging is not enabled, save a little time by not clearing
  115. * an entry's link pointer when it is unlinked, as the stale pointer
  116. * is harmless as long as it is ignored when the entry is not in a
  117. * list.
  118. */
  119. #ifndef NTP_DEBUG_LISTS
  120. #define MAYBE_Z_LISTS(p) do { } while (false)
  121. #else
  122. #define MAYBE_Z_LISTS(p) (p) = NULL
  123. #endif
  124. #define LINK_SLIST(listhead, pentry, nextlink) \
  125. do { \
  126. (pentry)->nextlink = (listhead); \
  127. (listhead) = (pentry); \
  128. } while (false)
  129. #define LINK_TAIL_SLIST(listhead, pentry, nextlink, entrytype) \
  130. do { \
  131. entrytype **pptail; \
  132. \
  133. pptail = &(listhead); \
  134. while (*pptail != NULL) \
  135. pptail = &((*pptail)->nextlink); \
  136. \
  137. (pentry)->nextlink = NULL; \
  138. *pptail = (pentry); \
  139. } while (false)
  140. #define LINK_SORT_SLIST_CURRENT() (*ppentry)
  141. #define L_S_S_CUR() LINK_SORT_SLIST_CURRENT()
  142. #define LINK_SORT_SLIST(listhead, pentry, beforecur, nextlink, \
  143. entrytype) \
  144. do { \
  145. entrytype **ppentry; \
  146. \
  147. ppentry = &(listhead); \
  148. while (true) { \
  149. if (NULL == *ppentry || (beforecur)) { \
  150. (pentry)->nextlink = *ppentry; \
  151. *ppentry = (pentry); \
  152. break; \
  153. } \
  154. ppentry = &((*ppentry)->nextlink); \
  155. if (NULL == *ppentry) { \
  156. (pentry)->nextlink = NULL; \
  157. *ppentry = (pentry); \
  158. break; \
  159. } \
  160. } \
  161. } while (false)
  162. #define UNLINK_HEAD_SLIST(punlinked, listhead, nextlink) \
  163. do { \
  164. (punlinked) = (listhead); \
  165. if (NULL != (punlinked)) { \
  166. (listhead) = (punlinked)->nextlink; \
  167. MAYBE_Z_LISTS((punlinked)->nextlink); \
  168. } \
  169. } while (false)
  170. #define UNLINK_EXPR_SLIST_CURRENT() (*ppentry)
  171. #define U_E_S_CUR() UNLINK_EXPR_SLIST_CURRENT()
  172. #define UNLINK_EXPR_SLIST(punlinked, listhead, expr, nextlink, \
  173. entrytype) \
  174. do { \
  175. entrytype **ppentry; \
  176. \
  177. ppentry = &(listhead); \
  178. \
  179. while (!(expr)) \
  180. if (*ppentry != NULL && \
  181. (*ppentry)->nextlink != NULL) { \
  182. ppentry = &((*ppentry)->nextlink); \
  183. } else { \
  184. ppentry = NULL; \
  185. break; \
  186. } \
  187. \
  188. if (ppentry != NULL) { \
  189. (punlinked) = *ppentry; \
  190. *ppentry = (punlinked)->nextlink; \
  191. MAYBE_Z_LISTS((punlinked)->nextlink); \
  192. } else { \
  193. (punlinked) = NULL; \
  194. } \
  195. } while (false)
  196. #define UNLINK_SLIST(punlinked, listhead, ptounlink, nextlink, \
  197. entrytype) \
  198. UNLINK_EXPR_SLIST(punlinked, listhead, (ptounlink) == \
  199. U_E_S_CUR(), nextlink, entrytype)
  200. #define CHECK_SLIST(listhead, nextlink, entrytype) \
  201. do { \
  202. entrytype *pentry; \
  203. \
  204. for (pentry = (listhead); \
  205. pentry != NULL; \
  206. pentry = pentry->nextlink){ \
  207. NTP_INSIST(pentry != pentry->nextlink); \
  208. NTP_INSIST((listhead) != pentry->nextlink); \
  209. } \
  210. } while (false)
  211. /*
  212. * FIFO
  213. */
  214. #define DECL_FIFO_ANCHOR(entrytype) \
  215. struct { \
  216. entrytype * phead; /* NULL if list empty */ \
  217. entrytype ** pptail; /* NULL if list empty */ \
  218. }
  219. #define HEAD_FIFO(anchor) ((anchor).phead)
  220. #define TAIL_FIFO(anchor) ((NULL == (anchor).pptail) \
  221. ? NULL \
  222. : *((anchor).pptail))
  223. /*
  224. * For DEBUG builds only, verify both or neither of the anchor pointers
  225. * are NULL with each operation.
  226. */
  227. #if !defined(NTP_DEBUG_LISTS)
  228. #define CHECK_FIFO_CONSISTENCY(anchor) do { } while (false)
  229. #else
  230. #define CHECK_FIFO_CONSISTENCY(anchor) \
  231. check_gen_fifo_consistency(&(anchor))
  232. void check_gen_fifo_consistency(void *fifo);
  233. #endif
  234. /*
  235. * generic FIFO element used to access any FIFO where each element
  236. * begins with the link pointer
  237. */
  238. typedef struct gen_node_tag gen_node;
  239. struct gen_node_tag {
  240. gen_node * link;
  241. };
  242. /* generic FIFO */
  243. typedef DECL_FIFO_ANCHOR(gen_node) gen_fifo;
  244. #define LINK_FIFO(anchor, pentry, nextlink) \
  245. do { \
  246. CHECK_FIFO_CONSISTENCY(anchor); \
  247. \
  248. (pentry)->nextlink = NULL; \
  249. if (NULL != (anchor).pptail) { \
  250. (*((anchor).pptail))->nextlink = (pentry); \
  251. (anchor).pptail = \
  252. &(*((anchor).pptail))->nextlink; \
  253. } else { \
  254. (anchor).phead = (pentry); \
  255. (anchor).pptail = &(anchor).phead; \
  256. } \
  257. \
  258. CHECK_FIFO_CONSISTENCY(anchor); \
  259. } while (false)
  260. #define UNLINK_FIFO(punlinked, anchor, nextlink) \
  261. do { \
  262. CHECK_FIFO_CONSISTENCY(anchor); \
  263. \
  264. (punlinked) = (anchor).phead; \
  265. if (NULL != (punlinked)) { \
  266. (anchor).phead = (punlinked)->nextlink; \
  267. if (NULL == (anchor).phead) \
  268. (anchor).pptail = NULL; \
  269. else if ((anchor).pptail == \
  270. &(punlinked)->nextlink) \
  271. (anchor).pptail = &(anchor).phead; \
  272. MAYBE_Z_LISTS((punlinked)->nextlink); \
  273. CHECK_FIFO_CONSISTENCY(anchor); \
  274. } \
  275. } while (false)
  276. #define UNLINK_MID_FIFO(punlinked, anchor, tounlink, nextlink, \
  277. entrytype) \
  278. do { \
  279. entrytype **ppentry; \
  280. \
  281. CHECK_FIFO_CONSISTENCY(anchor); \
  282. \
  283. ppentry = &(anchor).phead; \
  284. \
  285. while ((tounlink) != *ppentry) \
  286. if ((*ppentry)->nextlink != NULL) { \
  287. ppentry = &((*ppentry)->nextlink); \
  288. } else { \
  289. ppentry = NULL; \
  290. break; \
  291. } \
  292. \
  293. if (ppentry != NULL) { \
  294. (punlinked) = *ppentry; \
  295. *ppentry = (punlinked)->nextlink; \
  296. if (NULL == *ppentry) \
  297. (anchor).pptail = NULL; \
  298. else if ((anchor).pptail == \
  299. &(punlinked)->nextlink) \
  300. (anchor).pptail = &(anchor).phead; \
  301. MAYBE_Z_LISTS((punlinked)->nextlink); \
  302. CHECK_FIFO_CONSISTENCY(anchor); \
  303. } else { \
  304. (punlinked) = NULL; \
  305. } \
  306. } while (false)
  307. #define CONCAT_FIFO(f1, f2, nextlink) \
  308. do { \
  309. CHECK_FIFO_CONSISTENCY(f1); \
  310. CHECK_FIFO_CONSISTENCY(f2); \
  311. \
  312. if ((f2).pptail != NULL) { \
  313. if ((f1).pptail != NULL) { \
  314. (*(f1).pptail)->nextlink = (f2).phead; \
  315. if ((f2).pptail == &(f2).phead) \
  316. (f1).pptail = \
  317. &(*(f1).pptail)->nextlink; \
  318. else \
  319. (f1).pptail = (f2).pptail; \
  320. CHECK_FIFO_CONSISTENCY(f1); \
  321. } else { \
  322. (f1) = (f2); \
  323. } \
  324. MAYBE_Z_LISTS((f2).phead); \
  325. MAYBE_Z_LISTS((f2).pptail); \
  326. } \
  327. } while (false)
  328. /*
  329. * DLIST
  330. */
  331. #define DECL_DLIST_LINK(entrytype, link) \
  332. struct { \
  333. entrytype * b; \
  334. entrytype * f; \
  335. } link
  336. #define INIT_DLIST(listhead, link) \
  337. do { \
  338. (listhead).link.f = &(listhead); \
  339. (listhead).link.b = &(listhead); \
  340. } while (false)
  341. #define HEAD_DLIST(listhead, link) \
  342. ( \
  343. (&(listhead) != (listhead).link.f) \
  344. ? (listhead).link.f \
  345. : NULL \
  346. )
  347. #define TAIL_DLIST(listhead, link) \
  348. ( \
  349. (&(listhead) != (listhead).link.b) \
  350. ? (listhead).link.b \
  351. : NULL \
  352. )
  353. #define NEXT_DLIST(listhead, entry, link) \
  354. ( \
  355. (&(listhead) != (entry)->link.f) \
  356. ? (entry)->link.f \
  357. : NULL \
  358. )
  359. #define PREV_DLIST(listhead, entry, link) \
  360. ( \
  361. (&(listhead) != (entry)->link.b) \
  362. ? (entry)->link.b \
  363. : NULL \
  364. )
  365. #define LINK_DLIST(listhead, pentry, link) \
  366. do { \
  367. (pentry)->link.f = (listhead).link.f; \
  368. (pentry)->link.b = &(listhead); \
  369. (listhead).link.f->link.b = (pentry); \
  370. (listhead).link.f = (pentry); \
  371. } while (false)
  372. #define LINK_TAIL_DLIST(listhead, pentry, link) \
  373. do { \
  374. (pentry)->link.b = (listhead).link.b; \
  375. (pentry)->link.f = &(listhead); \
  376. (listhead).link.b->link.f = (pentry); \
  377. (listhead).link.b = (pentry); \
  378. } while (false)
  379. #define UNLINK_DLIST(ptounlink, link) \
  380. do { \
  381. (ptounlink)->link.b->link.f = (ptounlink)->link.f; \
  382. (ptounlink)->link.f->link.b = (ptounlink)->link.b; \
  383. MAYBE_Z_LISTS((ptounlink)->link.b); \
  384. MAYBE_Z_LISTS((ptounlink)->link.f); \
  385. } while (false)
  386. #define ITER_DLIST_BEGIN(listhead, iter, link, entrytype) \
  387. { \
  388. entrytype *i_dl_nextiter; \
  389. \
  390. for ((iter) = (listhead).link.f; \
  391. (iter) != &(listhead) \
  392. && ((i_dl_nextiter = (iter)->link.f), true); \
  393. (iter) = i_dl_nextiter) {
  394. #define ITER_DLIST_END() \
  395. } \
  396. }
  397. #define REV_ITER_DLIST_BEGIN(listhead, iter, link, entrytype) \
  398. { \
  399. entrytype *i_dl_nextiter; \
  400. \
  401. for ((iter) = (listhead).link.b; \
  402. (iter) != &(listhead) \
  403. && ((i_dl_nextiter = (iter)->link.b), true); \
  404. (iter) = i_dl_nextiter) {
  405. #define REV_ITER_DLIST_END() \
  406. } \
  407. }
  408. #endif /* GUARD_NTP_LISTS_H */