comparison freeDiameter/tests/testqueues.c @ 8:3e143f047f78

Backup for the week-end
author Sebastien Decugis <sdecugis@nict.go.jp>
date Fri, 18 Sep 2009 18:54:07 +0900
parents freeDiameter/tests/testmq.c@bafb831ba688
children
comparison
equal deleted inserted replaced
7:e5af94b04946 8:3e143f047f78
1 /*********************************************************************************************************
2 * Software License Agreement (BSD License) *
3 * Author: Sebastien Decugis <sdecugis@nict.go.jp> *
4 * *
5 * Copyright (c) 2009, WIDE Project and NICT *
6 * All rights reserved. *
7 * *
8 * Redistribution and use of this software in source and binary forms, with or without modification, are *
9 * permitted provided that the following conditions are met: *
10 * *
11 * * Redistributions of source code must retain the above *
12 * copyright notice, this list of conditions and the *
13 * following disclaimer. *
14 * *
15 * * Redistributions in binary form must reproduce the above *
16 * copyright notice, this list of conditions and the *
17 * following disclaimer in the documentation and/or other *
18 * materials provided with the distribution. *
19 * *
20 * * Neither the name of the WIDE Project or NICT nor the *
21 * names of its contributors may be used to endorse or *
22 * promote products derived from this software without *
23 * specific prior written permission of WIDE Project and *
24 * NICT. *
25 * *
26 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED *
27 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
28 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR *
29 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT *
30 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS *
31 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR *
32 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF *
33 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *
34 *********************************************************************************************************/
35
36 #include "tests.h"
37
38 /* Structure for testing threshold function */
39 static struct thrh_test {
40 struct fifo * queue; /* pointer to the queue */
41 int h_calls; /* number of calls of h_cb */
42 int l_calls; /* number of calls of l_cb */
43 } thrh_td;
44
45 /* Callbacks for threasholds test */
46 void thrh_cb_h(struct fifo *queue, void **data)
47 {
48 if (thrh_td.h_calls == thrh_td.l_calls) {
49 CHECK( NULL, *data );
50 *data = &thrh_td;
51 } else {
52 CHECK( *data, &thrh_td );
53 }
54 CHECK( queue, thrh_td.queue );
55
56 /* Update the count */
57 thrh_td.h_calls ++;
58 }
59 void thrh_cb_l(struct fifo *queue, void **data)
60 {
61 CHECK( 1, data ? 1 : 0 );
62 CHECK( *data, &thrh_td );
63
64 /* Check the queue parameter is correct */
65 CHECK( queue, thrh_td.queue );
66
67 /* Update the count */
68 thrh_td.l_calls ++;
69 /* Cleanup the data ptr if needed */
70 if (thrh_td.l_calls == thrh_td.h_calls)
71 *data = NULL;
72 /* done */
73 }
74
75
76 /* Structure that is passed to the test function */
77 struct test_data {
78 struct fifo * queue; /* pointer to the queue */
79 pthread_barrier_t * bar; /* if not NULL, barrier to synchronize before getting messages */
80 struct timespec * ts; /* if not NULL, use a timedget instead of a get */
81 int nbr; /* number of messages to retrieve from the queue */
82 };
83
84 /* The test function, to be threaded */
85 static void * test_fct(void * data)
86 {
87 int ret = 0, i;
88 struct msg * msg = NULL;
89 struct test_data * td = (struct test_data *) data;
90
91 if (td->bar != NULL) {
92 ret = pthread_barrier_wait(td->bar);
93 if (ret != PTHREAD_BARRIER_SERIAL_THREAD) {
94 CHECK( 0, ret);
95 } else {
96 CHECK( PTHREAD_BARRIER_SERIAL_THREAD, ret); /* just for the traces */
97 }
98 }
99
100 for (i=0; i< td->nbr; i++) {
101 if (td->ts != NULL) {
102 CHECK( 0, fd_fifo_timedget(td->queue, &msg, td->ts) );
103 } else {
104 CHECK( 0, fd_fifo_get(td->queue, &msg) );
105 }
106 }
107
108 return NULL;
109 }
110
111
112 /* Main test routine */
113 int main(int argc, char *argv[])
114 {
115 struct timespec ts;
116
117 struct msg * msg1 = NULL;
118 struct msg * msg2 = NULL;
119 struct msg * msg3 = NULL;
120
121 /* First, initialize the daemon modules */
122 INIT_FD();
123
124 /* Prolog: create the messages */
125 {
126 struct dict_object * acr_model = NULL;
127 struct dict_object * cer_model = NULL;
128 struct dict_object * dwr_model = NULL;
129
130 CHECK( 0, fd_dict_search ( fd_g_config->g_dict, DICT_COMMAND, CMD_BY_NAME, "Accounting-Request", &acr_model, ENOENT ) );
131 CHECK( 0, fd_dict_search ( fd_g_config->g_dict, DICT_COMMAND, CMD_BY_NAME, "Capabilities-Exchange-Request", &cer_model, ENOENT ) );
132 CHECK( 0, fd_dict_search ( fd_g_config->g_dict, DICT_COMMAND, CMD_BY_NAME, "Device-Watchdog-Request", &dwr_model, ENOENT ) );
133 CHECK( 0, fd_msg_new ( acr_model, 0, &msg1 ) );
134 CHECK( 0, fd_msg_new ( cer_model, 0, &msg2 ) );
135 CHECK( 0, fd_msg_new ( dwr_model, 0, &msg3 ) );
136 }
137
138 /* Basic operation */
139 {
140 struct fifo * queue = NULL;
141 int count;
142 struct msg * msg = NULL;
143
144 /* Create the queue */
145 CHECK( 0, fd_fifo_new(&queue) );
146
147 /* Check the count is 0 */
148 CHECK( 0, fd_fifo_length(queue, &count) );
149 CHECK( 0, count);
150
151 /* Now enqueue */
152 msg = msg1;
153 CHECK( 0, fd_fifo_post(queue, &msg) );
154 msg = msg2;
155 CHECK( 0, fd_fifo_post(queue, &msg) );
156 msg = msg3;
157 CHECK( 0, fd_fifo_post(queue, &msg) );
158
159 /* Check the count is 3 */
160 CHECK( 0, fd_fifo_length(queue, &count) );
161 CHECK( 3, count);
162
163 /* Retrieve the first message using fd_fifo_get */
164 CHECK( 0, fd_fifo_get(queue, &msg) );
165 CHECK( msg1, msg);
166 CHECK( 0, fd_fifo_length(queue, &count) );
167 CHECK( 2, count);
168
169 /* Retrieve the second message using fd_fifo_timedget */
170 CHECK(0, clock_gettime(CLOCK_REALTIME, &ts));
171 ts.tv_sec += 1; /* Set the timeout to 1 second */
172 CHECK( 0, fd_fifo_timedget(queue, &msg, &ts) );
173 CHECK( msg2, msg);
174 CHECK( 0, fd_fifo_length(queue, &count) );
175 CHECK( 1, count);
176
177 /* Retrieve the third message using meq_tryget */
178 CHECK( 0, fd_fifo_tryget(queue, &msg) );
179 CHECK( msg3, msg);
180 CHECK( 0, fd_fifo_length(queue, &count) );
181 CHECK( 0, count);
182
183 /* Check that another meq_tryget does not block */
184 CHECK( EWOULDBLOCK, fd_fifo_tryget(queue, &msg) );
185 CHECK( 0, fd_fifo_length(queue, &count) );
186 CHECK( 0, count);
187
188 /* We're done for basic tests */
189 CHECK( 0, fd_fifo_del(&queue) );
190 }
191
192 /* Test robustness, ensure no messages are lost */
193 {
194 #define NBR_MSG 200
195 #define NBR_THREADS 60
196 struct fifo *queue = NULL;
197 pthread_barrier_t bar;
198 struct test_data td_1;
199 struct test_data td_2;
200 struct msg *msgs[NBR_MSG * NBR_THREADS * 2], *msg;
201 pthread_t thr [NBR_THREADS * 2];
202 struct dict_object *dwr_model = NULL;
203 int count;
204 int i;
205
206 /* Create the queue */
207 CHECK( 0, fd_fifo_new(&queue) );
208
209 /* Create the barrier */
210 CHECK( 0, pthread_barrier_init(&bar, NULL, NBR_THREADS * 2 + 1) );
211
212 /* Initialize the ts */
213 CHECK(0, clock_gettime(CLOCK_REALTIME, &ts));
214 ts.tv_sec += 2; /* Set the timeout to 2 second */
215
216 /* Create the messages */
217 CHECK( 0, fd_dict_search ( fd_g_config->g_dict, DICT_COMMAND, CMD_BY_NAME, "Device-Watchdog-Request", &dwr_model, ENOENT ) );
218 for (i = 0; i < NBR_MSG * NBR_THREADS * 2; i++) {
219 CHECK( 0, fd_msg_new ( dwr_model, 0, &msgs[i] ) );
220 }
221
222 /* Initialize the test data structures */
223 td_1.queue = queue;
224 td_1.bar = &bar;
225 td_1.ts = &ts;
226 td_1.nbr = NBR_MSG;
227 td_2.queue = queue;
228 td_2.bar = &bar;
229 td_2.ts = NULL;
230 td_2.nbr = NBR_MSG;
231
232 /* Create the threads */
233 for (i=0; i < NBR_THREADS * 2; i++) {
234 CHECK( 0, pthread_create( &thr[i], NULL, test_fct, (i & 1) ? &td_1 : &td_2 ) );
235 }
236
237 /* Synchronize everyone */
238 {
239 int ret = pthread_barrier_wait(&bar);
240 if (ret != PTHREAD_BARRIER_SERIAL_THREAD) {
241 CHECK( 0, ret);
242 } else {
243 CHECK( PTHREAD_BARRIER_SERIAL_THREAD, ret); /* for trace only */
244 }
245 }
246
247 /* Now post all the messages */
248 for (i=0; i < NBR_MSG * NBR_THREADS * 2; i++) {
249 msg = msgs[i];
250 CHECK( 0, fd_fifo_post(queue, &msg) );
251 }
252
253 /* Join all threads. This blocks if messages are lost... */
254 for (i=0; i < NBR_THREADS * 2; i++) {
255 CHECK( 0, pthread_join( thr[i], NULL ) );
256 }
257
258 /* Check the count of the queue is back to 0 */
259 CHECK( 0, fd_fifo_length(queue, &count) );
260 CHECK( 0, count);
261
262 /* Destroy this queue and the messages */
263 CHECK( 0, fd_fifo_del(&queue) );
264 for (i=0; i < NBR_MSG * NBR_THREADS * 2; i++) {
265 CHECK( 0, fd_msg_free( msgs[i] ) );
266 }
267 }
268
269 /* Test thread cancelation */
270 {
271 struct fifo *queue = NULL;
272 pthread_barrier_t bar;
273 struct test_data td;
274 pthread_t th;
275
276 /* Create the queue */
277 CHECK( 0, fd_fifo_new(&queue) );
278
279 /* Create the barrier */
280 CHECK( 0, pthread_barrier_init(&bar, NULL, 2) );
281
282 /* Initialize the ts */
283 CHECK(0, clock_gettime(CLOCK_REALTIME, &ts));
284 ts.tv_sec += 2; /* Set the timeout to 2 second */
285
286 /* Initialize the test data structures */
287 td.queue = queue;
288 td.bar = &bar;
289 td.ts = &ts;
290 td.nbr = 1;
291
292 /* Create the thread */
293 CHECK( 0, pthread_create( &th, NULL, test_fct, &td ) );
294
295 /* Wait for the thread to be running */
296 {
297 int ret = pthread_barrier_wait(&bar);
298 if (ret != PTHREAD_BARRIER_SERIAL_THREAD) {
299 CHECK( 0, ret);
300 } else {
301 CHECK( PTHREAD_BARRIER_SERIAL_THREAD, ret );
302 }
303 }
304
305 /* Now cancel the thread */
306 CHECK( 0, pthread_cancel( th ) );
307
308 /* Join it */
309 CHECK( 0, pthread_join( th, NULL ) );
310
311 /* Do the same with the other function */
312 td.ts = NULL;
313
314 /* Create the thread */
315 CHECK( 0, pthread_create( &th, NULL, test_fct, &td ) );
316
317 /* Wait for the thread to be running */
318 {
319 int ret = pthread_barrier_wait(&bar);
320 if (ret != PTHREAD_BARRIER_SERIAL_THREAD) {
321 CHECK( 0, ret);
322 } else {
323 CHECK( PTHREAD_BARRIER_SERIAL_THREAD, ret );
324 }
325 }
326
327 /* Now cancel the thread */
328 CHECK( 0, pthread_cancel( th ) );
329
330 /* Join it */
331 CHECK( 0, pthread_join( th, NULL ) );
332
333 /* Destroy the queue */
334 CHECK( 0, fd_fifo_del(&queue) );
335 }
336
337 /* Test the threashold function */
338 {
339 struct fifo * queue = NULL;
340 int i;
341 struct msg * msg = NULL;
342
343 /* Create the queue */
344 CHECK( 0, fd_fifo_new(&queue) );
345
346 /* Prepare the test data */
347 memset(&thrh_td, 0, sizeof(thrh_td));
348 thrh_td.queue = queue;
349
350 /* Set the thresholds for the queue */
351 CHECK( 0, fd_fifo_setthrhd ( queue, NULL, 6, thrh_cb_h, 4, thrh_cb_l ) );
352
353 /* Post 5 messages, no cb must be called. */
354 for (i=0; i<5; i++) {
355 msg = msg1;
356 CHECK( 0, fd_fifo_post(queue, &msg) );
357 } /* 5 msg in queue */
358 CHECK( 0, thrh_td.h_calls );
359 CHECK( 0, thrh_td.l_calls );
360
361 /* Get all these messages, and check again */
362 for (i=0; i<5; i++) {
363 CHECK( 0, fd_fifo_get(queue, &msg) );
364 } /* 0 msg in queue */
365 CHECK( 0, thrh_td.h_calls );
366 CHECK( 0, thrh_td.l_calls );
367
368 /* Now, post 6 messages, the high threashold */
369 for (i=0; i<6; i++) {
370 msg = msg1;
371 CHECK( 0, fd_fifo_post(queue, &msg) );
372 } /* 6 msg in queue */
373 CHECK( 1, thrh_td.h_calls );
374 CHECK( 0, thrh_td.l_calls );
375
376 /* Remove 2 messages, to reach the low threshold */
377 for (i=0; i<2; i++) {
378 CHECK( 0, fd_fifo_get(queue, &msg) );
379 } /* 4 msg in queue */
380 CHECK( 1, thrh_td.h_calls );
381 CHECK( 1, thrh_td.l_calls );
382
383 /* Come again at the high threshold */
384 for (i=0; i<2; i++) {
385 msg = msg1;
386 CHECK( 0, fd_fifo_post(queue, &msg) );
387 } /* 6 msg in queue */
388 CHECK( 2, thrh_td.h_calls );
389 CHECK( 1, thrh_td.l_calls );
390
391 /* Suppose the queue continues to grow */
392 for (i=0; i<6; i++) {
393 msg = msg1;
394 CHECK( 0, fd_fifo_post(queue, &msg) );
395 } /* 12 msg in queue */
396 CHECK( 3, thrh_td.h_calls );
397 CHECK( 1, thrh_td.l_calls );
398 for (i=0; i<5; i++) {
399 msg = msg1;
400 CHECK( 0, fd_fifo_post(queue, &msg) );
401 } /* 17 msg in queue */
402 CHECK( 3, thrh_td.h_calls );
403 CHECK( 1, thrh_td.l_calls );
404
405 /* Now the queue goes back to 0 messages */
406 for (i=0; i<17; i++) {
407 CHECK( 0, fd_fifo_get(queue, &msg) );
408 } /* 0 msg in queue */
409 CHECK( 3, thrh_td.h_calls );
410 CHECK( 3, thrh_td.l_calls );
411
412 /* We're done for this test */
413 CHECK( 0, fd_fifo_del(&queue) );
414 }
415
416 /* Delete the messages */
417 CHECK( 0, fd_msg_free( msg1 ) );
418 CHECK( 0, fd_msg_free( msg2 ) );
419 CHECK( 0, fd_msg_free( msg3 ) );
420
421 /* That's all for the tests yet */
422 PASSTEST();
423 }
"Welcome to our mercurial repository"