Age Owner Branch data TLA Line data Source code
1 : : /*-------------------------------------------------------------------------
2 : : *
3 : : * proclist.h
4 : : * operations on doubly-linked lists of pgprocnos
5 : : *
6 : : * The interface is similar to dlist from ilist.h, but uses pgprocno instead
7 : : * of pointers. This allows proclist_head to be mapped at different addresses
8 : : * in different backends.
9 : : *
10 : : * See proclist_types.h for the structs that these functions operate on. They
11 : : * are separated to break a header dependency cycle with proc.h.
12 : : *
13 : : * Portions Copyright (c) 2016-2024, PostgreSQL Global Development Group
14 : : *
15 : : * IDENTIFICATION
16 : : * src/include/storage/proclist.h
17 : : *-------------------------------------------------------------------------
18 : : */
19 : : #ifndef PROCLIST_H
20 : : #define PROCLIST_H
21 : :
22 : : #include "storage/proc.h"
23 : : #include "storage/proclist_types.h"
24 : :
25 : : /*
26 : : * Initialize a proclist.
27 : : */
28 : : static inline void
2799 rhaas@postgresql.org 29 :CBC 19669856 : proclist_init(proclist_head *list)
30 : : {
42 heikki.linnakangas@i 31 :GNC 19669856 : list->head = list->tail = INVALID_PROC_NUMBER;
2799 rhaas@postgresql.org 32 :CBC 19669856 : }
33 : :
34 : : /*
35 : : * Is the list empty?
36 : : */
37 : : static inline bool
451 peter@eisentraut.org 38 : 6492273 : proclist_is_empty(const proclist_head *list)
39 : : {
42 heikki.linnakangas@i 40 :GNC 6492273 : return list->head == INVALID_PROC_NUMBER;
41 : : }
42 : :
43 : : /*
44 : : * Get a pointer to a proclist_node inside a given PGPROC, given a procno and
45 : : * the proclist_node field's offset within struct PGPROC.
46 : : */
47 : : static inline proclist_node *
2799 rhaas@postgresql.org 48 :CBC 8185241 : proclist_node_get(int procno, size_t node_offset)
49 : : {
50 : 8185241 : char *entry = (char *) GetPGProcByNumber(procno);
51 : :
52 : 8185241 : return (proclist_node *) (entry + node_offset);
53 : : }
54 : :
55 : : /*
56 : : * Insert a process at the beginning of a list.
57 : : */
58 : : static inline void
59 : 3364 : proclist_push_head_offset(proclist_head *list, int procno, size_t node_offset)
60 : : {
61 : 3364 : proclist_node *node = proclist_node_get(procno, node_offset);
62 : :
2288 tgl@sss.pgh.pa.us 63 [ + - - + ]: 3364 : Assert(node->next == 0 && node->prev == 0);
64 : :
42 heikki.linnakangas@i 65 [ + + ]:GNC 3364 : if (list->head == INVALID_PROC_NUMBER)
66 : : {
67 [ - + ]: 2928 : Assert(list->tail == INVALID_PROC_NUMBER);
68 : 2928 : node->next = node->prev = INVALID_PROC_NUMBER;
2799 rhaas@postgresql.org 69 :CBC 2928 : list->head = list->tail = procno;
70 : : }
71 : : else
72 : : {
42 heikki.linnakangas@i 73 [ - + ]:GNC 436 : Assert(list->tail != INVALID_PROC_NUMBER);
2700 rhaas@postgresql.org 74 [ - + ]:CBC 436 : Assert(list->head != procno);
75 [ - + ]: 436 : Assert(list->tail != procno);
2799 76 : 436 : node->next = list->head;
77 : 436 : proclist_node_get(node->next, node_offset)->prev = procno;
42 heikki.linnakangas@i 78 :GNC 436 : node->prev = INVALID_PROC_NUMBER;
2799 rhaas@postgresql.org 79 :CBC 436 : list->head = procno;
80 : : }
81 : 3364 : }
82 : :
83 : : /*
84 : : * Insert a process at the end of a list.
85 : : */
86 : : static inline void
87 : 1097329 : proclist_push_tail_offset(proclist_head *list, int procno, size_t node_offset)
88 : : {
89 : 1097329 : proclist_node *node = proclist_node_get(procno, node_offset);
90 : :
2288 tgl@sss.pgh.pa.us 91 [ + - - + ]: 1097329 : Assert(node->next == 0 && node->prev == 0);
92 : :
42 heikki.linnakangas@i 93 [ + + ]:GNC 1097329 : if (list->tail == INVALID_PROC_NUMBER)
94 : : {
95 [ - + ]: 1062625 : Assert(list->head == INVALID_PROC_NUMBER);
96 : 1062625 : node->next = node->prev = INVALID_PROC_NUMBER;
2799 rhaas@postgresql.org 97 :CBC 1062625 : list->head = list->tail = procno;
98 : : }
99 : : else
100 : : {
42 heikki.linnakangas@i 101 [ - + ]:GNC 34704 : Assert(list->head != INVALID_PROC_NUMBER);
2700 rhaas@postgresql.org 102 [ - + ]:CBC 34704 : Assert(list->head != procno);
103 [ - + ]: 34704 : Assert(list->tail != procno);
2799 104 : 34704 : node->prev = list->tail;
105 : 34704 : proclist_node_get(node->prev, node_offset)->next = procno;
42 heikki.linnakangas@i 106 :GNC 34704 : node->next = INVALID_PROC_NUMBER;
2799 rhaas@postgresql.org 107 :CBC 34704 : list->tail = procno;
108 : : }
109 : 1097329 : }
110 : :
111 : : /*
112 : : * Delete a process from a list --- it must be in the list!
113 : : */
114 : : static inline void
115 : 1100673 : proclist_delete_offset(proclist_head *list, int procno, size_t node_offset)
116 : : {
117 : 1100673 : proclist_node *node = proclist_node_get(procno, node_offset);
118 : :
2288 tgl@sss.pgh.pa.us 119 [ + + - + ]: 1100673 : Assert(node->next != 0 || node->prev != 0);
120 : :
42 heikki.linnakangas@i 121 [ + + ]:GNC 1100673 : if (node->prev == INVALID_PROC_NUMBER)
122 : : {
2288 tgl@sss.pgh.pa.us 123 [ - + ]:CBC 1099490 : Assert(list->head == procno);
2799 rhaas@postgresql.org 124 : 1099490 : list->head = node->next;
125 : : }
126 : : else
127 : 1183 : proclist_node_get(node->prev, node_offset)->next = node->next;
128 : :
42 heikki.linnakangas@i 129 [ + + ]:GNC 1100673 : if (node->next == INVALID_PROC_NUMBER)
130 : : {
2288 tgl@sss.pgh.pa.us 131 [ - + ]:CBC 1066660 : Assert(list->tail == procno);
2799 rhaas@postgresql.org 132 : 1066660 : list->tail = node->prev;
133 : : }
134 : : else
135 : 34013 : proclist_node_get(node->next, node_offset)->prev = node->prev;
136 : :
2288 tgl@sss.pgh.pa.us 137 : 1100673 : node->next = node->prev = 0;
2700 rhaas@postgresql.org 138 : 1100673 : }
139 : :
140 : : /*
141 : : * Check if a process is currently in a list. It must be known that the
142 : : * process is not in any _other_ proclist that uses the same proclist_node,
143 : : * so that the only possibilities are that it is in this list or none.
144 : : */
145 : : static inline bool
451 peter@eisentraut.org 146 : 4978655 : proclist_contains_offset(const proclist_head *list, int procno,
147 : : size_t node_offset)
148 : : {
149 : 4978655 : const proclist_node *node = proclist_node_get(procno, node_offset);
150 : :
151 : : /* If it's not in any list, it's definitely not in this one. */
2700 rhaas@postgresql.org 152 [ + + + - ]: 4978655 : if (node->prev == 0 && node->next == 0)
153 : 4926346 : return false;
154 : :
155 : : /*
156 : : * It must, in fact, be in this list. Ideally, in assert-enabled builds,
157 : : * we'd verify that. But since this function is typically used while
158 : : * holding a spinlock, crawling the whole list is unacceptable. However,
159 : : * we can verify matters in O(1) time when the node is a list head or
160 : : * tail, and that seems worth doing, since in practice that should often
161 : : * be enough to catch mistakes.
162 : : */
42 heikki.linnakangas@i 163 [ + + - + ]:GNC 52309 : Assert(node->prev != INVALID_PROC_NUMBER || list->head == procno);
164 [ + + - + ]: 52309 : Assert(node->next != INVALID_PROC_NUMBER || list->tail == procno);
165 : :
2288 tgl@sss.pgh.pa.us 166 :CBC 52309 : return true;
167 : : }
168 : :
169 : : /*
170 : : * Remove and return the first process from a list (there must be one).
171 : : */
172 : : static inline PGPROC *
2700 rhaas@postgresql.org 173 : 29305 : proclist_pop_head_node_offset(proclist_head *list, size_t node_offset)
174 : : {
175 : : PGPROC *proc;
176 : :
177 [ - + ]: 29305 : Assert(!proclist_is_empty(list));
178 : 29305 : proc = GetPGProcByNumber(list->head);
179 : 29305 : proclist_delete_offset(list, list->head, node_offset);
180 : 29305 : return proc;
181 : : }
182 : :
183 : : /*
184 : : * Helper macros to avoid repetition of offsetof(PGPROC, <member>).
185 : : * 'link_member' is the name of a proclist_node member in PGPROC.
186 : : */
187 : : #define proclist_delete(list, procno, link_member) \
188 : : proclist_delete_offset((list), (procno), offsetof(PGPROC, link_member))
189 : : #define proclist_push_head(list, procno, link_member) \
190 : : proclist_push_head_offset((list), (procno), offsetof(PGPROC, link_member))
191 : : #define proclist_push_tail(list, procno, link_member) \
192 : : proclist_push_tail_offset((list), (procno), offsetof(PGPROC, link_member))
193 : : #define proclist_pop_head_node(list, link_member) \
194 : : proclist_pop_head_node_offset((list), offsetof(PGPROC, link_member))
195 : : #define proclist_contains(list, procno, link_member) \
196 : : proclist_contains_offset((list), (procno), offsetof(PGPROC, link_member))
197 : :
198 : : /*
199 : : * Iterate through the list pointed at by 'lhead', storing the current
200 : : * position in 'iter'. 'link_member' is the name of a proclist_node member in
201 : : * PGPROC. Access the current position with iter.cur.
202 : : *
203 : : * The only list modification allowed while iterating is deleting the current
204 : : * node with proclist_delete(list, iter.cur, node_offset).
205 : : */
206 : : #define proclist_foreach_modify(iter, lhead, link_member) \
207 : : for (AssertVariableIsOfTypeMacro(iter, proclist_mutable_iter), \
208 : : AssertVariableIsOfTypeMacro(lhead, proclist_head *), \
209 : : (iter).cur = (lhead)->head, \
210 : : (iter).next = (iter).cur == INVALID_PROC_NUMBER ? INVALID_PROC_NUMBER : \
211 : : proclist_node_get((iter).cur, \
212 : : offsetof(PGPROC, link_member))->next; \
213 : : (iter).cur != INVALID_PROC_NUMBER; \
214 : : (iter).cur = (iter).next, \
215 : : (iter).next = (iter).cur == INVALID_PROC_NUMBER ? INVALID_PROC_NUMBER : \
216 : : proclist_node_get((iter).cur, \
217 : : offsetof(PGPROC, link_member))->next)
218 : :
219 : : #endif /* PROCLIST_H */
|