1 | /* |
2 | Copyright (c) 2012, Broadcom Europe Ltd |
3 | All rights reserved. |
4 | |
5 | Redistribution and use in source and binary forms, with or without |
6 | modification, are permitted provided that the following conditions are met: |
7 | * Redistributions of source code must retain the above copyright |
8 | notice, this list of conditions and the following disclaimer. |
9 | * Redistributions in binary form must reproduce the above copyright |
10 | notice, this list of conditions and the following disclaimer in the |
11 | documentation and/or other materials provided with the distribution. |
12 | * Neither the name of the copyright holder nor the |
13 | names of its contributors may be used to endorse or promote products |
14 | derived from this software without specific prior written permission. |
15 | |
16 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND |
17 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
18 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
19 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY |
20 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
21 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
22 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
23 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
24 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
25 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
26 | */ |
27 | |
28 | #include <stdio.h> |
29 | #include <stdlib.h> |
30 | #include <string.h> |
31 | |
32 | #include "vchiq_test.h" |
33 | #ifndef USE_VCHIQ_ARM |
34 | #define USE_VCHIQ_ARM |
35 | #endif |
36 | #include "interface/vchi/vchi.h" |
37 | |
38 | #define NUM_BULK_BUFS 2 |
39 | #define BULK_SIZE (1024*256) |
40 | #ifndef PAGE_SIZE |
41 | #define PAGE_SIZE 4096 |
42 | #endif |
43 | |
44 | #define INIT_PARAMS(sp_, fourcc_, cb_, userdata_, ver_) \ |
45 | do { \ |
46 | memset((sp_), 0, sizeof(*(sp_))); \ |
47 | (sp_)->fourcc = fourcc_; \ |
48 | (sp_)->callback = cb_; \ |
49 | (sp_)->userdata = userdata_; \ |
50 | (sp_)->version = ver_; \ |
51 | (sp_)->version_min = ver_; \ |
52 | } while (0) |
53 | |
54 | |
55 | static struct test_params g_params = { MSG_CONFIG, 64, 100, 1, 1, 1, 0, 0, 0, 0 }; |
56 | static const char *g_servname = "echo" ; |
57 | |
58 | static VCOS_EVENT_T g_server_reply; |
59 | static VCOS_EVENT_T g_shutdown; |
60 | static VCOS_MUTEX_T g_mutex; |
61 | |
62 | static const char *g_server_error = NULL; |
63 | |
64 | static volatile int g_sync_mode = 0; |
65 | |
66 | static VCOS_EVENT_T func_test_sync; |
67 | static int want_echo = 1; |
68 | static int func_error = 0; |
69 | static int fun2_error = 0; |
70 | static int func_data_test_start = -1; |
71 | static int func_data_test_end = 0x7fffffff; |
72 | static int func_data_test_iter; |
73 | |
74 | char *bulk_bufs[NUM_BULK_BUFS * 2]; |
75 | char *bulk_tx_data[NUM_BULK_BUFS]; |
76 | char *bulk_rx_data[NUM_BULK_BUFS]; |
77 | |
78 | static int ctrl_received = 0; |
79 | static int bulk_tx_sent = 0; |
80 | static int bulk_rx_sent = 0; |
81 | static int bulk_tx_received = 0; |
82 | static int bulk_rx_received = 0; |
83 | |
84 | static char clnt_service1_data[SERVICE1_DATA_SIZE]; |
85 | static char clnt_service2_data[SERVICE2_DATA_SIZE]; |
86 | |
87 | static VCOS_LOG_CAT_T vchiq_test_log_category; |
88 | |
89 | static int vchiq_test(int argc, char **argv); |
90 | static VCHIQ_STATUS_T vchiq_bulk_test(void); |
91 | static VCHIQ_STATUS_T vchiq_ctrl_test(void); |
92 | static VCHIQ_STATUS_T vchiq_functional_test(void); |
93 | static VCHIQ_STATUS_T vchiq_ping_test(void); |
94 | static VCHIQ_STATUS_T vchiq_signal_test(void); |
95 | |
96 | static VCHIQ_STATUS_T do_functional_test(void); |
97 | static void do_ping_test(VCHIQ_SERVICE_HANDLE_T service, int size, int async, int oneway, int iters); |
98 | static void do_vchi_ping_test(VCHI_SERVICE_HANDLE_T service, int size, int async, int oneway, int iters); |
99 | |
100 | static VCHIQ_STATUS_T func_data_test(VCHIQ_SERVICE_HANDLE_T service, int size, int align, int server_align); |
101 | |
102 | #ifdef VCHIQ_LOCAL |
103 | static void *vchiq_test_server(void *); |
104 | #endif |
105 | |
106 | static VCHIQ_STATUS_T |
107 | clnt_callback(VCHIQ_REASON_T reason, VCHIQ_HEADER_T *, |
108 | VCHIQ_SERVICE_HANDLE_T service, void *bulk_userdata); |
109 | static void |
110 | vchi_clnt_callback(void *callback_param, VCHI_CALLBACK_REASON_T reason, |
111 | void *handle); |
112 | static VCHIQ_STATUS_T func_clnt_callback(VCHIQ_REASON_T reason, VCHIQ_HEADER_T *, |
113 | VCHIQ_SERVICE_HANDLE_T service, void *bulk_userdata); |
114 | static VCHIQ_STATUS_T fun2_clnt_callback(VCHIQ_REASON_T reason, VCHIQ_HEADER_T *, |
115 | VCHIQ_SERVICE_HANDLE_T service, void *bulk_userdata); |
116 | static int mem_check(const void *expected, const void *actual, int size); |
117 | static void usage(void); |
118 | static void check_timer(void); |
119 | static char *buf_align(char *buf, int align_size, int align); |
120 | |
121 | #ifdef ANDROID |
122 | |
123 | static int g_timeout_ms = 0; |
124 | static pid_t main_process_pid; |
125 | static void kill_timeout_handler(int cause, siginfo_t *how, void *ucontext); |
126 | static int setup_auto_kill(int timeout_ms); |
127 | |
128 | #endif |
129 | |
130 | #ifdef __linux__ |
131 | |
132 | #include <fcntl.h> |
133 | #include <sys/ioctl.h> |
134 | #include "interface/vmcs_host/vc_cma.h" |
135 | |
136 | static void reserve_test(int reserve, int delay) |
137 | { |
138 | int fd = open("/dev/vc-cma" , O_RDWR); |
139 | int rc = -1; |
140 | if (fd >= 0) |
141 | { |
142 | rc = ioctl(fd, VC_CMA_IOC_RESERVE, reserve); |
143 | if (rc == 0) |
144 | { |
145 | printf("Sleeping for %d seconds...\n" , delay); |
146 | sleep(delay); |
147 | } |
148 | else |
149 | printf("* failed to ioctl /dev/vc-cma - rc %d\n" , rc); |
150 | close(fd); |
151 | } |
152 | else |
153 | printf("* failed to open /dev/vc-cma - rc %d\n" , fd); |
154 | } |
155 | |
156 | #endif |
157 | |
158 | static int vchiq_test(int argc, char **argv) |
159 | { |
160 | VCHIQ_STATUS_T status; |
161 | int run_bulk_test = 0; |
162 | int run_ctrl_test = 0; |
163 | int run_functional_test = 0; |
164 | int run_ping_test = 0; |
165 | int run_signal_test = 0; |
166 | int verbose = 0; |
167 | int argn; |
168 | |
169 | argn = 1; |
170 | while ((argn < argc) && (argv[argn][0] == '-')) |
171 | { |
172 | const char *arg = argv[argn++]; |
173 | if (strcmp(arg, "-s" ) == 0) |
174 | { |
175 | g_servname = argv[argn++]; |
176 | if (!g_servname || (strlen(g_servname) != 4)) |
177 | { |
178 | usage(); |
179 | } |
180 | } |
181 | else if (strcasecmp(arg, "-a" ) == 0) |
182 | { |
183 | g_params.align_size = (strcmp(arg, "-A" ) == 0) ? 4096 : 32; |
184 | g_params.client_align = atoi(argv[argn++]); |
185 | g_params.server_align = atoi(argv[argn++]); |
186 | } |
187 | else if (strcmp(arg, "-b" ) == 0) |
188 | { |
189 | run_bulk_test = 1; |
190 | g_params.blocksize = atoi(argv[argn++]); |
191 | } |
192 | else if (strcmp(arg, "-c" ) == 0) |
193 | { |
194 | run_ctrl_test = 1; |
195 | g_params.blocksize = atoi(argv[argn++]); |
196 | } |
197 | else if (strcmp(arg, "-e" ) == 0) |
198 | { |
199 | want_echo = 0; |
200 | } |
201 | else if (strcmp(arg, "-f" ) == 0) |
202 | { |
203 | run_functional_test = 1; |
204 | } |
205 | else if (strcmp(arg, "-h" ) == 0) |
206 | { |
207 | usage(); |
208 | } |
209 | else if (strcmp(arg, "-i" ) == 0) |
210 | { |
211 | run_signal_test = 1; |
212 | } |
213 | else if (strcmp(arg, "-m" ) == 0) |
214 | { |
215 | g_params.client_message_quota = atoi(argv[argn++]); |
216 | } |
217 | else if (strcmp(arg, "-M" ) == 0) |
218 | { |
219 | g_params.server_message_quota = atoi(argv[argn++]); |
220 | } |
221 | else if (strcmp(arg, "-p" ) == 0) |
222 | { |
223 | run_ping_test = 1; |
224 | g_params.iters = 1000; |
225 | } |
226 | else if (strcmp(arg, "-q" ) == 0) |
227 | { |
228 | /* coverity[missing_lock : FALSE] - g_server_reply is not used for mutual exclusion */ |
229 | g_params.verify = 0; |
230 | } |
231 | #ifdef __linux__ |
232 | else if (strcmp(arg, "-r" ) == 0) |
233 | { |
234 | int reserve, delay; |
235 | if (argn+1 < argc) |
236 | { |
237 | reserve = atoi(argv[argn++]); |
238 | delay = atoi(argv[argn++]); |
239 | reserve_test(reserve, delay); |
240 | exit(0); |
241 | } |
242 | else |
243 | { |
244 | printf("not enough arguments (-r reserve delay)\n" ); |
245 | exit(-1); |
246 | } |
247 | } |
248 | #endif |
249 | #ifdef ANDROID |
250 | else if (strcmp(arg, "-K" ) == 0) |
251 | { |
252 | if (argn < argc) |
253 | g_timeout_ms = atoi(argv[argn++]); |
254 | else |
255 | { |
256 | printf("not enough arguments (-K timeout)\n" ); |
257 | exit(-1); |
258 | } |
259 | } |
260 | #endif |
261 | else if (strcmp(arg, "-t" ) == 0) |
262 | { |
263 | check_timer(); |
264 | exit(0); |
265 | } |
266 | else if (strcmp(arg, "-v" ) == 0) |
267 | { |
268 | verbose = 1; |
269 | } |
270 | else if (strcmp(arg, "-S" ) == 0) |
271 | { |
272 | func_data_test_start = atoi(argv[argn++]); |
273 | } |
274 | else if (strcmp(arg, "-E" ) == 0) |
275 | { |
276 | func_data_test_end = atoi(argv[argn++]); |
277 | } |
278 | else |
279 | { |
280 | printf("* unknown option '%s'\n" , arg); |
281 | usage(); |
282 | } |
283 | } |
284 | |
285 | if ((run_ctrl_test + run_bulk_test + run_functional_test + run_ping_test + run_signal_test) != 1) |
286 | usage(); |
287 | |
288 | if (argn < argc) |
289 | { |
290 | g_params.iters = atoi(argv[argn++]); |
291 | if (argn != argc) |
292 | { |
293 | usage(); |
294 | } |
295 | } |
296 | |
297 | vcos_log_set_level(VCOS_LOG_CATEGORY, verbose ? VCOS_LOG_TRACE : VCOS_LOG_INFO); |
298 | vcos_log_register("vchiq_test" , VCOS_LOG_CATEGORY); |
299 | |
300 | #ifdef VCHIQ_LOCAL |
301 | { |
302 | static VCOS_THREAD_T server_task; |
303 | void *pointer = NULL; |
304 | int stack_size = 4096; |
305 | |
306 | #if VCOS_CAN_SET_STACK_ADDR |
307 | pointer = malloc(stack_size); |
308 | vcos_demand(pointer); |
309 | #endif |
310 | vcos_thread_create_classic(&server_task, "vchiq_test server" , vchiq_test_server, (void *)0, pointer, stack_size, |
311 | 10 | VCOS_AFFINITY_CPU1, 20, VCOS_START); |
312 | } |
313 | #endif |
314 | |
315 | vcos_event_create(&g_server_reply, "g_server_reply" ); |
316 | vcos_event_create(&g_shutdown, "g_shutdown" ); |
317 | vcos_mutex_create(&g_mutex, "g_mutex" ); |
318 | |
319 | |
320 | status = VCHIQ_ERROR; |
321 | |
322 | if (run_bulk_test) |
323 | status = vchiq_bulk_test(); |
324 | else if (run_ctrl_test) |
325 | status = vchiq_ctrl_test(); |
326 | else if (run_functional_test) |
327 | status = vchiq_functional_test(); |
328 | else if (run_ping_test) |
329 | status = vchiq_ping_test(); |
330 | else if (run_signal_test) |
331 | status = vchiq_signal_test(); |
332 | |
333 | return (status == VCHIQ_SUCCESS) ? 0 : -1; |
334 | } |
335 | |
336 | static VCHIQ_STATUS_T |
337 | vchiq_bulk_test(void) |
338 | { |
339 | VCHIQ_INSTANCE_T vchiq_instance; |
340 | VCHIQ_SERVICE_HANDLE_T vchiq_service; |
341 | VCHIQ_SERVICE_PARAMS_T service_params; |
342 | VCHIQ_ELEMENT_T elements[4]; |
343 | VCHIQ_ELEMENT_T *element; |
344 | int num_bulk_bufs = NUM_BULK_BUFS; |
345 | uint32_t start, end; |
346 | int i; |
347 | |
348 | g_params.blocksize *= 1024; |
349 | |
350 | for (i = 0; i < (NUM_BULK_BUFS * 2); i++) |
351 | { |
352 | bulk_bufs[i] = malloc(g_params.blocksize + BULK_ALIGN_SIZE - 1); |
353 | if (!bulk_bufs[i]) |
354 | { |
355 | printf("* out of memory\n" ); |
356 | while (i > 0) |
357 | { |
358 | free(bulk_bufs[--i]); |
359 | } |
360 | return VCHIQ_ERROR; |
361 | } |
362 | } |
363 | |
364 | for (i = 0; i < NUM_BULK_BUFS; i++) |
365 | { |
366 | int j; |
367 | bulk_tx_data[i] = buf_align(bulk_bufs[i*2 + 0], g_params.align_size, g_params.client_align); |
368 | bulk_rx_data[i] = buf_align(bulk_bufs[i*2 + 1], g_params.align_size, g_params.client_align); |
369 | for (j = 0; j < g_params.blocksize; j+=4) |
370 | { |
371 | *(unsigned int *)(bulk_tx_data[i] + j) = ((0x80 | i) << 24) + j; |
372 | } |
373 | memset(bulk_rx_data[i], 0xff, g_params.blocksize); |
374 | } |
375 | |
376 | #ifdef ANDROID |
377 | if (g_timeout_ms) |
378 | { |
379 | setup_auto_kill(g_timeout_ms); |
380 | } |
381 | #endif |
382 | |
383 | if (vchiq_initialise(&vchiq_instance) != VCHIQ_SUCCESS) |
384 | { |
385 | printf("* failed to open vchiq instance\n" ); |
386 | return VCHIQ_ERROR; |
387 | } |
388 | |
389 | vchiq_connect(vchiq_instance); |
390 | |
391 | memset(&service_params, 0, sizeof(service_params)); |
392 | |
393 | service_params.version = service_params.version_min = VCHIQ_TEST_VER; |
394 | service_params.fourcc = VCHIQ_MAKE_FOURCC(g_servname[0], g_servname[1], g_servname[2], g_servname[3]); |
395 | service_params.callback = clnt_callback; |
396 | service_params.userdata = "clnt userdata" ; |
397 | |
398 | if (vchiq_open_service(vchiq_instance, &service_params, &vchiq_service) != VCHIQ_SUCCESS) |
399 | { |
400 | printf("* failed to open service - already in use?\n" ); |
401 | return VCHIQ_ERROR; |
402 | } |
403 | |
404 | printf("Bulk test - service:%s, block size:%d, iters:%d\n" , g_servname, g_params.blocksize, g_params.iters); |
405 | |
406 | /* coverity[missing_lock : FALSE] - g_server_reply is not used for mutual exclusion */ |
407 | g_params.echo = want_echo; |
408 | element = elements; |
409 | element->data = &g_params; |
410 | element->size = sizeof(g_params); |
411 | element++; |
412 | |
413 | vchiq_queue_message(vchiq_service, elements, element - elements); |
414 | |
415 | vcos_event_wait(&g_server_reply); |
416 | |
417 | if (g_server_error) |
418 | { |
419 | printf("* server error: %s\n" , g_server_error); |
420 | return VCHIQ_ERROR; |
421 | } |
422 | |
423 | if ( num_bulk_bufs > g_params.iters ) |
424 | num_bulk_bufs = g_params.iters; |
425 | |
426 | start = vcos_getmicrosecs(); |
427 | |
428 | vcos_mutex_lock(&g_mutex); |
429 | |
430 | for (i = 0; i < num_bulk_bufs; i++) |
431 | { |
432 | vchiq_queue_bulk_transmit(vchiq_service, bulk_tx_data[i], g_params.blocksize, (void *)i); |
433 | |
434 | vcos_log_trace("vchiq_test: queued bulk tx %d" , i); |
435 | bulk_tx_sent++; |
436 | |
437 | if (g_params.echo) |
438 | { |
439 | vchiq_queue_bulk_receive(vchiq_service, bulk_rx_data[i], g_params.blocksize, (void *)i); |
440 | |
441 | vcos_log_trace("vchiq_test: queued bulk rx %d" , i); |
442 | bulk_rx_sent++; |
443 | } |
444 | } |
445 | |
446 | vcos_mutex_unlock(&g_mutex); |
447 | |
448 | vcos_log_trace("Sent all messages" ); |
449 | |
450 | vcos_log_trace("vchiq_test: waiting for shutdown" ); |
451 | |
452 | vcos_event_wait(&g_shutdown); |
453 | |
454 | end = vcos_getmicrosecs(); |
455 | |
456 | for (i = 0; i < (NUM_BULK_BUFS * 2); i++) |
457 | { |
458 | free(bulk_bufs[i]); |
459 | } |
460 | |
461 | vchiq_remove_service(vchiq_service); |
462 | |
463 | vcos_log_trace("vchiq_test: shutting down" ); |
464 | |
465 | vchiq_shutdown(vchiq_instance); |
466 | |
467 | printf("Elapsed time: %dus per iteration\n" , (end - start) / g_params.iters); |
468 | |
469 | return VCHIQ_SUCCESS; |
470 | } |
471 | |
472 | static VCHIQ_STATUS_T |
473 | vchiq_ctrl_test(void) |
474 | { |
475 | VCHIQ_INSTANCE_T vchiq_instance; |
476 | VCHIQ_SERVICE_HANDLE_T vchiq_service; |
477 | VCHIQ_SERVICE_PARAMS_T service_params; |
478 | uint32_t start, end; |
479 | int i; |
480 | |
481 | ctrl_received = 0; |
482 | if (g_params.blocksize < 4) |
483 | g_params.blocksize = 4; |
484 | |
485 | for (i = 0; i < NUM_BULK_BUFS; i++) |
486 | { |
487 | int j; |
488 | bulk_tx_data[i] = malloc(g_params.blocksize); |
489 | if (!bulk_tx_data[i]) |
490 | { |
491 | printf("* out of memory\n" ); |
492 | return VCHIQ_ERROR; |
493 | } |
494 | *(int *)bulk_tx_data[i] = MSG_ECHO; |
495 | for (j = 4; j < g_params.blocksize; j+=4) |
496 | { |
497 | *(unsigned int *)(bulk_tx_data[i] + j) = ((0x80 | i) << 24) + j; |
498 | } |
499 | } |
500 | |
501 | #ifdef ANDROID |
502 | if (g_timeout_ms) |
503 | { |
504 | setup_auto_kill(g_timeout_ms); |
505 | } |
506 | #endif |
507 | |
508 | if (vchiq_initialise(&vchiq_instance) != VCHIQ_SUCCESS) |
509 | { |
510 | printf("* failed to open vchiq instance\n" ); |
511 | return VCHIQ_ERROR; |
512 | } |
513 | |
514 | vchiq_connect(vchiq_instance); |
515 | |
516 | memset(&service_params, 0, sizeof(service_params)); |
517 | |
518 | service_params.fourcc = VCHIQ_MAKE_FOURCC(g_servname[0], g_servname[1], g_servname[2], g_servname[3]); |
519 | service_params.callback = clnt_callback; |
520 | service_params.userdata = "clnt userdata" ; |
521 | service_params.version = VCHIQ_TEST_VER; |
522 | service_params.version_min = VCHIQ_TEST_VER; |
523 | |
524 | if (vchiq_open_service(vchiq_instance, &service_params, &vchiq_service) != VCHIQ_SUCCESS) |
525 | { |
526 | printf("* failed to open service - already in use?\n" ); |
527 | return VCHIQ_ERROR; |
528 | } |
529 | |
530 | printf("Ctrl test - service:%s, block size:%d, iters:%d\n" , g_servname, g_params.blocksize, g_params.iters); |
531 | |
532 | start = vcos_getmicrosecs(); |
533 | |
534 | for (i = 0; i < g_params.iters; i++) |
535 | { |
536 | VCHIQ_ELEMENT_T element; |
537 | element.data = bulk_tx_data[i % NUM_BULK_BUFS]; |
538 | element.size = g_params.blocksize; |
539 | |
540 | if (vchiq_queue_message(vchiq_service, &element, 1) != VCHIQ_SUCCESS) |
541 | { |
542 | printf("* failed to send a message\n" ); |
543 | goto error_exit; |
544 | } |
545 | if (g_server_error) |
546 | { |
547 | printf("* error - %s\n" , g_server_error); |
548 | goto error_exit; |
549 | } |
550 | } |
551 | |
552 | vcos_log_trace("Sent all messages" ); |
553 | |
554 | if (g_params.echo) |
555 | { |
556 | vcos_log_trace("vchiq_test: waiting for shutdown" ); |
557 | |
558 | vcos_event_wait(&g_shutdown); |
559 | } |
560 | |
561 | if (g_server_error) |
562 | { |
563 | printf("* error - %s\n" , g_server_error); |
564 | goto error_exit; |
565 | } |
566 | |
567 | end = vcos_getmicrosecs(); |
568 | |
569 | vchiq_remove_service(vchiq_service); |
570 | |
571 | vcos_log_trace("vchiq_test: shutting down" ); |
572 | |
573 | vchiq_shutdown(vchiq_instance); |
574 | |
575 | printf("Elapsed time: %dus per iteration\n" , (end - start) / g_params.iters); |
576 | |
577 | return VCHIQ_SUCCESS; |
578 | |
579 | error_exit: |
580 | vchiq_remove_service(vchiq_service); |
581 | vchiq_shutdown(vchiq_instance); |
582 | return VCHIQ_ERROR; |
583 | } |
584 | |
585 | static VCHIQ_STATUS_T |
586 | vchiq_functional_test(void) |
587 | { |
588 | int i; |
589 | printf("Functional test - iters:%d\n" , g_params.iters); |
590 | for (i = 0; i < g_params.iters; i++) |
591 | { |
592 | printf("======== iteration %d ========\n" , i+1); |
593 | |
594 | if (do_functional_test() != VCHIQ_SUCCESS) |
595 | return VCHIQ_ERROR; |
596 | } |
597 | return VCHIQ_SUCCESS; |
598 | } |
599 | |
600 | static VCHIQ_STATUS_T |
601 | vchiq_ping_test(void) |
602 | { |
603 | /* Measure message round trip time for various sizes*/ |
604 | VCHIQ_INSTANCE_T vchiq_instance; |
605 | VCHIQ_SERVICE_HANDLE_T vchiq_service; |
606 | VCHI_SERVICE_HANDLE_T vchi_service; |
607 | SERVICE_CREATION_T service_params; |
608 | VCHIQ_SERVICE_PARAMS_T vchiq_service_params; |
609 | int fourcc; |
610 | |
611 | static int sizes[] = { 0, 1024, 2048, VCHIQ_MAX_MSG_SIZE }; |
612 | unsigned int i; |
613 | |
614 | fourcc = VCHIQ_MAKE_FOURCC(g_servname[0], g_servname[1], g_servname[2], g_servname[3]); |
615 | |
616 | printf("Ping test - service:%s, iters:%d, version %d\n" , g_servname, g_params.iters, VCHIQ_TEST_VER); |
617 | |
618 | #ifdef ANDROID |
619 | if (g_timeout_ms) |
620 | { |
621 | setup_auto_kill(g_timeout_ms); |
622 | } |
623 | #endif |
624 | |
625 | if (vchiq_initialise(&vchiq_instance) != VCHIQ_SUCCESS) |
626 | { |
627 | printf("* failed to open vchiq instance\n" ); |
628 | return VCHIQ_ERROR; |
629 | } |
630 | |
631 | vchiq_connect(vchiq_instance); |
632 | |
633 | memset(&service_params, 0, sizeof(service_params)); |
634 | service_params.version.version = service_params.version.version_min = VCHIQ_TEST_VER; |
635 | service_params.service_id = fourcc; |
636 | service_params.callback = vchi_clnt_callback; |
637 | service_params.callback_param = &vchi_service; |
638 | |
639 | if (vchi_service_open((VCHI_INSTANCE_T)vchiq_instance, &service_params, &vchi_service) != VCHIQ_SUCCESS) |
640 | { |
641 | printf("* failed to open service - already in use?\n" ); |
642 | return VCHIQ_ERROR; |
643 | } |
644 | |
645 | for (i = 0; i < sizeof(sizes)/sizeof(sizes[0]); i++) |
646 | { |
647 | const int iter_count = g_params.iters; |
648 | do_vchi_ping_test(vchi_service, sizes[i], 0, 0, iter_count); |
649 | do_vchi_ping_test(vchi_service, sizes[i], 0, 0, iter_count); |
650 | do_vchi_ping_test(vchi_service, sizes[i], 1, 0, iter_count); |
651 | do_vchi_ping_test(vchi_service, sizes[i], 2, 0, iter_count); |
652 | do_vchi_ping_test(vchi_service, sizes[i], 10, 0, iter_count); |
653 | do_vchi_ping_test(vchi_service, sizes[i], 0, 1, iter_count); |
654 | do_vchi_ping_test(vchi_service, sizes[i], 0, 2, iter_count); |
655 | do_vchi_ping_test(vchi_service, sizes[i], 0, 10, iter_count); |
656 | do_vchi_ping_test(vchi_service, sizes[i], 10, 10, iter_count); |
657 | do_vchi_ping_test(vchi_service, sizes[i], 100, 0, iter_count/10); |
658 | do_vchi_ping_test(vchi_service, sizes[i], 0, 100, iter_count/10); |
659 | do_vchi_ping_test(vchi_service, sizes[i], 100, 100, iter_count/10); |
660 | do_vchi_ping_test(vchi_service, sizes[i], 200, 0, iter_count/10); |
661 | do_vchi_ping_test(vchi_service, sizes[i], 0, 200, iter_count/10); |
662 | do_vchi_ping_test(vchi_service, sizes[i], 200, 200, iter_count/10); |
663 | do_vchi_ping_test(vchi_service, sizes[i], 400, 0, iter_count/20); |
664 | do_vchi_ping_test(vchi_service, sizes[i], 0, 400, iter_count/20); |
665 | do_vchi_ping_test(vchi_service, sizes[i], 400, 400, iter_count/20); |
666 | do_vchi_ping_test(vchi_service, sizes[i], 1000, 0, iter_count/50); |
667 | do_vchi_ping_test(vchi_service, sizes[i], 0, 1000, iter_count/50); |
668 | do_vchi_ping_test(vchi_service, sizes[i], 1000, 1000, iter_count/50); |
669 | } |
670 | |
671 | vchi_service_close(vchi_service); |
672 | |
673 | INIT_PARAMS(&vchiq_service_params, fourcc, clnt_callback, "clnt userdata" , VCHIQ_TEST_VER); |
674 | if (vchiq_open_service(vchiq_instance, &vchiq_service_params, &vchiq_service) != VCHIQ_SUCCESS) |
675 | { |
676 | printf("* failed to open service - already in use?\n" ); |
677 | return VCHIQ_ERROR; |
678 | } |
679 | |
680 | for (i = 0; i < sizeof(sizes)/sizeof(sizes[0]); i++) |
681 | { |
682 | const int iter_count = g_params.iters; |
683 | do_ping_test(vchiq_service, sizes[i], 0, 0, iter_count); |
684 | do_ping_test(vchiq_service, sizes[i], 0, 0, iter_count); |
685 | do_ping_test(vchiq_service, sizes[i], 1, 0, iter_count); |
686 | do_ping_test(vchiq_service, sizes[i], 2, 0, iter_count); |
687 | do_ping_test(vchiq_service, sizes[i], 10, 0, iter_count); |
688 | do_ping_test(vchiq_service, sizes[i], 0, 1, iter_count); |
689 | do_ping_test(vchiq_service, sizes[i], 0, 2, iter_count); |
690 | do_ping_test(vchiq_service, sizes[i], 0, 10, iter_count); |
691 | do_ping_test(vchiq_service, sizes[i], 10, 10, iter_count); |
692 | do_ping_test(vchiq_service, sizes[i], 100, 0, iter_count/10); |
693 | do_ping_test(vchiq_service, sizes[i], 0, 100, iter_count/10); |
694 | do_ping_test(vchiq_service, sizes[i], 100, 100, iter_count/10); |
695 | do_ping_test(vchiq_service, sizes[i], 200, 0, iter_count/10); |
696 | do_ping_test(vchiq_service, sizes[i], 0, 200, iter_count/10); |
697 | do_ping_test(vchiq_service, sizes[i], 200, 200, iter_count/10); |
698 | do_ping_test(vchiq_service, sizes[i], 400, 0, iter_count/20); |
699 | do_ping_test(vchiq_service, sizes[i], 0, 400, iter_count/20); |
700 | do_ping_test(vchiq_service, sizes[i], 400, 400, iter_count/20); |
701 | do_ping_test(vchiq_service, sizes[i], 1000, 0, iter_count/50); |
702 | do_ping_test(vchiq_service, sizes[i], 0, 1000, iter_count/50); |
703 | do_ping_test(vchiq_service, sizes[i], 1000, 1000, iter_count/50); |
704 | } |
705 | |
706 | vchiq_close_service(vchiq_service); |
707 | |
708 | return VCHIQ_SUCCESS; |
709 | } |
710 | |
711 | static VCHIQ_STATUS_T |
712 | vchiq_signal_test(void) |
713 | { |
714 | /* Measure message round trip time for various sizes*/ |
715 | VCHIQ_INSTANCE_T vchiq_instance; |
716 | VCHIQ_SERVICE_HANDLE_T vchiq_service; |
717 | VCHIQ_SERVICE_PARAMS_T vchiq_service_params; |
718 | int fourcc; |
719 | |
720 | static int sizes[] = { 0, 1024, 2048, VCHIQ_MAX_MSG_SIZE }; |
721 | |
722 | fourcc = VCHIQ_MAKE_FOURCC(g_servname[0], g_servname[1], g_servname[2], g_servname[3]); |
723 | |
724 | printf("signal test - service:%s, iters:%d, version %d\n" , g_servname, g_params.iters, VCHIQ_TEST_VER); |
725 | |
726 | #ifdef ANDROID |
727 | if (g_timeout_ms) |
728 | { |
729 | setup_auto_kill(g_timeout_ms); |
730 | } |
731 | #endif |
732 | |
733 | if (vchiq_initialise(&vchiq_instance) != VCHIQ_SUCCESS) |
734 | { |
735 | printf("* failed to open vchiq instance\n" ); |
736 | return VCHIQ_ERROR; |
737 | } |
738 | |
739 | vchiq_connect(vchiq_instance); |
740 | |
741 | INIT_PARAMS(&vchiq_service_params, fourcc, clnt_callback, "clnt userdata" , VCHIQ_TEST_VER); |
742 | if (vchiq_open_service(vchiq_instance, &vchiq_service_params, &vchiq_service) != VCHIQ_SUCCESS) |
743 | { |
744 | printf("* failed to open service - already in use?\n" ); |
745 | return VCHIQ_ERROR; |
746 | } |
747 | |
748 | vchiq_bulk_transmit(vchiq_service, &sizes, 16, 0, VCHIQ_BULK_MODE_BLOCKING); |
749 | |
750 | vchiq_close_service(vchiq_service); |
751 | |
752 | return VCHIQ_SUCCESS; |
753 | } |
754 | |
755 | static VCHIQ_STATUS_T |
756 | do_functional_test(void) |
757 | { |
758 | VCHIQ_ELEMENT_T elements[4]; |
759 | VCHIQ_INSTANCE_T instance; |
760 | VCHIQ_SERVICE_HANDLE_T service, service2, service3; |
761 | VCHIQ_SERVICE_PARAMS_T service_params; |
762 | VCHIQ_CONFIG_T config; |
763 | unsigned int size, i; |
764 | |
765 | vcos_event_create(&func_test_sync, "test_sync" ); |
766 | |
767 | #ifdef ANDROID |
768 | if (g_timeout_ms) |
769 | { |
770 | setup_auto_kill(g_timeout_ms); |
771 | } |
772 | #endif |
773 | |
774 | if (func_data_test_start != -1) |
775 | goto bulk_tests_only; |
776 | |
777 | EXPECT(vchiq_initialise(&instance), VCHIQ_SUCCESS); |
778 | EXPECT(vchiq_get_config(instance, sizeof(config) - 1, &config), VCHIQ_SUCCESS); // too small, but allowed for backwards compatibility |
779 | EXPECT(vchiq_get_config(instance, sizeof(config) + 1, &config), VCHIQ_ERROR); // too large |
780 | EXPECT(vchiq_get_config(instance, sizeof(config), &config), VCHIQ_SUCCESS); // just right |
781 | EXPECT(config.max_msg_size, VCHIQ_MAX_MSG_SIZE); |
782 | |
783 | INIT_PARAMS(&service_params, FUNC_FOURCC, func_clnt_callback, (void *)1, VCHIQ_TEST_VER); |
784 | EXPECT(vchiq_add_service(instance, &service_params, &service), VCHIQ_SUCCESS); |
785 | |
786 | INIT_PARAMS(&service_params, FUNC_FOURCC, func_clnt_callback, (void *)2, VCHIQ_TEST_VER); |
787 | EXPECT(vchiq_add_service(instance, &service_params, &service2), VCHIQ_SUCCESS); |
788 | |
789 | INIT_PARAMS(&service_params, FUNC_FOURCC, clnt_callback, (void *)3, VCHIQ_TEST_VER); |
790 | EXPECT(vchiq_add_service(instance, &service_params, &service3), VCHIQ_ERROR); // callback doesn't match |
791 | |
792 | EXPECT(vchiq_set_service_option(service, VCHIQ_SERVICE_OPTION_AUTOCLOSE, 0), VCHIQ_SUCCESS); |
793 | EXPECT(vchiq_set_service_option(service, VCHIQ_SERVICE_OPTION_AUTOCLOSE, 1), VCHIQ_SUCCESS); |
794 | EXPECT(vchiq_set_service_option(service, 42, 1), VCHIQ_ERROR); // invalid option |
795 | EXPECT(vchiq_remove_service(service), VCHIQ_SUCCESS); |
796 | EXPECT(vchiq_remove_service(service), VCHIQ_ERROR); // service already removed |
797 | EXPECT(vchiq_remove_service(service2), VCHIQ_SUCCESS); |
798 | EXPECT(vchiq_queue_message(service, NULL, 0), VCHIQ_ERROR); // service not valid |
799 | EXPECT(vchiq_set_service_option(service, VCHIQ_SERVICE_OPTION_AUTOCLOSE, 0), VCHIQ_ERROR); // service not valid |
800 | |
801 | INIT_PARAMS(&service_params, FUNC_FOURCC, clnt_callback, (void *)3, VCHIQ_TEST_VER); |
802 | EXPECT(vchiq_add_service(instance, &service_params, &service3), VCHIQ_SUCCESS); |
803 | |
804 | EXPECT(vchiq_queue_message(service, NULL, 0), VCHIQ_ERROR); // service not open |
805 | EXPECT(vchiq_queue_bulk_transmit(service, clnt_service1_data, sizeof(clnt_service1_data), (void *)1), VCHIQ_ERROR); // service not open |
806 | EXPECT(vchiq_queue_bulk_receive(service2, clnt_service2_data, sizeof(clnt_service2_data), (void *)2), VCHIQ_ERROR); // service not open |
807 | EXPECT(vchiq_queue_bulk_receive(service, 0, sizeof(clnt_service1_data), (void *)1), VCHIQ_ERROR); // invalid buffer |
808 | EXPECT(vchiq_shutdown(instance), VCHIQ_SUCCESS); |
809 | EXPECT(vchiq_initialise(&instance), VCHIQ_SUCCESS); |
810 | INIT_PARAMS(&service_params, FUNC_FOURCC, func_clnt_callback, (void*)1, 0); |
811 | EXPECT(vchiq_open_service(instance, &service_params, &service), VCHIQ_ERROR); // not connected |
812 | EXPECT(vchiq_connect(instance), VCHIQ_SUCCESS); |
813 | EXPECT(vchiq_open_service(instance, &service_params, &service), VCHIQ_ERROR); // wrong version number |
814 | memset(&service_params, 0, sizeof(service_params)); |
815 | service_params.fourcc = FUNC_FOURCC; |
816 | service_params.callback = func_clnt_callback; |
817 | service_params.userdata = (void*)1; |
818 | service_params.version = 1; |
819 | service_params.version_min = 1; |
820 | EXPECT(vchiq_open_service(instance, &service_params, &service), VCHIQ_ERROR); // Still the wrong version number |
821 | service_params.version = VCHIQ_TEST_VER + 1; |
822 | service_params.version_min = VCHIQ_TEST_VER + 1; |
823 | EXPECT(vchiq_open_service(instance, &service_params, &service), VCHIQ_ERROR); // Still the wrong version number |
824 | service_params.version = VCHIQ_TEST_VER; |
825 | service_params.version_min = VCHIQ_TEST_VER; |
826 | EXPECT(vchiq_open_service(instance, &service_params, &service), VCHIQ_SUCCESS); // That's better |
827 | |
828 | INIT_PARAMS(&service_params, VCHIQ_MAKE_FOURCC('n','o','n','e'), func_clnt_callback, (void*)2, VCHIQ_TEST_VER); |
829 | EXPECT(vchiq_open_service(instance, &service_params, &service2), VCHIQ_ERROR); // no listener |
830 | INIT_PARAMS(&service_params, FUNC_FOURCC, func_clnt_callback, (void*)2, VCHIQ_TEST_VER); |
831 | EXPECT(vchiq_open_service(instance, &service_params, &service2), VCHIQ_SUCCESS); |
832 | INIT_PARAMS(&service_params, FUNC_FOURCC, func_clnt_callback, (void*)3, VCHIQ_TEST_VER); |
833 | EXPECT(vchiq_open_service(instance, &service_params, &service3), VCHIQ_ERROR); // no more listeners |
834 | EXPECT(vchiq_remove_service(service2), VCHIQ_SUCCESS); |
835 | INIT_PARAMS(&service_params, FUNC_FOURCC, func_clnt_callback, (void*)2, VCHIQ_TEST_VER); |
836 | EXPECT(vchiq_open_service(instance, &service_params, &service2), VCHIQ_SUCCESS); |
837 | |
838 | elements[0].data = "a" ; |
839 | elements[0].size = 1; |
840 | elements[1].data = "bcdef" ; |
841 | elements[1].size = 5; |
842 | elements[2].data = "ghijklmnopq" ; |
843 | elements[2].size = 11; |
844 | elements[3].data = "rstuvwxyz" ; |
845 | elements[3].size = 9; |
846 | EXPECT(vchiq_queue_message(service, elements, 4), VCHIQ_SUCCESS); |
847 | |
848 | EXPECT(vchiq_queue_bulk_transmit(service2, clnt_service2_data, sizeof(clnt_service2_data), (void *)0x2001), VCHIQ_SUCCESS); |
849 | for (i = 0; i < sizeof(clnt_service1_data); i++) |
850 | { |
851 | clnt_service1_data[i] = (char)i; |
852 | } |
853 | EXPECT(vchiq_queue_bulk_transmit(service, clnt_service1_data, sizeof(clnt_service1_data), (void*)0x1001), VCHIQ_SUCCESS); |
854 | |
855 | vcos_event_wait(&func_test_sync); |
856 | EXPECT(func_error, 0); |
857 | EXPECT(vchiq_remove_service(service), VCHIQ_SUCCESS); |
858 | vcos_event_wait(&func_test_sync); |
859 | |
860 | EXPECT(vchiq_shutdown(instance), VCHIQ_SUCCESS); |
861 | |
862 | vcos_event_wait(&func_test_sync); |
863 | EXPECT(func_error, 0); |
864 | |
865 | INIT_PARAMS(&service_params, FUNC_FOURCC, func_clnt_callback, NULL, VCHIQ_TEST_VER); |
866 | EXPECT(vchiq_open_service(instance, &service_params, &service), VCHIQ_ERROR); /* Instance not initialised */ |
867 | EXPECT(vchiq_add_service(instance, &service_params, &service), VCHIQ_ERROR); /* Instance not initialised */ |
868 | EXPECT(vchiq_connect(instance), VCHIQ_ERROR); /* Instance not initialised */ |
869 | |
870 | bulk_tests_only: |
871 | /* Now test the bulk data transfers */ |
872 | EXPECT(vchiq_initialise(&instance), VCHIQ_SUCCESS); |
873 | EXPECT(vchiq_connect(instance), VCHIQ_SUCCESS); |
874 | |
875 | func_data_test_iter = 0; |
876 | |
877 | INIT_PARAMS(&service_params, FUN2_FOURCC, fun2_clnt_callback, NULL, VCHIQ_TEST_VER); |
878 | EXPECT(vchiq_open_service(instance, &service_params, &service), VCHIQ_SUCCESS); |
879 | |
880 | if (func_data_test_end < func_data_test_start) |
881 | goto skip_bulk_tests; |
882 | |
883 | printf("Testing bulk transfer for alignment.\n" ); |
884 | for (size = 1; size < 64; size++) |
885 | { |
886 | int align, srvr_align; |
887 | for (srvr_align = 32; srvr_align; srvr_align >>= 1) |
888 | { |
889 | for (align = 32; align; align >>= 1) |
890 | { |
891 | EXPECT(func_data_test(service, size, align & 31, srvr_align & 31), VCHIQ_SUCCESS); |
892 | } |
893 | } |
894 | } |
895 | |
896 | printf("Testing bulk transfer at PAGE_SIZE.\n" ); |
897 | for (size = 1; size < 64; size++) |
898 | { |
899 | int align, srvr_align; |
900 | for (srvr_align = 32; srvr_align; srvr_align >>= 1) |
901 | { |
902 | for (align = 32; align; align >>= 1) |
903 | { |
904 | EXPECT(func_data_test(service, size, PAGE_SIZE - align, srvr_align & 31), VCHIQ_SUCCESS); |
905 | } |
906 | } |
907 | } |
908 | |
909 | for (size = 64; size < FUN2_MAX_DATA_SIZE; size<<=1) |
910 | { |
911 | static const int aligns[] = { 0, 1, 31 }; |
912 | |
913 | for (i = 0; i < vcos_countof(aligns); i++) |
914 | { |
915 | int srvr_align = aligns[i]; |
916 | unsigned int j; |
917 | for (j = 0; j < vcos_countof(aligns); j++) |
918 | { |
919 | int k; |
920 | int align = aligns[j]; |
921 | for (k = 0; k <= 8; k++) |
922 | { |
923 | EXPECT(func_data_test(service, size, align, srvr_align + k), VCHIQ_SUCCESS); |
924 | } |
925 | } |
926 | } |
927 | } |
928 | |
929 | skip_bulk_tests: |
930 | |
931 | EXPECT(vchiq_shutdown(instance), VCHIQ_SUCCESS); |
932 | |
933 | vcos_event_delete(&func_test_sync); |
934 | |
935 | return VCHIQ_SUCCESS; |
936 | |
937 | error_exit: |
938 | return VCHIQ_ERROR; |
939 | } |
940 | |
941 | static void |
942 | do_ping_test(VCHIQ_SERVICE_HANDLE_T service, int size, int async, int oneway, int iters) |
943 | { |
944 | uint32_t start, end; |
945 | char *ping_buf = malloc(size + sizeof(struct test_params)); |
946 | struct test_params *params = (struct test_params *)ping_buf; |
947 | VCHIQ_ELEMENT_T element; |
948 | int i; |
949 | |
950 | element.data = ping_buf; |
951 | |
952 | /* Set up the quotas for messages */ |
953 | *params = g_params; |
954 | params->magic = MSG_CONFIG; |
955 | params->blocksize = 0; |
956 | element.size = sizeof(*params); |
957 | vchiq_queue_message(service, &element, 1); |
958 | vcos_event_wait(&g_server_reply); |
959 | vchiq_set_service_option(service, VCHIQ_SERVICE_OPTION_MESSAGE_QUOTA, params->client_message_quota); |
960 | |
961 | /* Allow enough room for the type header */ |
962 | element.size = (size < 4) ? 4 : size; |
963 | |
964 | bulk_tx_received = -1; |
965 | |
966 | start = vcos_getmicrosecs(); |
967 | for (i = 0; i < iters; i++) |
968 | { |
969 | int j; |
970 | for (j = 0; j < vcos_max(async, oneway); j++) |
971 | { |
972 | if (j < async) |
973 | { |
974 | params->magic = MSG_ASYNC; |
975 | vchiq_queue_message(service, &element, 1); |
976 | } |
977 | if (j < oneway) |
978 | { |
979 | params->magic = MSG_ONEWAY; |
980 | vchiq_queue_message(service, &element, 1); |
981 | } |
982 | } |
983 | params->magic = MSG_SYNC; |
984 | vchiq_queue_message(service, &element, 1); |
985 | vcos_event_wait(&g_server_reply); |
986 | } |
987 | end = vcos_getmicrosecs(); |
988 | |
989 | printf("ping (size %d, %d async, %d oneway) -> %fus\n" , size, async, oneway, ((float)(end - start))/iters); |
990 | |
991 | vcos_sleep(20); |
992 | |
993 | if ((async == 0) && (oneway == 0)) |
994 | { |
995 | *params = g_params; |
996 | params->magic = MSG_CONFIG; |
997 | params->blocksize = size ? size : 8; |
998 | params->iters = iters; |
999 | params->verify = 0; |
1000 | params->echo = 0; |
1001 | |
1002 | element.size = sizeof(*params); |
1003 | vchiq_queue_message(service, &element, 1); |
1004 | vcos_event_wait(&g_server_reply); |
1005 | |
1006 | vcos_sleep(30); |
1007 | |
1008 | start = vcos_getmicrosecs(); |
1009 | for (i = 0; i < iters; i++) |
1010 | { |
1011 | vchiq_queue_bulk_transmit(service, ping_buf, params->blocksize, 0); |
1012 | vcos_event_wait(&g_server_reply); |
1013 | } |
1014 | end = vcos_getmicrosecs(); |
1015 | |
1016 | printf("bulk (size %d, async) -> %fus\n" , size, ((float)(end - start))/iters); |
1017 | |
1018 | vcos_sleep(40); |
1019 | } |
1020 | |
1021 | if (oneway == 0) |
1022 | { |
1023 | *params = g_params; |
1024 | params->magic = MSG_CONFIG; |
1025 | params->blocksize = size ? size : 8; |
1026 | params->iters = iters * (async + 1); |
1027 | params->verify = 0; |
1028 | params->echo = 0; |
1029 | |
1030 | element.size = sizeof(*params); |
1031 | vchiq_queue_message(service, &element, 1); |
1032 | vcos_event_wait(&g_server_reply); |
1033 | |
1034 | vcos_sleep(50); |
1035 | |
1036 | start = vcos_getmicrosecs(); |
1037 | for (i = 0; i < iters; i++) |
1038 | { |
1039 | int j; |
1040 | for (j = 0; j < async; j++) |
1041 | vchiq_bulk_transmit(service, ping_buf, params->blocksize, 0, VCHIQ_BULK_MODE_NOCALLBACK); |
1042 | vchiq_bulk_transmit(service, ping_buf, params->blocksize, 0, VCHIQ_BULK_MODE_BLOCKING); |
1043 | } |
1044 | end = vcos_getmicrosecs(); |
1045 | |
1046 | printf("bulk (size %d, %d async) -> %fus\n" , size, async, ((float)(end - start))/iters); |
1047 | |
1048 | vcos_sleep(60); |
1049 | } |
1050 | |
1051 | free(ping_buf); |
1052 | |
1053 | bulk_tx_received = 0; |
1054 | } |
1055 | |
1056 | static void |
1057 | do_vchi_ping_test(VCHI_SERVICE_HANDLE_T service, int size, int async, int oneway, int iters) |
1058 | { |
1059 | uint32_t start, end; |
1060 | uint32_t actual; |
1061 | char *ping_buf = malloc(size + sizeof(struct test_params)); |
1062 | char pong_buf[100]; |
1063 | struct test_params *params = (struct test_params *)ping_buf; |
1064 | int msg_size; |
1065 | int i; |
1066 | |
1067 | /* Set up the quotas for messages */ |
1068 | *params = g_params; |
1069 | params->magic = MSG_CONFIG; |
1070 | params->blocksize = 0; |
1071 | vchi_msg_queue(service, params, sizeof(*params), VCHI_FLAGS_BLOCK_UNTIL_QUEUED, 0); |
1072 | vcos_event_wait(&g_server_reply); |
1073 | vchiq_set_service_option((VCHIQ_SERVICE_HANDLE_T)service, VCHIQ_SERVICE_OPTION_MESSAGE_QUOTA, params->client_message_quota); |
1074 | |
1075 | /* Allow enough room for the type header */ |
1076 | msg_size = (size < 4) ? 4 : size; |
1077 | |
1078 | bulk_tx_received = -1; |
1079 | |
1080 | if ((oneway == 0) && (async == 0)) |
1081 | { |
1082 | params->magic = MSG_SYNC; |
1083 | |
1084 | g_sync_mode = 1; |
1085 | |
1086 | start = vcos_getmicrosecs(); |
1087 | for (i = 0; i < iters; i++) |
1088 | { |
1089 | vchi_msg_queue(service, ping_buf, msg_size, VCHI_FLAGS_BLOCK_UNTIL_QUEUED, 0); |
1090 | vchi_msg_dequeue(service, pong_buf, sizeof(pong_buf), &actual, VCHI_FLAGS_BLOCK_UNTIL_OP_COMPLETE); |
1091 | } |
1092 | end = vcos_getmicrosecs(); |
1093 | |
1094 | printf("vchi ping (size %d) -> %fus\n" , size, ((float)(end - start))/iters); |
1095 | |
1096 | vcos_sleep(10); |
1097 | |
1098 | g_sync_mode = 0; |
1099 | } |
1100 | |
1101 | while (vchi_msg_dequeue(service, pong_buf, sizeof(pong_buf), &actual, VCHI_FLAGS_NONE) != -1) |
1102 | { |
1103 | printf("* Unexpected message found in queue - size %d\n" , actual); |
1104 | } |
1105 | |
1106 | start = vcos_getmicrosecs(); |
1107 | for (i = 0; i < iters; i++) |
1108 | { |
1109 | int j; |
1110 | for (j = 0; j < vcos_max(async, oneway); j++) |
1111 | { |
1112 | if (j < async) |
1113 | { |
1114 | params->magic = MSG_ASYNC; |
1115 | vchi_msg_queue(service, ping_buf, msg_size, VCHI_FLAGS_BLOCK_UNTIL_QUEUED, 0); |
1116 | } |
1117 | if (j < oneway) |
1118 | { |
1119 | params->magic = MSG_ONEWAY; |
1120 | vchi_msg_queue(service, ping_buf, msg_size, VCHI_FLAGS_BLOCK_UNTIL_QUEUED, 0); |
1121 | } |
1122 | } |
1123 | params->magic = MSG_SYNC; |
1124 | vchi_msg_queue(service, ping_buf, msg_size, VCHI_FLAGS_BLOCK_UNTIL_QUEUED, 0); |
1125 | vcos_event_wait(&g_server_reply); |
1126 | } |
1127 | end = vcos_getmicrosecs(); |
1128 | |
1129 | printf("vchi ping (size %d, %d async, %d oneway) -> %fus\n" , size, async, oneway, ((float)(end - start))/iters); |
1130 | |
1131 | vcos_sleep(20); |
1132 | |
1133 | if ((async == 0) && (oneway == 0)) |
1134 | { |
1135 | *params = g_params; |
1136 | params->magic = MSG_CONFIG; |
1137 | params->blocksize = size ? size : 8; |
1138 | params->iters = iters; |
1139 | params->verify = 0; |
1140 | params->echo = 0; |
1141 | |
1142 | vchi_msg_queue(service, params, sizeof(*params), VCHI_FLAGS_BLOCK_UNTIL_QUEUED, 0); |
1143 | vcos_event_wait(&g_server_reply); |
1144 | |
1145 | vcos_sleep(30); |
1146 | |
1147 | start = vcos_getmicrosecs(); |
1148 | for (i = 0; i < iters; i++) |
1149 | { |
1150 | vchi_bulk_queue_transmit(service, ping_buf, params->blocksize, |
1151 | VCHI_FLAGS_CALLBACK_WHEN_OP_COMPLETE | VCHI_FLAGS_BLOCK_UNTIL_QUEUED, 0); |
1152 | vcos_event_wait(&g_server_reply); |
1153 | } |
1154 | end = vcos_getmicrosecs(); |
1155 | |
1156 | printf("vchi bulk (size %d, %d async, %d oneway) -> %fus\n" , size, async, oneway, ((float)(end - start))/iters); |
1157 | |
1158 | vcos_sleep(40); |
1159 | } |
1160 | |
1161 | if (oneway == 0) |
1162 | { |
1163 | *params = g_params; |
1164 | params->magic = MSG_CONFIG; |
1165 | params->blocksize = size ? size : 8; |
1166 | params->iters = iters * (async + 1); |
1167 | params->verify = 0; |
1168 | params->echo = 0; |
1169 | |
1170 | vchi_msg_queue(service, params, sizeof(*params), VCHI_FLAGS_BLOCK_UNTIL_QUEUED, 0); |
1171 | vcos_event_wait(&g_server_reply); |
1172 | |
1173 | vcos_sleep(50); |
1174 | |
1175 | start = vcos_getmicrosecs(); |
1176 | for (i = 0; i < iters; i++) |
1177 | { |
1178 | int j; |
1179 | for (j = 0; j < async; j++) |
1180 | vchi_bulk_queue_transmit(service, ping_buf, params->blocksize, VCHI_FLAGS_NONE, 0); |
1181 | vchi_bulk_queue_transmit(service, ping_buf, params->blocksize, VCHI_FLAGS_BLOCK_UNTIL_DATA_READ, 0); |
1182 | } |
1183 | end = vcos_getmicrosecs(); |
1184 | |
1185 | printf("vchi bulk (size %d, %d oneway) -> %fus\n" , size, oneway, ((float)(end - start))/iters); |
1186 | |
1187 | vcos_sleep(60); |
1188 | } |
1189 | |
1190 | free(ping_buf); |
1191 | |
1192 | bulk_tx_received = 0; |
1193 | } |
1194 | |
1195 | static VCHIQ_STATUS_T |
1196 | func_data_test(VCHIQ_SERVICE_HANDLE_T service, int datalen, int align, int server_align) |
1197 | { |
1198 | enum { PROLOGUE_SIZE = 32, EPILOGUE_SIZE = 32 }; |
1199 | static uint8_t databuf[PAGE_SIZE + PROLOGUE_SIZE + FUN2_MAX_DATA_SIZE + EPILOGUE_SIZE]; |
1200 | static uint8_t databuf2[PAGE_SIZE + PROLOGUE_SIZE + FUN2_MAX_DATA_SIZE + EPILOGUE_SIZE]; |
1201 | uint8_t *data, *data2, *prologue, *epilogue; |
1202 | VCHIQ_ELEMENT_T element; |
1203 | int params[4] = { datalen, server_align, align, func_data_test_iter }; |
1204 | int success = 1, i; |
1205 | |
1206 | if (!vcos_verify(datalen < FUN2_MAX_DATA_SIZE)) |
1207 | return VCHIQ_ERROR; |
1208 | |
1209 | if ((func_data_test_iter < func_data_test_start) || (func_data_test_iter > func_data_test_end)) |
1210 | goto skip_iter; |
1211 | |
1212 | element.size = sizeof(params); |
1213 | element.data = ¶ms; |
1214 | EXPECT(vchiq_queue_message(service, &element, 1), VCHIQ_SUCCESS); |
1215 | |
1216 | memset(databuf, 0xff, sizeof(databuf)); |
1217 | data = (uint8_t *)((uintptr_t)databuf & ~(PAGE_SIZE - 1)) + align; |
1218 | data = (uint8_t *)((((intptr_t)databuf + PROLOGUE_SIZE) & ~(FUN2_MAX_ALIGN - 1)) + align - PROLOGUE_SIZE); |
1219 | if (data < databuf) |
1220 | data += PAGE_SIZE; |
1221 | data += PROLOGUE_SIZE; |
1222 | |
1223 | EXPECT(vchiq_queue_bulk_receive(service, data, datalen, NULL), VCHIQ_SUCCESS); |
1224 | |
1225 | data2 = (uint8_t *)(((uintptr_t)databuf2 + PROLOGUE_SIZE) & ~(PAGE_SIZE - 1)) + align - PROLOGUE_SIZE; |
1226 | if (data2 < databuf2) |
1227 | data2 += PAGE_SIZE; |
1228 | prologue = data2; |
1229 | data2 += PROLOGUE_SIZE; |
1230 | epilogue = data2 + datalen; |
1231 | |
1232 | memset(prologue, 0xff, PROLOGUE_SIZE); |
1233 | memset(epilogue, 0xff, EPILOGUE_SIZE); |
1234 | |
1235 | for (i = 0; i < (datalen - 1); i++) |
1236 | { |
1237 | data2[i] = (uint8_t)(((i & 0x1f) == 0) ? (i >> 5) : i); |
1238 | } |
1239 | data2[i] = '\0'; |
1240 | |
1241 | /* Attempt to pull the boundaries into the cache */ |
1242 | prologue = data - PROLOGUE_SIZE; |
1243 | epilogue = data + datalen; |
1244 | prologue[PROLOGUE_SIZE - 1] = 0xfe; |
1245 | epilogue[0] = 0xfe; |
1246 | |
1247 | EXPECT(vchiq_queue_bulk_transmit(service, data2, datalen, NULL), VCHIQ_SUCCESS); |
1248 | vcos_event_wait(&func_test_sync); /* Wait for the receive to complete */ |
1249 | |
1250 | for (i = 0; i < PROLOGUE_SIZE; i++) |
1251 | { |
1252 | if (prologue[i] != (uint8_t)((i == PROLOGUE_SIZE - 1) ? '\xfe' : '\xff')) |
1253 | { |
1254 | vcos_log_error("%d: Prologue corrupted at %x (datalen %x, align %x, server_align %x) -> %02x" , func_data_test_iter, i, datalen, align, server_align, prologue[i]); |
1255 | VCOS_BKPT; |
1256 | success = 0; |
1257 | break; |
1258 | } |
1259 | } |
1260 | for (i = 0; i < EPILOGUE_SIZE; i++) |
1261 | { |
1262 | if (epilogue[i] != (uint8_t)((i == 0) ? '\xfe' : '\xff')) |
1263 | { |
1264 | vcos_log_error("%d: Epilogue corrupted at %x (datalen %x, align %x, server_align %x) -> %02x" , func_data_test_iter, i, datalen, align, server_align, epilogue[i]); |
1265 | VCOS_BKPT; |
1266 | success = 0; |
1267 | break; |
1268 | } |
1269 | } |
1270 | |
1271 | if (success) |
1272 | { |
1273 | int diffs = 0; |
1274 | for (i = 0; i < datalen; i++) |
1275 | { |
1276 | int diff = (i == datalen - 1) ? |
1277 | (data[i] != 0) : |
1278 | ((i & 0x1f) == 0) ? |
1279 | (data[i] != (uint8_t)(i >> 5)) : |
1280 | (data[i] != (uint8_t)i); |
1281 | |
1282 | if (diff) |
1283 | diffs++; |
1284 | else if (diffs) |
1285 | { |
1286 | vcos_log_error("%d: Data corrupted at %x-%x (datalen %x, align %x, server_align %x) -> %02x" , func_data_test_iter, i - diffs, i - 1, datalen, align, server_align, data[i-1]); |
1287 | VCOS_BKPT; |
1288 | success = 0; |
1289 | diffs = 0; |
1290 | } |
1291 | } |
1292 | if (diffs) |
1293 | { |
1294 | vcos_log_error("%d: Data corrupted at %x-%x (datalen %x, align %x, server_align %x) -> %02x" , func_data_test_iter, i - diffs, i - 1, datalen, align, server_align, data[i-1]); |
1295 | VCOS_BKPT; |
1296 | success = 0; |
1297 | } |
1298 | } |
1299 | |
1300 | skip_iter: |
1301 | if (success) |
1302 | { |
1303 | func_data_test_iter++; |
1304 | return VCHIQ_SUCCESS; |
1305 | } |
1306 | |
1307 | error_exit: |
1308 | return VCHIQ_ERROR; |
1309 | } |
1310 | |
1311 | |
1312 | #ifdef VCHIQ_LOCAL |
1313 | |
1314 | static void *vchiq_test_server(void *param) |
1315 | { |
1316 | VCHIQ_INSTANCE_T instance; |
1317 | |
1318 | vcos_demand(vchiq_initialise(&instance) == VCHIQ_SUCCESS); |
1319 | vchiq_test_start_services(instance); |
1320 | vchiq_connect(instance); |
1321 | printf("test server started\n" ); |
1322 | return 0; |
1323 | } |
1324 | |
1325 | #endif |
1326 | |
1327 | static VCHIQ_STATUS_T |
1328 | clnt_callback(VCHIQ_REASON_T reason, VCHIQ_HEADER_T *, |
1329 | VCHIQ_SERVICE_HANDLE_T service, void *bulk_userdata) |
1330 | { |
1331 | int data; |
1332 | vcos_mutex_lock(&g_mutex); |
1333 | if (reason == VCHIQ_MESSAGE_AVAILABLE) |
1334 | { |
1335 | /* |
1336 | * Store the header size as it is going to be released |
1337 | * and the size may be overwritten by the release. |
1338 | */ |
1339 | size_t = header->size; |
1340 | |
1341 | if (header_size <= 1) |
1342 | vchiq_release_message(service, header); |
1343 | else |
1344 | /* Responses of length 0 are not sync points */ |
1345 | if ((header_size >= 4) && (memcpy(&data, header->data, sizeof(data)), data == MSG_ECHO)) |
1346 | { |
1347 | /* This is a complete echoed packet */ |
1348 | if (g_params.verify && (mem_check(header->data, bulk_tx_data[ctrl_received % NUM_BULK_BUFS], g_params.blocksize) != 0)) |
1349 | g_server_error = "corrupt data" ; |
1350 | else |
1351 | ctrl_received++; |
1352 | if (g_server_error || (ctrl_received == g_params.iters)) |
1353 | vcos_event_signal(&g_shutdown); |
1354 | vchiq_release_message(service, header); |
1355 | } |
1356 | else if (header_size != 0) |
1357 | g_server_error = header->data; |
1358 | |
1359 | if ((header_size != 0) || g_server_error) |
1360 | vcos_event_signal(&g_server_reply); |
1361 | } |
1362 | else if (reason == VCHIQ_BULK_TRANSMIT_DONE) |
1363 | { |
1364 | int i = (int)bulk_userdata; |
1365 | vcos_log_trace(" BULK_TRANSMIT_DONE(%d)" , i); |
1366 | if (bulk_tx_received < 0) |
1367 | vcos_event_signal(&g_server_reply); |
1368 | else |
1369 | { |
1370 | vcos_assert(i == bulk_tx_received); |
1371 | bulk_tx_received++; |
1372 | if (bulk_tx_sent < g_params.iters) |
1373 | { |
1374 | vchiq_queue_bulk_transmit(service, bulk_tx_data[i % NUM_BULK_BUFS], g_params.blocksize, (void *)bulk_tx_sent); |
1375 | bulk_tx_sent++; |
1376 | } |
1377 | } |
1378 | } |
1379 | else if (reason == VCHIQ_BULK_RECEIVE_DONE) |
1380 | { |
1381 | int i = (int)bulk_userdata; |
1382 | vcos_log_trace(" BULK_RECEIVE_DONE(%d): data '%s'" , i, bulk_rx_data[i % NUM_BULK_BUFS]); |
1383 | vcos_assert(i == bulk_rx_received); |
1384 | if (g_params.verify && (mem_check(bulk_tx_data[i % NUM_BULK_BUFS], bulk_rx_data[i % NUM_BULK_BUFS], g_params.blocksize) != 0)) |
1385 | { |
1386 | vcos_log_error("* Data corruption - %d: %x, %x, %x" , i, (unsigned int)bulk_tx_data[i % NUM_BULK_BUFS], (unsigned int)bulk_rx_data[i % NUM_BULK_BUFS], g_params.blocksize); |
1387 | VCOS_BKPT; |
1388 | } |
1389 | bulk_rx_received++; |
1390 | if (bulk_rx_sent < g_params.iters) |
1391 | { |
1392 | if (g_params.verify) |
1393 | memset(bulk_rx_data[i % NUM_BULK_BUFS], 0xff, g_params.blocksize); |
1394 | vchiq_queue_bulk_receive(service, bulk_rx_data[i % NUM_BULK_BUFS], g_params.blocksize, (void *)bulk_rx_sent); |
1395 | bulk_rx_sent++; |
1396 | } |
1397 | } |
1398 | else if (reason == VCHIQ_BULK_TRANSMIT_ABORTED) |
1399 | { |
1400 | int i = (int)bulk_userdata; |
1401 | vcos_log_info(" BULK_TRANSMIT_ABORTED(%d)" , i); |
1402 | } |
1403 | else if (reason == VCHIQ_BULK_RECEIVE_ABORTED) |
1404 | { |
1405 | int i = (int)bulk_userdata; |
1406 | vcos_log_info(" BULK_RECEIVE_ABORTED(%d)" , i); |
1407 | } |
1408 | if ((bulk_tx_received == g_params.iters) && |
1409 | ((g_params.echo == 0) || (bulk_rx_received == g_params.iters))) |
1410 | vcos_event_signal(&g_shutdown); |
1411 | vcos_mutex_unlock(&g_mutex); |
1412 | return VCHIQ_SUCCESS; |
1413 | } |
1414 | |
1415 | static void |
1416 | vchi_clnt_callback(void *callback_param, |
1417 | VCHI_CALLBACK_REASON_T reason, |
1418 | void *handle) |
1419 | { |
1420 | VCHI_SERVICE_HANDLE_T service = *(VCHI_SERVICE_HANDLE_T *)callback_param; |
1421 | vcos_mutex_lock(&g_mutex); |
1422 | if (reason == VCHI_CALLBACK_MSG_AVAILABLE) |
1423 | { |
1424 | if (!g_sync_mode) |
1425 | { |
1426 | static char pong_buf[100]; |
1427 | uint32_t actual; |
1428 | while (vchi_msg_dequeue(service, pong_buf, sizeof(pong_buf), &actual, VCHI_FLAGS_NONE) == 0) |
1429 | { |
1430 | if (actual > 1) |
1431 | g_server_error = pong_buf; |
1432 | if (actual != 0) |
1433 | { |
1434 | /* Responses of length 0 are not sync points */ |
1435 | vcos_event_signal(&g_server_reply); |
1436 | break; |
1437 | } |
1438 | } |
1439 | } |
1440 | } |
1441 | else if (reason == VCHI_CALLBACK_BULK_SENT) |
1442 | { |
1443 | int i = (int)handle; |
1444 | vcos_log_trace(" BULK_TRANSMIT_DONE(%d)" , i); |
1445 | if (bulk_tx_received < 0) |
1446 | vcos_event_signal(&g_server_reply); |
1447 | else |
1448 | { |
1449 | vcos_assert(i == bulk_tx_received); |
1450 | bulk_tx_received++; |
1451 | if (bulk_tx_sent < g_params.iters) |
1452 | { |
1453 | vchi_bulk_queue_transmit(service, bulk_tx_data[i % NUM_BULK_BUFS], |
1454 | g_params.blocksize, |
1455 | VCHI_FLAGS_CALLBACK_WHEN_OP_COMPLETE | VCHI_FLAGS_BLOCK_UNTIL_QUEUED, |
1456 | (void *)bulk_tx_sent); |
1457 | bulk_tx_sent++; |
1458 | } |
1459 | } |
1460 | } |
1461 | else if (reason == VCHI_CALLBACK_BULK_RECEIVED) |
1462 | { |
1463 | int i = (int)handle; |
1464 | vcos_log_trace(" BULK_RECEIVE_DONE(%d): data '%s'" , i, bulk_rx_data[i % NUM_BULK_BUFS]); |
1465 | vcos_assert(i == bulk_rx_received); |
1466 | if (g_params.verify && (mem_check(bulk_tx_data[i % NUM_BULK_BUFS], bulk_rx_data[i % NUM_BULK_BUFS], g_params.blocksize) != 0)) |
1467 | { |
1468 | vcos_log_error("* Data corruption - %x, %x, %x" , (unsigned int)bulk_tx_data[i % NUM_BULK_BUFS], (unsigned int)bulk_rx_data[i % NUM_BULK_BUFS], g_params.blocksize); |
1469 | VCOS_BKPT; |
1470 | } |
1471 | bulk_rx_received++; |
1472 | if (bulk_rx_sent < g_params.iters) |
1473 | { |
1474 | if (g_params.verify) |
1475 | memset(bulk_rx_data[i % NUM_BULK_BUFS], 0xff, g_params.blocksize); |
1476 | vchi_bulk_queue_receive(service, bulk_rx_data[i % NUM_BULK_BUFS], g_params.blocksize, |
1477 | VCHI_FLAGS_CALLBACK_WHEN_OP_COMPLETE | VCHI_FLAGS_BLOCK_UNTIL_QUEUED, |
1478 | (void *)bulk_rx_sent); |
1479 | bulk_rx_sent++; |
1480 | } |
1481 | } |
1482 | else if (reason == VCHI_CALLBACK_BULK_TRANSMIT_ABORTED) |
1483 | { |
1484 | int i = (int)handle; |
1485 | vcos_log_info(" BULK_TRANSMIT_ABORTED(%d)" , i); |
1486 | } |
1487 | else if (reason == VCHI_CALLBACK_BULK_RECEIVE_ABORTED) |
1488 | { |
1489 | int i = (int)handle; |
1490 | vcos_log_info(" BULK_RECEIVE_ABORTED(%d)" , i); |
1491 | } |
1492 | if ((bulk_tx_received == g_params.iters) && (bulk_rx_received == g_params.iters)) |
1493 | vcos_event_signal(&g_shutdown); |
1494 | vcos_mutex_unlock(&g_mutex); |
1495 | } |
1496 | |
1497 | static VCHIQ_STATUS_T |
1498 | func_clnt_callback(VCHIQ_REASON_T reason, VCHIQ_HEADER_T *, |
1499 | VCHIQ_SERVICE_HANDLE_T service, void *bulk_userdata) |
1500 | { |
1501 | static int callback_count = 0, bulk_count = 0; |
1502 | int callback_index = 0, bulk_index = 0; |
1503 | |
1504 | if (reason < VCHIQ_BULK_TRANSMIT_DONE) |
1505 | { |
1506 | callback_count++; |
1507 | |
1508 | START_CALLBACK(VCHIQ_SERVICE_CLOSED, 2) |
1509 | END_CALLBACK(VCHIQ_SUCCESS) |
1510 | |
1511 | START_CALLBACK(VCHIQ_MESSAGE_AVAILABLE, 1) |
1512 | EXPECT(bulk_userdata, NULL); |
1513 | EXPECT(header->size, 26); |
1514 | EXPECT(mem_check(header->data, "abcdefghijklmnopqrstuvwxyz" , 26), 0); |
1515 | vchiq_release_message(service, header); |
1516 | END_CALLBACK(VCHIQ_SUCCESS) |
1517 | |
1518 | START_CALLBACK(VCHIQ_MESSAGE_AVAILABLE, 1) |
1519 | EXPECT(bulk_userdata, NULL); |
1520 | EXPECT(header->size, 0); |
1521 | vchiq_release_message(service, header); |
1522 | EXPECT(vchiq_queue_bulk_receive(service, clnt_service2_data, sizeof(clnt_service2_data), (void*)0x1004), VCHIQ_SUCCESS); |
1523 | vcos_event_signal(&func_test_sync); |
1524 | END_CALLBACK(VCHIQ_SUCCESS) |
1525 | |
1526 | START_CALLBACK(VCHIQ_SERVICE_CLOSED, 1) |
1527 | vcos_event_signal(&func_test_sync); |
1528 | END_CALLBACK(VCHIQ_SUCCESS) |
1529 | |
1530 | START_CALLBACK(VCHIQ_SERVICE_CLOSED, 2) |
1531 | vcos_event_signal(&func_test_sync); |
1532 | callback_count = 0; |
1533 | bulk_count = 0; |
1534 | END_CALLBACK(VCHIQ_SUCCESS) |
1535 | } |
1536 | else |
1537 | { |
1538 | bulk_count++; |
1539 | |
1540 | START_BULK_CALLBACK(VCHIQ_BULK_TRANSMIT_DONE, 1, 0x1001) |
1541 | memset(clnt_service2_data, 0xff, sizeof(clnt_service2_data)); |
1542 | EXPECT(vchiq_queue_bulk_receive(service, clnt_service2_data, sizeof(clnt_service2_data), (void*)0x1002), VCHIQ_SUCCESS); |
1543 | END_CALLBACK(VCHIQ_SUCCESS) |
1544 | |
1545 | START_BULK_CALLBACK(VCHIQ_BULK_RECEIVE_ABORTED, 1, 0x1002) |
1546 | EXPECT(vchiq_queue_bulk_receive(service, clnt_service2_data, sizeof(clnt_service2_data), (void*)0x1003), VCHIQ_SUCCESS); |
1547 | END_CALLBACK(VCHIQ_SUCCESS) |
1548 | |
1549 | START_BULK_CALLBACK(VCHIQ_BULK_RECEIVE_DONE, 1, 0x1003) |
1550 | (void)(mem_check(clnt_service1_data, clnt_service2_data, sizeof(clnt_service1_data)), 0); |
1551 | (void)(mem_check(clnt_service1_data, clnt_service2_data + sizeof(clnt_service1_data), sizeof(clnt_service1_data)), 0); |
1552 | END_CALLBACK(VCHIQ_SUCCESS) |
1553 | |
1554 | START_BULK_CALLBACK(VCHIQ_BULK_RECEIVE_ABORTED, 1, 0x1004) |
1555 | END_CALLBACK(VCHIQ_SUCCESS) |
1556 | |
1557 | START_BULK_CALLBACK(VCHIQ_BULK_TRANSMIT_ABORTED, 2, 0x2001) |
1558 | END_CALLBACK(VCHIQ_SUCCESS) |
1559 | } |
1560 | |
1561 | error_exit: |
1562 | callback_count = 0; |
1563 | bulk_count = 0; |
1564 | |
1565 | func_error = 1; |
1566 | vcos_event_signal(&func_test_sync); |
1567 | |
1568 | return VCHIQ_ERROR; |
1569 | } |
1570 | |
1571 | static VCHIQ_STATUS_T |
1572 | fun2_clnt_callback(VCHIQ_REASON_T reason, VCHIQ_HEADER_T *, |
1573 | VCHIQ_SERVICE_HANDLE_T service, void *bulk_userdata) |
1574 | { |
1575 | vcos_unused(header); |
1576 | vcos_unused(service); |
1577 | vcos_unused(bulk_userdata); |
1578 | |
1579 | switch (reason) |
1580 | { |
1581 | case VCHIQ_SERVICE_OPENED: |
1582 | case VCHIQ_SERVICE_CLOSED: |
1583 | case VCHIQ_BULK_TRANSMIT_DONE: |
1584 | break; |
1585 | case VCHIQ_BULK_RECEIVE_DONE: |
1586 | vcos_event_signal(&func_test_sync); |
1587 | break; |
1588 | default: |
1589 | fun2_error = 1; |
1590 | vcos_event_signal(&func_test_sync); |
1591 | break; |
1592 | } |
1593 | |
1594 | return VCHIQ_SUCCESS; |
1595 | } |
1596 | |
1597 | static int mem_check(const void *expected, const void *actual, int size) |
1598 | { |
1599 | if (memcmp(expected, actual, size) != 0) |
1600 | { |
1601 | int i; |
1602 | for (i = 0; i < size; i++) |
1603 | { |
1604 | int ce = ((const char *)expected)[i]; |
1605 | int ca = ((const char *)actual)[i]; |
1606 | if (ca != ce) |
1607 | printf("%08x,%x: %02x <-> %02x\n" , i + (unsigned int)actual, i, ce, ca); |
1608 | } |
1609 | printf("mem_check failed - buffer %x, size %d\n" , (unsigned int)actual, size); |
1610 | return 1; |
1611 | } |
1612 | return 0; |
1613 | } |
1614 | |
1615 | static void usage(void) |
1616 | { |
1617 | printf("Usage: vchiq_test [<options>] <mode> <iters>\n" ); |
1618 | printf(" where <options> is any of:\n" ); |
1619 | printf(" -a <c> <s> set the client and server bulk alignment (modulo 32)\n" ); |
1620 | printf(" -A <c> <s> set the client and server bulk alignment (modulo 4096)\n" ); |
1621 | printf(" -e disable echoing in the main bulk transfer mode\n" ); |
1622 | printf(" -k <n> skip the first <n> func data tests\n" ); |
1623 | printf(" -m <n> set the client message quota to <n>\n" ); |
1624 | printf(" -M <n> set the server message quota to <n>\n" ); |
1625 | printf(" -q disable data verification\n" ); |
1626 | printf(" -s ???? service (any 4 characters)\n" ); |
1627 | printf(" -v enable more verbose output\n" ); |
1628 | printf(" -r <b> <s> reserve <b> bytes for <s> seconds\n" ); |
1629 | printf(" -K <t> send a SIGKILL after <t> ms\n" ); |
1630 | printf(" and <mode> is one of:\n" ); |
1631 | printf(" -c <size> control test (size in bytes)\n" ); |
1632 | printf(" -b <size> bulk test (size in kilobytes)\n" ); |
1633 | printf(" -f functional test\n" ); |
1634 | printf(" -p ping test\n" ); |
1635 | printf(" -t check the timer\n" ); |
1636 | printf(" and <iters> is the number of test iterations\n" ); |
1637 | exit(1); |
1638 | } |
1639 | |
1640 | static void check_timer(void) |
1641 | { |
1642 | uint32_t start = vcos_getmicrosecs(); |
1643 | uint32_t sleep_time = 1000; |
1644 | |
1645 | printf("0\n" ); |
1646 | |
1647 | while (1) |
1648 | { |
1649 | uint32_t now; |
1650 | vcos_sleep(sleep_time); |
1651 | now = vcos_getmicrosecs(); |
1652 | printf("%d - sleep %d\n" , now - start, sleep_time); |
1653 | } |
1654 | } |
1655 | |
1656 | static char *buf_align(char *buf, int align_size, int align) |
1657 | { |
1658 | char *aligned = buf - ((intptr_t)buf & (align_size - 1)) + align; |
1659 | if (aligned < buf) |
1660 | aligned += align_size; |
1661 | return aligned; |
1662 | } |
1663 | |
1664 | #ifdef ANDROID |
1665 | |
1666 | static void kill_timeout_handler(int cause, siginfo_t *how, void *ucontext) |
1667 | { |
1668 | printf("Sending signal SIGKILL\n" ); |
1669 | kill(main_process_pid, SIGKILL); |
1670 | } |
1671 | |
1672 | static int setup_auto_kill(int timeout_ms) |
1673 | { |
1674 | long timeout; |
1675 | struct timeval interval; |
1676 | |
1677 | if (timeout_ms <= 0) |
1678 | { |
1679 | return -1; |
1680 | } |
1681 | timeout = 1000 * timeout_ms; |
1682 | |
1683 | /* install a signal handler for the alarm */ |
1684 | struct sigaction sa; |
1685 | memset(&sa, 0, sizeof(struct sigaction)); |
1686 | sa.sa_sigaction = kill_timeout_handler; |
1687 | sigemptyset(&sa.sa_mask); |
1688 | sa.sa_flags = SA_SIGINFO; |
1689 | if (sigaction(SIGALRM, &sa, 0)) |
1690 | { |
1691 | perror("sigaction" ); |
1692 | exit(1); |
1693 | } |
1694 | |
1695 | /* when to expire */ |
1696 | interval.tv_sec = timeout / 1000000; |
1697 | interval.tv_usec = timeout % 1000000; |
1698 | |
1699 | struct itimerval alarm_spec = { |
1700 | .it_interval = {0,0}, |
1701 | .it_value = interval |
1702 | }; |
1703 | |
1704 | int rc = setitimer(ITIMER_REAL, &alarm_spec, NULL); |
1705 | if (rc < 0) |
1706 | { |
1707 | perror("setitimer failed" ); |
1708 | exit(1); |
1709 | } |
1710 | |
1711 | return 0; |
1712 | } |
1713 | |
1714 | |
1715 | |
1716 | #endif |
1717 | |
1718 | #ifdef VCOS_APPLICATION_INITIALIZE |
1719 | |
1720 | static VCOS_THREAD_T Task_0; |
1721 | |
1722 | void *main_task(void *param) |
1723 | { |
1724 | vchiq_test(rtos_argc, rtos_argv); |
1725 | |
1726 | VCOS_BKPT; |
1727 | |
1728 | return NULL; |
1729 | } |
1730 | |
1731 | #include "vcfw/logging/logging.h" |
1732 | |
1733 | void VCOS_APPLICATION_INITIALIZE(void *first_available_memory) |
1734 | { |
1735 | const int stack_size = 64*1024; |
1736 | void *pointer = NULL; |
1737 | VCOS_STATUS_T status; |
1738 | |
1739 | logging_init(); |
1740 | logging_level(LOGGING_VCOS); |
1741 | vcos_init(); |
1742 | |
1743 | /* Create task 0. */ |
1744 | #if VCOS_CAN_SET_STACK_ADDR |
1745 | pointer = malloc(stack_size); |
1746 | vcos_demand(pointer); |
1747 | #endif |
1748 | status = vcos_thread_create_classic( &Task_0, "TASK 0" , main_task, (void *)0, pointer, stack_size, |
1749 | 10 | VCOS_AFFINITY_DEFAULT, 20, VCOS_START ); |
1750 | vcos_demand(status == VCOS_SUCCESS); |
1751 | } |
1752 | |
1753 | #else |
1754 | |
1755 | int main(int argc, char **argv) |
1756 | { |
1757 | #ifdef ANDROID |
1758 | main_process_pid = getpid(); |
1759 | #endif |
1760 | |
1761 | vcos_init(); |
1762 | vcos_use_android_log = 0; |
1763 | return vchiq_test(argc, argv); |
1764 | } |
1765 | |
1766 | #endif |
1767 | |