The FreeRADIUS server $Id: a4e7f8c94e8038b7627bcf52356b7ed15955c1d7 $
Loading...
Searching...
No Matches
atomic_queue_test.c
Go to the documentation of this file.
1/*
2 * atomic_queue_test.c Tests for atomic queues
3 *
4 * Version: $Id: e814fcdb0537af7bc1e7863f31dd14eb312ef5ce $
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 *
20 * @copyright 2016 Alan DeKok (aland@freeradius.org)
21 */
22
23RCSID("$Id: e814fcdb0537af7bc1e7863f31dd14eb312ef5ce $")
24
25#include <freeradius-devel/io/atomic_queue.h>
26#include <freeradius-devel/util/debug.h>
27#include <freeradius-devel/util/table.h>
28#include <string.h>
29#include <sys/time.h>
30
31#ifdef HAVE_GETOPT_H
32# include <getopt.h>
33#endif
34
35#define OFFSET (1024)
36
37static int debug_lvl = 0;
38
39/** Which allocator the queue under test comes from
40 */
41typedef enum : uint8_t {
42 QUEUE_TYPE_TALLOC = 0, //!< #fr_atomic_queue_talloc, queue lives in the talloc hierarchy.
43 QUEUE_TYPE_MALLOC, //!< #fr_atomic_queue_malloc, raw queue owned by a talloc handle.
46
48 { L("malloc"), QUEUE_TYPE_MALLOC },
49 { L("talloc"), QUEUE_TYPE_TALLOC }
50};
52
53
54/**********************************************************************/
55typedef struct request_s request_t;
56void request_verify(UNUSED char const *file, UNUSED int line, UNUSED request_t *request);
57
59{
60}
61/**********************************************************************/
62
63
64static NEVER_RETURNS void usage(void)
65{
66 fprintf(stderr, "usage: atomic_queue_test [OPTS]\n");
67 fprintf(stderr, " -s size set queue size.\n");
68 fprintf(stderr, " -t type queue type to test, 'talloc' or 'malloc' (default: both).\n");
69 fprintf(stderr, " -x Debugging mode.\n");
70
71 fr_exit_now(EXIT_SUCCESS);
72}
73
74/** Fill the queue to capacity, check it refuses one more, then drain it
75 *
76 * Exits the process on the first wrong answer.
77 */
78static void queue_exercise(fr_atomic_queue_t *aq, int size)
79{
80 int i;
81 intptr_t val;
82 void *data;
83
84#ifndef NDEBUG
85 if (debug_lvl) {
86 printf("Start\n");
88
89 if (debug_lvl > 1) printf("Filling with %d\n", size);
90 }
91
92#endif
93
94
95 for (i = 0; i < size; i++) {
96 val = i + OFFSET;
97 data = (void *) val;
98
100 fprintf(stderr, "Failed pushing at %d\n", i);
101 fr_exit_now(EXIT_FAILURE);
102 }
103
104#ifndef NDEBUG
105 if (debug_lvl > 1) {
106 printf("iteration %d\n", i);
107 fr_atomic_queue_debug(stdout, aq);
108 }
109#endif
110 }
111
112 val = size + OFFSET;
113 data = (void *) val;
114
115 /*
116 * Queue is full. No more pushes are allowed.
117 */
119 fprintf(stderr, "Pushed an entry past the end of the queue.");
120 fr_exit_now(EXIT_FAILURE);
121 }
122
123#ifndef NDEBUG
124 if (debug_lvl) {
125 printf("Full\n");
126 fr_atomic_queue_debug(stdout, aq);
127
128 if (debug_lvl > 1) printf("Emptying\n");
129 }
130#endif
131
132 /*
133 * And now pop them all.
134 */
135 for (i = 0; i < size; i++) {
136 if (!fr_atomic_queue_pop(aq, &data)) {
137 fprintf(stderr, "Failed popping at %d\n", i);
138 fr_exit_now(EXIT_FAILURE);
139 }
140
141 val = (intptr_t) data;
142 if (val != (i + OFFSET)) {
143 fprintf(stderr, "Pop expected %d, got %d\n",
144 i + OFFSET, (int) val);
145 fr_exit_now(EXIT_FAILURE);
146 }
147
148#ifndef NDEBUG
149 if (debug_lvl > 1) {
150 printf("iteration %d\n", i);
151 fr_atomic_queue_debug(stdout, aq);
152 }
153#endif
154 }
155
156 /*
157 * Queue is empty. No more pops are allowed.
158 */
159 if (fr_atomic_queue_pop(aq, &data)) {
160 fprintf(stderr, "Popped an entry past the end of the queue.");
161 fr_exit_now(EXIT_FAILURE);
162 }
163
164#ifndef NDEBUG
165 if (debug_lvl) {
166 printf("Empty\n");
167 fr_atomic_queue_debug(stdout, aq);
168 }
169#endif
170}
171
172/** Queue allocated inside the talloc hierarchy
173 */
174static void test_talloc(TALLOC_CTX *ctx, int size)
175{
177
178 aq = fr_atomic_queue_talloc(ctx, size);
179 if (!aq) {
180 fprintf(stderr, "Failed allocating talloc queue\n");
181 fr_exit_now(EXIT_FAILURE);
182 }
183
184 queue_exercise(aq, size);
186}
187
188/** Queue allocated outside talloc, but owned by a talloc context
189 *
190 * The only talloc'd block is the owner handle, so the context holds
191 * exactly one child, and freeing the context releases the raw queue
192 * through the handle.
193 */
194static void test_malloc(TALLOC_CTX *ctx, int size)
195{
197 TALLOC_CTX *owner_ctx;
198
199 owner_ctx = talloc_new(ctx);
200 aq = fr_atomic_queue_malloc(owner_ctx, size);
201 if (!aq) {
202 fprintf(stderr, "Failed allocating raw queue\n");
203 fr_exit_now(EXIT_FAILURE);
204 }
205
206 if (talloc_total_blocks(owner_ctx) != 2) {
207 fprintf(stderr, "Expected owner handle to be the only child of ctx, found %zu blocks\n",
208 talloc_total_blocks(owner_ctx));
209 fr_exit_now(EXIT_FAILURE);
210 }
211
212 queue_exercise(aq, size);
213 talloc_free(owner_ctx);
214}
215
216typedef void (*queue_test_t)(TALLOC_CTX *ctx, int size);
217
222
223int main(int argc, char *argv[])
224{
225 int c;
226 int size;
227 int type;
228 bool selected[QUEUE_TYPE_MAX] = {};
229 bool any_selected = false;
230 TALLOC_CTX *autofree = talloc_autofree_context();
231
232 size = 4;
233
234 while ((c = getopt(argc, argv, "hs:t:x")) != -1) switch (c) {
235 case 's':
236 size = atoi(optarg);
237 break;
238
239 case 't':
241 if (type < 0) {
242 fprintf(stderr, "Unknown queue type '%s'\n", optarg);
243 usage();
244 }
245 selected[type] = true;
246 any_selected = true;
247 break;
248
249 case 'x':
250 debug_lvl++;
251 break;
252
253 case 'h':
254 default:
255 usage();
256 }
257#if 0
258 argc -= (optind - 1);
259 argv += (optind - 1);
260#endif
261
262 for (type = 0; type < QUEUE_TYPE_MAX; type++) {
263 if (any_selected && !selected[type]) continue;
264
265 if (debug_lvl) printf("Testing %s queue\n", fr_table_str_by_value(queue_type_table, type, "<INVALID>"));
266 queue_tests[type](autofree, size);
267 }
268
269 return 0;
270}
271
void int line
Definition acutest.h:810
fr_atomic_queue_t * fr_atomic_queue_malloc(TALLOC_CTX *ctx, size_t size)
Create fixed-size atomic queue outside the talloc hierarchy, owned by a talloc context.
bool fr_atomic_queue_pop(fr_atomic_queue_t *aq, void **p_data)
Pop a pointer from the atomic queue.
void fr_atomic_queue_debug(FILE *fp, fr_atomic_queue_t *aq)
Dump an atomic queue.
bool fr_atomic_queue_push(fr_atomic_queue_t *aq, void *data)
Push a pointer into the atomic queue.
void fr_atomic_queue_free(fr_atomic_queue_t **aq)
Free an atomic queue if it's not freed by ctx.
fr_atomic_queue_t * fr_atomic_queue_talloc(TALLOC_CTX *ctx, size_t size)
Create fixed-size atomic queue.
Structure to hold the atomic queue.
int main(int argc, char *argv[])
#define OFFSET
static void test_malloc(TALLOC_CTX *ctx, int size)
Queue allocated outside talloc, but owned by a talloc context.
static fr_table_num_sorted_t const queue_type_table[]
static void queue_exercise(fr_atomic_queue_t *aq, int size)
Fill the queue to capacity, check it refuses one more, then drain it.
static size_t queue_type_table_len
void(* queue_test_t)(TALLOC_CTX *ctx, int size)
static queue_test_t const queue_tests[QUEUE_TYPE_MAX]
static void test_talloc(TALLOC_CTX *ctx, int size)
Queue allocated inside the talloc hierarchy.
queue_type_t
Which allocator the queue under test comes from.
@ QUEUE_TYPE_MAX
@ QUEUE_TYPE_MALLOC
fr_atomic_queue_malloc, raw queue owned by a talloc handle.
@ QUEUE_TYPE_TALLOC
fr_atomic_queue_talloc, queue lives in the talloc hierarchy.
static NEVER_RETURNS void usage(void)
void request_verify(UNUSED char const *file, UNUSED int line, UNUSED request_t *request)
static int debug_lvl
static uint8_t request[4]
#define RCSID(id)
Definition build.h:603
#define NEVER_RETURNS
Should be placed before the function return type.
Definition build.h:413
#define L(_str)
Helper for initialising arrays of string literals.
Definition build.h:245
#define UNUSED
Definition build.h:415
#define NUM_ELEMENTS(_t)
Definition build.h:437
TALLOC_CTX * autofree
Definition common.c:29
static fr_atomic_queue_t ** aq
#define fr_exit_now(_x)
Exit without calling atexit() handlers, producing a log message in debug builds.
Definition debug.h:272
talloc_free(hp)
unsigned char uint8_t
fr_aka_sim_id_type_t type
#define fr_table_value_by_str(_table, _name, _def)
Convert a string to a value using a sorted or ordered table.
Definition table.h:685
#define fr_table_str_by_value(_table, _number, _def)
Convert an integer to a string.
Definition table.h:804
An element in a lexicographically sorted array of name to num mappings.
Definition table.h:49
#define talloc_autofree_context
The original function is deprecated, so replace it with our version.
Definition talloc.h:55
static fr_slen_t data
Definition value.h:1366