The FreeRADIUS server  $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
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  */
25 RCSID("$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 
33 struct 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  */
51 fr_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  */
85 bool fr_queue_push(fr_queue_t *fq, void *data)
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  */
107 bool 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 
208 done:
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  */
258 void 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.
Definition: atomic_queue.c:215
Structure to hold the atomic queue.
Definition: atomic_queue.c:54
#define RCSID(id)
Definition: build.h:444
static fr_atomic_queue_t * aq
Definition: control_test.c:47
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
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
fr_queue_t * fr_queue_create(TALLOC_CTX *ctx, int size)
Create a non-thread-safe queue.
Definition: queue.c:51
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)
static bool done
Definition: radclient.c:80
fr_assert(0)
static fr_slen_t data
Definition: value.h:1259