2 * PgBouncer - Lightweight connection pooler for PostgreSQL.
4 * Copyright (c) 2007-2009 Marko Kreen, Skype Technologies OÜ
6 * Permission to use, copy, modify, and/or distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20 * Circular doubly linked list implementation.
22 * Basic idea from <linux/list.h>.
24 * <sys/queue.h> seemed usable, but overcomplicated.
30 /* turn on slow checking */
31 /* #define LIST_DEBUG */
33 /* give offset of a field inside struct */
35 #define offsetof(type, field) ((unsigned long)&(((type *)0)->field))
38 /* given pointer to field inside struct, return pointer to struct */
40 #define container_of(ptr, type, field) ((type *)((char *)(ptr) - offsetof(type, field)))
44 typedef struct List List
;
50 #define LIST(var) List var = { &var, &var }
52 /* initialize struct */
53 static inline void list_init(List
*list
)
55 list
->next
= list
->prev
= list
;
59 static inline bool list_empty(const List
*list
)
61 return list
->next
== list
;
64 /* add item to the start of the list */
65 static inline List
*list_prepend(List
*item
, List
*list
)
67 Assert(list_empty(item
));
69 item
->next
= list
->next
;
71 list
->next
->prev
= item
;
76 /* add item to the end of the list */
77 static inline List
*list_append(List
*item
, List
*list
)
79 Assert(list_empty(item
));
82 item
->prev
= list
->prev
;
83 list
->prev
->next
= item
;
88 /* remove item from list */
89 static inline List
*list_del(List
*item
)
91 item
->prev
->next
= item
->next
;
92 item
->next
->prev
= item
->prev
;
93 item
->next
= item
->prev
= item
;
97 /* remove first from list and return */
98 static inline List
*list_pop(List
*list
)
100 if (list_empty(list
))
102 return list_del(list
->next
);
105 /* remove first from list and return */
106 static inline List
*list_first(const List
*list
)
108 if (list_empty(list
))
113 /* put all elems in one list in the start of another list */
114 static inline void list_prepend_list(List
*src
, List
*dst
)
118 src
->next
->prev
= dst
;
119 src
->prev
->next
= dst
->next
;
120 dst
->next
->prev
= src
->prev
;
121 dst
->next
= src
->next
;
123 src
->next
= src
->prev
= src
;
126 /* put all elems in one list in the end of another list */
127 static inline void list_append_list(List
*src
, List
*dst
)
131 src
->next
->prev
= dst
->prev
;
132 src
->prev
->next
= dst
;
133 dst
->prev
->next
= src
->next
;
134 dst
->prev
= src
->prev
;
136 src
->next
= src
->prev
= src
;
139 /* remove first elem from list and return with casting */
140 #define list_pop_type(list, typ, field) \
141 (list_empty(list) ? NULL \
142 : container_of(list_del((list)->next), typ, field))
145 #define list_for_each(item, list) \
146 for ((item) = (list)->next; \
148 (item) = (item)->next)
150 /* loop over list and allow removing item */
151 #define list_for_each_safe(item, list, tmp) \
152 for ((item) = (list)->next, (tmp) = (list)->next->next; \
154 (item) = (tmp), (tmp) = (tmp)->next)
156 static inline bool item_in_list(const List
*item
, const List
*list
)
159 list_for_each(tmp
, list
)
167 * wrapper for List that keeps track of number of items
170 typedef struct StatList StatList
;
180 #define STATLIST(var) StatList var = { {&var.head, &var.head}, 0, #var }
182 #define STATLIST(var) StatList var = { {&var.head, &var.head}, 0 }
185 static inline void statlist_inc_count(StatList
*list
, int val
)
187 list
->cur_count
+= val
;
190 static inline void statlist_prepend(List
*item
, StatList
*list
)
192 list_prepend(item
, &list
->head
);
193 statlist_inc_count(list
, 1);
196 static inline void statlist_append(List
*item
, StatList
*list
)
198 list_append(item
, &list
->head
);
199 statlist_inc_count(list
, 1);
202 static inline void statlist_put_before(List
*item
, StatList
*list
, List
*pos
)
204 list_append(item
, pos
);
205 statlist_inc_count(list
, 1);
208 static inline void statlist_remove(List
*item
, StatList
*list
)
212 if (!item_in_list(item
, &list
->head
))
213 fatal("item in wrong list, expected: %s", list
->name
);
219 Assert(list
->cur_count
>= 0);
222 static inline void statlist_init(StatList
*list
, const char *name
)
224 list_init(&list
->head
);
231 static inline int statlist_count(const StatList
*list
)
233 Assert(list
->cur_count
> 0 || list_empty(&list
->head
));
234 return list
->cur_count
;
237 static inline List
*statlist_pop(StatList
*list
)
239 List
*item
= list_pop(&list
->head
);
244 Assert(list
->cur_count
>= 0);
249 static inline void statlist_prepend_list(StatList
*src
, StatList
*dst
)
251 list_prepend_list(&src
->head
, &dst
->head
);
252 statlist_inc_count(dst
, src
->cur_count
);
256 static inline void statlist_append_list(StatList
*src
, StatList
*dst
)
258 list_append_list(&src
->head
, &dst
->head
);
259 statlist_inc_count(dst
, src
->cur_count
);
263 static inline List
*statlist_first(const StatList
*list
)
265 return list_first(&list
->head
);
268 static inline bool statlist_empty(const StatList
*list
)
270 return list_empty(&list
->head
);
273 #define statlist_for_each(item, list) list_for_each(item, &((list)->head))
274 #define statlist_for_each_safe(item, list, tmp) list_for_each_safe(item, &((list)->head), tmp)
276 #endif /* __LIST_H_ */