The FreeRADIUS server $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
Loading...
Searching...
No Matches
queue.c
Go to the documentation of this file.
1/*
2 * This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2 of the License, or
5 * (at your option) any later version.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
15 */
16
17/**
18 * $Id: d548ba35be7ea8fa5baf0a68d3dddacbe6674101 $
19 *
20 * @brief Thread-unsafe queues
21 * @file io/queue.c
22 *
23 * @copyright 2016 Alan DeKok (aland@freeradius.org)
24 */
25RCSID("$Id: d548ba35be7ea8fa5baf0a68d3dddacbe6674101 $")
26
27#include <stdint.h>
28#include <string.h>
29
30#include <freeradius-devel/util/debug.h>
31#include <freeradius-devel/io/queue.h>
32
33struct fr_queue_s {
34 int head; //!< head of the queue
35 int tail; //!< tail of the queue
36
37 int size; //!< size of the queue
38 int num; //!< number of elements pushed into the queue
39
40 void *entry[1]; //!< Array of queue data.
41};
42
43/** Create a non-thread-safe queue.
44 *
45 * @param[in] ctx the talloc ctx
46 * @param[in] size the number of entries in the queue
47 * @return
48 * - NULL on error
49 * - fr_queue_t *, a pointer to the allocated and initialized queue
50 */
51fr_queue_t *fr_queue_create(TALLOC_CTX *ctx, int size)
52{
53 fr_queue_t *fq;
54
55 if (size <= 0) return NULL;
56
57 /*
58 * Allocate a contiguous blob for the header and queue.
59 * This helps with memory locality.
60 *
61 * Since we're allocating a blob, we should also set the
62 * name of the data, too.
63 */
64 fq = talloc_size(ctx, sizeof(*fq) + (size - 1) * sizeof(fq->entry[0]));
65 if (!fq) return NULL;
66
67 talloc_set_name(fq, "fr_queue_t");
68
69 memset(fq, 0, sizeof(*fq) + (size - 1) * sizeof(fq->entry[0]));
70
71 fq->size = size;
72
73 return fq;
74}
75
76
77/** Push a pointer into the queue
78 *
79 * @param[in] fq the queue
80 * @param[in] data the data to push
81 * @return
82 * - true on successful push
83 * - false on queue full
84 */
86{
87 (void) talloc_get_type_abort(fq, fr_queue_t);
88
89 if (fq->num >= fq->size) return false;
90
91 fq->entry[fq->head++] = data;
92 if (fq->head >= fq->size) fq->head = 0;
93 fq->num++;
94
95 return true;
96}
97
98
99/** Pop a pointer from the queue
100 *
101 * @param[in] fq the queue
102 * @param[in] p_data where to write the data
103 * @return
104 * - true on successful pop
105 * - false on queue empty
106 */
107bool fr_queue_pop(fr_queue_t *fq, void **p_data)
108{
109 (void) talloc_get_type_abort(fq, fr_queue_t);
110
111 if (fq->num == 0) return false;
112
113 *p_data = fq->entry[fq->tail++];
114 if (fq->tail >= fq->size) fq->tail = 0;
115 fq->num--;
116
117 return true;
118}
119
120
121/** get the size of a queue
122 *
123 * @param[in] fq the queue
124 * @return
125 * - The size of the queue.
126 */
128{
129 (void) talloc_get_type_abort(fq, fr_queue_t);
130
131 return fq->size;
132}
133
134
135/** get the number of elements in a queue.
136 *
137 * @param[in] fq the queue
138 * @return
139 * - The number of elements in the queue.
140 */
142{
143 (void) talloc_get_type_abort(fq, fr_queue_t);
144
145 return fq->num;
146}
147
148
149
150/** Resize a queue, and copy the entries over.
151 *
152 * @param[in] fq the queue
153 * @param[in] size the new size of the queue
154 * @return
155 * - NULL on error
156 * - fr_queue_t * the new queue, which MAY BE fq.
157 */
159{
160 fr_queue_t *nq;
161 TALLOC_CTX *ctx;
162
163 (void) talloc_get_type_abort(fq, fr_queue_t);
164
165 if (size <= 0) return NULL;
166
167 if (size <= fq->size) return fq;
168
169 ctx = talloc_parent(fq);
170
171 /*
172 * If we can't create the new queue, return the old one.
173 */
174 nq = fr_queue_create(ctx, size);
175 if (!nq) return fq;
176
177 /*
178 * Empty: we're done.
179 */
180 if (!fq->num) {
181 goto done;
182 }
183
184 /*
185 * Simple block of used elements, copy it.
186 */
187 if (fq->head > fq->tail) {
188 fr_assert(fq->num == (fq->head - fq->tail));
189 memcpy(&nq->entry[0], &fq->entry[fq->tail], &fq->entry[fq->head] - &fq->entry[fq->tail]);
190 nq->head = fq->num;
191 nq->num = fq->num;
192 goto done;
193 }
194
195 /*
196 * The block of elements is split in two. Copy the tail
197 * to the bottom of our array, and then then head.
198 */
199 memcpy(&nq->entry[0], &fq->entry[fq->tail], &fq->entry[fq->size] - &fq->entry[fq->tail]);
200 nq->head = fq->size - fq->tail;
201
202 fr_assert((nq->head + fq->head) == fq->num);
203
204 memcpy(&nq->entry[nq->head], &fq->entry[0], &fq->entry[fq->head] - &fq->entry[0]);
205 nq->head = fq->num;
206 nq->num = fq->num;
207
208done:
209 talloc_free(fq);
210
211 return nq;
212}
213
214
215/** Pull all entries from an atomic queue into our local queue.
216 *
217 * @param[in] fq the local queue
218 * @param[in] aq the atomic queue
219 * @return
220 * - number of entries successfully moved over
221 */
223{
224 void *data;
225 int i, room;
226
227 (void) talloc_get_type_abort(fq, fr_queue_t);
228
229 /*
230 * No room to push anything, return an error.
231 */
232 room = fq->size - fq->num;
233 if (!room) return 0;
234
235 /*
236 * Pop as many entries as we have room for.
237 */
238 for (i = 0; i < room; i++) {
239 if (!fr_atomic_queue_pop(aq, &data)) {
240 return i;
241 }
242
243 fq->entry[fq->head++] = data;
244 if (fq->head >= fq->size) fq->head = 0;
245 fq->num++;
246 fr_assert(fq->num <= fq->size);
247 }
248
249 return room;
250}
251
252#ifndef NDEBUG
253/** Dump a queue.
254 *
255 * @param[in] fq the queue
256 * @param[in] fp where the debugging information will be printed.
257 */
258void fr_queue_debug(fr_queue_t *fq, FILE *fp)
259{
260 int i;
261
262 fprintf(fp, "FQ %p size %d, head %d, tail %d\n",
263 fq, fq->size, fq->head, fq->tail);
264
265 for (i = 0; i < fq->size; i++) {
266 fprintf(fp, "\t[%d] = { %p }\n",
267 i, fq->entry[i]);
268 }
269}
270#endif
bool fr_atomic_queue_pop(fr_atomic_queue_t *aq, void **p_data)
Pop a pointer from the atomic queue.
Structure to hold the atomic queue.
#define RCSID(id)
Definition build.h:483
static fr_atomic_queue_t * aq
int fr_queue_size(fr_queue_t *fq)
get the size of a queue
Definition queue.c:127
bool fr_queue_pop(fr_queue_t *fq, void **p_data)
Pop a pointer from the queue.
Definition queue.c:107
int head
head of the queue
Definition queue.c:34
int size
size of the queue
Definition queue.c:37
fr_queue_t * fr_queue_create(TALLOC_CTX *ctx, int size)
Create a non-thread-safe queue.
Definition queue.c:51
int num
number of elements pushed into the queue
Definition queue.c:38
void * entry[1]
Array of queue data.
Definition queue.c:40
fr_queue_t * fr_queue_resize(fr_queue_t *fq, int size)
Resize a queue, and copy the entries over.
Definition queue.c:158
void fr_queue_debug(fr_queue_t *fq, FILE *fp)
Dump a queue.
Definition queue.c:258
bool fr_queue_push(fr_queue_t *fq, void *data)
Push a pointer into the queue.
Definition queue.c:85
int fr_queue_num_elements(fr_queue_t *fq)
get the number of elements in a queue.
Definition queue.c:141
int tail
tail of the queue
Definition queue.c:35
int fr_queue_localize_atomic(fr_queue_t *fq, fr_atomic_queue_t *aq)
Pull all entries from an atomic queue into our local queue.
Definition queue.c:222
talloc_free(reap)
#define fr_assert(_expr)
Definition rad_assert.h:38
static bool done
Definition radclient.c:80
static fr_slen_t data
Definition value.h:1265