The FreeRADIUS server $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
Loading...
Searching...
No Matches
fifo.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/** Non-thread-safe fifo (FIFO) implementation
18 *
19 * @file src/lib/util/fifo.c
20 *
21 * @copyright 2005,2006 The FreeRADIUS server project
22 * @copyright 2005 Alan DeKok (aland@freeradius.org)
23 */
24RCSID("$Id: 3c967c14f10148ad89679fcadadb49fb8f212808 $")
25
26#include <string.h>
27
28#include <freeradius-devel/util/fifo.h>
29
30struct fr_fifo_s {
31 unsigned int num; //!< How many elements exist in the fifo.
32 unsigned int first, last; //!< Head and tail indexes for the fifo.
33 unsigned int max; //!< How many elements were created in the fifo.
34 fr_fifo_free_t free_node; //!< Function to call to free nodes when the fifo is freed.
35
36 char const *type; //!< Type of elements.
37
38 void *data[1];
39};
40
41/** Free a fifo and optionally, any data still enqueued
42 *
43 * @param[in] fi to free.
44 * @return 0
45 */
46static int _fifo_free(fr_fifo_t *fi)
47{
48 unsigned int i;
49
50 if (fi->free_node) {
51 for (i = 0 ; i < fi->num; i++) {
52 unsigned int element;
53
54 element = i + fi->first;
55 if (element > fi->max) {
56 element -= fi->max;
57 }
58
59 fi->free_node(fi->data[element]);
60 fi->data[element] = NULL;
61 }
62 }
63
64 memset(fi, 0, sizeof(*fi));
65
66 return 0;
67}
68
69/** Create a fifo queue
70 *
71 * The first element enqueued will be the first to be dequeued.
72 *
73 * @note The created fifo does not provide any thread synchronisation functionality
74 * such as mutexes. If multiple threads are enqueueing and dequeueing data
75 * the callers must synchronise their access.
76 *
77 * @param[in] ctx to allocate fifo array in.
78 * @param[in] type Talloc type of elements (may be NULL).
79 * @param[in] max The maximum number of elements allowed.
80 * @param[in] free_node Function to use to free node data if the fifo is freed.
81 * @return
82 * - A new fifo queue.
83 * - NULL on error.
84 */
85fr_fifo_t *_fr_fifo_create(TALLOC_CTX *ctx, char const *type, int max, fr_fifo_free_t free_node)
86{
87 fr_fifo_t *fi;
88
89 if ((max < 2) || (max > (1024 * 1024))) return NULL;
90
91 fi = talloc_zero_size(ctx, (sizeof(*fi) + (sizeof(fi->data[0])*max)));
92 if (!fi) return NULL;
93 talloc_set_type(fi, fr_fifo_t);
94 talloc_set_destructor(fi, _fifo_free);
95
96 fi->max = max;
97 fi->type = type;
98 fi->free_node = free_node;
99
100 return fi;
101}
102
103/** Push data onto the fifo
104 *
105 * @param[in] fi FIFO to push data onto.
106 * @param[in] data to push.
107 * @return
108 * - 0 on success.
109 * - -1 on error.
110 */
112{
113 if (!fi || !data) return -1;
114
115 if (fi->num >= fi->max) return -1;
116
117#ifndef TALLOC_GET_TYPE_ABORT_NOOP
118 if (fi->type) _talloc_get_type_abort(data, fi->type, __location__);
119#endif
120
121 fi->data[fi->last++] = data;
122 if (fi->last >= fi->max) fi->last = 0;
123 fi->num++;
124
125 return 0;
126}
127
128/** Pop data off of the fifo
129 *
130 * @param[in] fi FIFO to pop data from.
131 * @return
132 * - The data popped.
133 * - NULL if the queue is empty.
134 */
136{
137 void *data;
138
139 if (!fi || (fi->num == 0)) return NULL;
140
141 data = fi->data[fi->first++];
142
143 if (fi->first >= fi->max) {
144 fi->first = 0;
145 }
146 fi->num--;
147
148 return data;
149}
150
151/** Examine the next element that would be popped
152 *
153 * @param[in] fi FIFO to peek at.
154 * @return
155 * - The data at the head of the queue
156 * - NULL if the queue is empty.
157 */
159{
160 if (!fi || (fi->num == 0)) return NULL;
161
162 return fi->data[fi->first];
163}
164
165/** Return the number of elements in the fifo queue
166 *
167 * @param[in] fi FIFO to count elements in.
168 * @return the number of elements
169 */
171{
172 if (!fi) return 0;
173
174 return fi->num;
175}
176
177#ifdef TESTING
178
179/*
180 * cc -DTESTING -I .. fifo.c -o fifo
181 *
182 * ./fifo
183 */
184
185#define MAX 1024
186int main(int argc, char **argv)
187{
188 int i, j, array[MAX];
189 fr_fifo_t *fi;
190
191 fi = fr_fifo_create(NULL, MAX, NULL);
192 if (!fi) fr_exit(1);
193
194 for (j = 0; j < 5; j++) {
195#define SPLIT (MAX/3)
196#define COUNT ((j * SPLIT) + i)
197 for (i = 0; i < SPLIT; i++) {
198 array[COUNT % MAX] = COUNT;
199
200 if (fr_fifo_push(fi, &array[COUNT % MAX]) < 0) {
201 fprintf(stderr, "%d %d\tfailed pushing %d\n",
202 j, i, COUNT);
203 fr_exit(2);
204 }
205
206 if (fr_fifo_num_elements(fi) != (i + 1)) {
207 fprintf(stderr, "%d %d\tgot size %d expected %d\n",
208 j, i, i + 1, fr_fifo_num_elements(fi));
209 fr_exit(1);
210 }
211 }
212
213 if (fr_fifo_num_elements(fi) != SPLIT) {
214 fprintf(stderr, "HALF %d %d\n",
215 fr_fifo_num_elements(fi), SPLIT);
216 fr_exit(1);
217 }
218
219 for (i = 0; i < SPLIT; i++) {
220 int *p;
221
222 p = fr_fifo_pop(fi);
223 if (!p) {
224 fprintf(stderr, "No pop at %d\n", i);
225 fr_exit(3);
226 }
227
228 if (*p != COUNT) {
229 fprintf(stderr, "%d %d\tgot %d expected %d\n",
230 j, i, *p, COUNT);
231 fr_exit(4);
232 }
233
234 if (fr_fifo_num_elements(fi) != SPLIT - (i + 1)) {
235 fprintf(stderr, "%d %d\tgot size %d expected %d\n",
236 j, i, SPLIT - (i + 1), fr_fifo_num_elements(fi));
237 fr_exit(1);
238 }
239 }
240
241 if (fr_fifo_num_elements(fi) != 0) {
242 fprintf(stderr, "ZERO %d %d\n",
243 fr_fifo_num_elements(fi), 0);
244 fr_exit(1);
245 }
246 }
247
248 talloc_free(fi);
249
250 fr_exit(0);
251}
252#endif
#define RCSID(id)
Definition build.h:483
#define fr_exit(_x)
Exit, producing a log message in debug builds.
Definition debug.h:228
int main(int argc, char **argv)
Definition dhcpclient.c:524
void * fr_fifo_peek(fr_fifo_t *fi)
Examine the next element that would be popped.
Definition fifo.c:158
char const * type
Type of elements.
Definition fifo.c:36
unsigned int last
Head and tail indexes for the fifo.
Definition fifo.c:32
void * data[1]
Definition fifo.c:38
unsigned int num
How many elements exist in the fifo.
Definition fifo.c:31
unsigned int fr_fifo_num_elements(fr_fifo_t *fi)
Return the number of elements in the fifo queue.
Definition fifo.c:170
fr_fifo_t * _fr_fifo_create(TALLOC_CTX *ctx, char const *type, int max, fr_fifo_free_t free_node)
Create a fifo queue.
Definition fifo.c:85
int fr_fifo_push(fr_fifo_t *fi, void *data)
Push data onto the fifo.
Definition fifo.c:111
fr_fifo_free_t free_node
Function to call to free nodes when the fifo is freed.
Definition fifo.c:34
unsigned int max
How many elements were created in the fifo.
Definition fifo.c:33
void * fr_fifo_pop(fr_fifo_t *fi)
Pop data off of the fifo.
Definition fifo.c:135
unsigned int first
Definition fifo.c:32
static int _fifo_free(fr_fifo_t *fi)
Free a fifo and optionally, any data still enqueued.
Definition fifo.c:46
#define fr_fifo_create(_ctx, _max_entries, _node_free)
Creates a fifo.
Definition fifo.h:66
void(* fr_fifo_free_t)(void *)
Definition fifo.h:36
talloc_free(reap)
fr_aka_sim_id_type_t type
static fr_slen_t data
Definition value.h:1265