f79438dc836690644e1cbebf59babfaa157ae0e6
[ipc/ipcdev.git] / qnx / src / ipc3x_dev / ti / syslink / samples / hlos / rpmsg-rpc-stress / usr / tests_rpc_stress.c
1 /*
2 * Copyright (c) 2013, Texas Instruments Incorporated
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
7 * are met:
8 *
9 * * Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 *
12 * * Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * * Neither the name of Texas Instruments Incorporated nor the names of
17 * its contributors may be used to endorse or promote products derived
18 * from this software without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
22 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
24 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
27 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
28 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
29 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
30 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 */
32 /*
33 * tests_rpc_stress.c
34 *
35 * Stress tests for rpmsg-rpc.
36 *
37 */
39 #include <sys/select.h>
40 #include <sys/types.h>
41 #include <sys/stat.h>
42 #include <fcntl.h>
43 #include <errno.h>
44 #include <stdio.h>
45 #include <string.h>
46 #include <stdlib.h>
47 #include <unistd.h>
48 #include <pthread.h>
49 #include <time.h>
50 #include <stdbool.h>
51 #include <semaphore.h>
52 #include <dlfcn.h>
54 #include "ti/ipc/rpmsg_rpc.h"
55 #include "ti/shmemallocator/SharedMemoryAllocatorUsr.h"
58 typedef struct {
59 int a;
60 int b;
61 int c;
62 } fxn_add3_args;
64 typedef struct {
65 int num;
66 int *array;
67 } fxn_addx_args;
69 /* Note: Set bit 31 to indicate static function indicies:
70 * This function order will be hardcoded on BIOS side, hence preconfigured:
71 */
72 enum {
73 FXN_IDX_FXNTRIPLE = 1,
74 FXN_IDX_FXNADD,
75 FXN_IDX_FXNADD3,
76 FXN_IDX_FXNADDX,
77 FXN_IDX_MAX
78 };
80 #define NUM_ITERATIONS 20
82 static int test_status = 0;
83 static bool runTest = true;
84 static int testFunc = FXN_IDX_FXNTRIPLE;
86 int exec_cmd(int fd, char *msg, size_t len, char *reply_msg, int *reply_len)
87 {
88 int ret = 0;
90 ret = write(fd, msg, len);
91 if (ret < 0) {
92 perror("Can't write to rpc_example instance");
93 return -1;
94 }
96 /* Now, await normal function result from rpc_example service:
97 * Note: len should be max length of response expected.
98 */
99 ret = read(fd, reply_msg, len);
100 if (ret < 0) {
101 perror("Can't read from rpc_example instance");
102 return -1;
103 }
104 else {
105 *reply_len = ret;
106 }
107 return 0;
108 }
110 int send_cmd(int fd, char *msg, int len)
111 {
112 int ret = 0;
114 ret = write(fd, msg, len);
115 if (ret < 0) {
116 perror("Can't write to rpc_example instance\n");
117 return -1;
118 }
120 return(0);
121 }
123 int recv_cmd(int fd, int len, char *reply_msg, int *reply_len)
124 {
125 int ret = 0;
127 /* Now, await normal function result from rpc_example service: */
128 // Note: len should be max length of response expected.
129 ret = read(fd, reply_msg, len);
130 if (ret < 0) {
131 perror("Can't read from rpc_example instance\n");
132 return -1;
133 }
134 else {
135 *reply_len = ret;
136 }
137 return(0);
138 }
140 typedef struct test_exec_args {
141 int fd;
142 int start_num;
143 int test_num;
144 sem_t * sem;
145 int thread_num;
146 int func_idx;
147 } test_exec_args;
149 static pthread_t * clientThreads = NULL;
150 static sem_t * clientSems = NULL;
151 static char **clientPackets = NULL;
152 static bool *readMsg = NULL;
153 static int *fds;
155 void *sharedmemalloc_lib = NULL;
156 int (*sharedmem_alloc)(int size, shm_buf *buf);
157 int (*sharedmem_free)(shm_buf *buf);
159 int deinit_sharedmem_funcs(void)
160 {
161 int ret = 0;
163 if (sharedmemalloc_lib)
164 dlclose(sharedmemalloc_lib);
165 sharedmemalloc_lib = NULL;
167 return ret;
168 }
170 int init_sharedmem_funcs()
171 {
172 int ret = 0;
174 if (sharedmemalloc_lib == NULL) {
175 sharedmemalloc_lib = dlopen("libsharedmemallocator.so",
176 RTLD_NOW | RTLD_GLOBAL);
177 if (sharedmemalloc_lib == NULL) {
178 perror("init_sharedmem_funcs: Error opening shared lib");
179 ret = -1;
180 }
181 else {
182 sharedmem_alloc = dlsym(sharedmemalloc_lib, "SHM_alloc");
183 if (sharedmem_alloc == NULL) {
184 perror("init_sharedmem_funcs: Error getting shared lib sym");
185 ret = -1;
186 }
187 else {
188 sharedmem_free = dlsym(sharedmemalloc_lib, "SHM_release");
189 if (sharedmem_free == NULL) {
190 perror("init_sharedmem_funcs: Error getting shared lib sym");
191 ret = -1;
192 }
193 }
194 }
195 }
196 if (ret < 0) {
197 deinit_sharedmem_funcs();
198 }
199 return ret;
200 }
202 void * test_exec_call(void * arg)
203 {
204 int i;
205 int packet_len;
206 int reply_len;
207 char packet_buf[512] = {0};
208 char return_buf[512] = {0};
209 test_exec_args *args = (test_exec_args *) arg;
210 int fd = args->fd;
211 struct rppc_function *function;
212 struct rppc_function_return *returned;
213 shm_buf buf, buf2;
214 void *ptr = NULL, *ptr2 = NULL;
216 for (i = args->start_num; i < args->start_num + NUM_ITERATIONS; i++) {
217 function = (struct rppc_function *)packet_buf;
218 function->fxn_id = args->func_idx;
219 switch (function->fxn_id) {
220 case FXN_IDX_FXNTRIPLE:
221 function->num_params = 1;
222 function->params[0].type = RPPC_PARAM_TYPE_ATOMIC;
223 function->params[0].size = sizeof(int);
224 function->params[0].data = i;
225 function->num_translations = 0;
226 break;
227 case FXN_IDX_FXNADD:
228 function->num_params = 2;
229 function->params[0].type = RPPC_PARAM_TYPE_ATOMIC;
230 function->params[0].size = sizeof(int);
231 function->params[0].data = i;
232 function->params[1].type = RPPC_PARAM_TYPE_ATOMIC;
233 function->params[1].size = sizeof(int);
234 function->params[1].data = i+1;
235 function->num_translations = 0;
236 break;
237 case FXN_IDX_FXNADD3:
238 if ((*sharedmem_alloc)(sizeof(fxn_add3_args), &buf) < 0) {
239 test_status = -1;
240 }
241 else {
242 ptr = (fxn_add3_args *)(buf.vir_addr);
243 ((fxn_add3_args *)ptr)->a = i;
244 ((fxn_add3_args *)ptr)->b = i+1;
245 ((fxn_add3_args *)ptr)->c = i+2;
246 function->num_params = 1;
247 function->params[0].type = RPPC_PARAM_TYPE_PTR;
248 function->params[0].size = sizeof(fxn_add3_args);
249 function->params[0].data = (size_t)ptr;
250 function->params[0].base = (size_t)ptr;
251 function->num_translations = 0;
252 }
253 break;
254 case FXN_IDX_FXNADDX:
255 if ((*sharedmem_alloc)(sizeof(fxn_addx_args), &buf) < 0) {
256 test_status = -1;
257 }
258 else if ((*sharedmem_alloc)(sizeof(int) * 3, &buf2) < 0) {
259 test_status = -1;
260 }
261 else {
262 ptr = (fxn_addx_args *)(buf.vir_addr);
263 ptr2 = (int *)(buf2.vir_addr);
264 ((fxn_addx_args *)ptr)->num = 3;
265 ((fxn_addx_args *)ptr)->array = ptr2;
266 ((int *)ptr2)[0] = i;
267 ((int *)ptr2)[1] = i+1;
268 ((int *)ptr2)[2] = i+2;
269 function->num_params = 1;
270 function->params[0].type = RPPC_PARAM_TYPE_PTR;
271 function->params[0].size = sizeof(fxn_addx_args);
272 function->params[0].data = (size_t)ptr;
273 function->params[0].base = (size_t)ptr;
274 function->num_translations = 1;
275 function->translations[0].index = 0;
276 function->translations[0].offset = (int)&(((fxn_addx_args *)ptr)->array) - (int)ptr;
277 function->translations[0].base = ((fxn_addx_args *)ptr)->array;
278 }
279 break;
280 }
282 if (test_status == -1)
283 break;
285 returned = (struct rppc_function_return *)return_buf;
287 /* Exec command: */
288 packet_len = sizeof(struct rppc_function) +\
289 (function->num_translations * \
290 sizeof(struct rppc_param_translation));
291 if (args->test_num == 1) {
292 if (exec_cmd(fd, (char *)packet_buf, packet_len,
293 (char *)return_buf, &reply_len)) {
294 test_status = -1;
295 break;
296 }
297 }
298 else if (args->test_num == 2 || args->test_num == 3) {
299 if (send_cmd(fd, (char *)packet_buf, packet_len)) {
300 test_status = -1;
301 break;
302 }
303 sem_wait(&clientSems[args->thread_num]);
304 memcpy(return_buf, clientPackets[args->thread_num], 512);
305 readMsg[args->thread_num] = true;
306 }
307 switch (function->fxn_id) {
308 case FXN_IDX_FXNTRIPLE:
309 if (i * 3 != returned->status) {
310 printf ("rpc_stress: "
311 "called fxnTriple(%d), result = %d, expected %d\n",
312 function->params[0].data, returned->status, i * 3);
313 test_status = -1;
314 }
315 else {
316 printf ("rpc_stress: called fxnTriple(%d), result = %d\n",
317 function->params[0].data, returned->status);
318 }
319 break;
320 case FXN_IDX_FXNADD:
321 if (i + (i+1) != returned->status) {
322 printf ("rpc_stress: "
323 "called fxnAdd(%d,%d), result = %d, expected %d\n",
324 function->params[0].data, function->params[1].data,
325 returned->status, i + (i+1));
326 test_status = -1;
327 }
328 else {
329 printf ("rpc_stress: called fxnAdd(%d,%d), result = %d\n",
330 function->params[0].data, function->params[1].data,
331 returned->status);
332 }
333 break;
334 case FXN_IDX_FXNADD3:
335 if (i + (i+1) + (i+2) != returned->status) {
336 printf ("rpc_stress: "
337 "called fxnAdd3(%d,%d,%d), result = %d, expected %d\n",
338 ((fxn_add3_args *)ptr)->a,
339 ((fxn_add3_args *)ptr)->b,
340 ((fxn_add3_args *)ptr)->c, returned->status,
341 i + (i+1) + (i+2));
342 test_status = -1;
343 }
344 else {
345 printf ("rpc_stress: called fxnAdd3(%d,%d,%d), result = %d\n",
346 ((fxn_add3_args *)ptr)->a,
347 ((fxn_add3_args *)ptr)->b,
348 ((fxn_add3_args *)ptr)->c, returned->status);
349 }
350 (*sharedmem_free)(&buf);
351 break;
352 case FXN_IDX_FXNADDX:
353 if (i + (i+1) + (i+2) != returned->status) {
354 printf ("rpc_stress: "
355 "called fxnAddX(%d,%d,%d), result = %d, expected %d\n",
356 ((int *)ptr2)[0], ((int *)ptr2)[1],
357 ((int *)ptr2)[2], returned->status,
358 i + (i+1) + (i+2));
359 test_status = -1;
360 }
361 else {
362 /* Check that reverse address translation is working */
363 if (((fxn_addx_args *)ptr)->array != ptr2) {
364 printf("rpc_stress: reverse addr translation failed, "
365 "addr = 0x%x expected 0x%x\n",
366 ((fxn_addx_args *)ptr)->array, ptr2);
367 test_status = -1;
368 }
369 printf ("rpc_stress: called fxnAddX(%d,%d,%d), result = %d\n",
370 ((int *)ptr2)[0], ((int *)ptr2)[1],
371 ((int *)ptr2)[2], returned->status);
372 }
373 (*sharedmem_free)(&buf);
374 (*sharedmem_free)(&buf2);
375 break;
376 }
377 if (test_status == -1) {
378 break;
379 }
380 }
382 return NULL;
383 }
385 void * test_select_thread (void * arg)
386 {
387 int fd;
388 int reply_len;
389 char return_buf[512] = {0};
390 struct rppc_function_return *rtn_packet =
391 (struct rppc_function_return *)return_buf;
392 int n, i;
393 fd_set rfd;
394 int max_fd = -1;
396 while (runTest) {
397 FD_ZERO(&rfd);
398 for (i = 0; i < (int)arg; i++) {
399 FD_SET(fds[i], &rfd);
400 max_fd = max(max_fd, fds[i]);
401 }
402 n = select(1 + max_fd, &rfd, NULL, NULL, NULL);
403 switch (n) {
404 case -1:
405 perror("select");
406 return NULL;
407 default:
408 for (i = 0; i < (int)arg; i++) {
409 if (FD_ISSET(fds[i], &rfd)) {
410 fd = fds[i];
411 break;
412 }
413 }
414 break;
415 }
416 if (recv_cmd(fd, 512, (char *)rtn_packet, &reply_len)) {
417 test_status = -1;
418 printf("test_select_thread: recv_cmd failed!");
419 break;
420 }
422 if (runTest == false)
423 break;
425 /* Decode reply: */
426 while (readMsg[i] == false) {
427 sleep(1);
428 }
429 memcpy(clientPackets[i], rtn_packet, 512);
430 readMsg[i] = false;
431 sem_post(&clientSems[i]);
432 }
433 return NULL;
434 }
436 void * test_read_thread (void * arg)
437 {
438 int fd = (int)arg;
439 int reply_len;
440 char return_buf[512] = {0};
441 struct rppc_function_return *rtn_packet =
442 (struct rppc_function_return *)return_buf;
443 int packet_id;
445 while (runTest) {
446 if (recv_cmd(fd, 512, (char *)rtn_packet, &reply_len)) {
447 test_status = -1;
448 printf("test_read_tread: recv_cmd failed!");
449 break;
450 }
452 if (runTest == false)
453 break;
455 /* Decode reply: */
456 switch (testFunc) {
457 case FXN_IDX_FXNTRIPLE:
458 packet_id = ((rtn_packet->status / 3) - 1) / NUM_ITERATIONS;
459 break;
460 case FXN_IDX_FXNADD:
461 packet_id = (((rtn_packet->status - 1) / 2) - 1) / NUM_ITERATIONS;
462 break;
463 case FXN_IDX_FXNADD3:
464 packet_id = (((rtn_packet->status - 3) / 3) - 1) / NUM_ITERATIONS;
465 break;
466 case FXN_IDX_FXNADDX:
467 packet_id = (((rtn_packet->status - 3) / 3) - 1) / NUM_ITERATIONS;
468 break;
469 }
470 while (readMsg[packet_id] == false) {
471 sleep(1);
472 }
473 memcpy(clientPackets[packet_id], rtn_packet, 512);
474 readMsg[packet_id] = false;
475 sem_post(&clientSems[packet_id]);
476 }
477 return NULL;
478 }
480 int test_rpc_stress_select(int core_id, int num_comps, int func_idx)
481 {
482 int ret = 0;
483 int i = 0, j = 0;
484 struct rppc_create_instance connreq;
485 struct rppc_function *function;
486 pthread_t select_thread;
487 int packet_len;
488 char packet_buf[512] = {0};
489 test_exec_args args[num_comps];
491 fds = malloc (sizeof(int) * num_comps);
492 if (!fds) {
493 return -1;
494 }
495 for (i = 0; i < num_comps; i++) {
496 /* Connect to the rpc_example ServiceMgr on the specified core: */
497 if (core_id == 0) {
498 fds[i] = open("/dev/rpmsg-omx0", O_RDWR);
499 if (fds[i] < 0) {
500 perror("Can't open OMX device");
501 ret = -1;
502 break;
503 }
504 strcpy(connreq.name, "rpmsg-omx0");
505 }
506 else if (core_id == 1) {
507 fds[i] = open("/dev/rpc_example", O_RDWR);
508 if (fds[i] < 0) {
509 perror("Can't open rpc_example device");
510 break;
511 }
512 strcpy(connreq.name, "rpc_example");
513 }
514 else if (core_id == 2) {
515 fds[i] = open("/dev/rpmsg-omx2", O_RDWR);
516 if (fds[i] < 0) {
517 perror("Can't open OMX device");
518 break;
519 }
520 strcpy(connreq.name, "rpmsg-omx2");
521 }
522 /* Create an rpc_example server instance, and rebind its address to this
523 * file descriptor.
524 */
525 ret = ioctl(fds[i], RPPC_IOC_CREATE, &connreq);
526 if (ret < 0) {
527 perror("Can't connect to rpc_example instance");
528 close(fds[i]);
529 break;
530 }
531 printf("rpc_sample: Connected to %s\n", connreq.name);
532 }
533 if (i != num_comps) {
534 /* cleanup */
535 for (j = 0; j < i; j++) {
536 ret = close(fds[j]);
537 if (ret < 0) {
538 perror("Can't close rpc_example fd ??");
539 }
540 }
541 free(fds);
542 return -1;
543 }
545 clientSems = malloc(sizeof(sem_t) * num_comps);
546 if (!clientSems) {
547 free(clientThreads);
548 for (i = 0; i < num_comps; i++) {
549 ret = close(fds[i]);
550 if (ret < 0) {
551 perror("Can't close rpc_example fd ??");
552 }
553 }
554 return -1;
555 }
557 readMsg = malloc(sizeof(bool) * num_comps);
558 if (!readMsg) {
559 free(clientSems);
560 free(clientThreads);
561 for (i = 0; i < num_comps; i++) {
562 ret = close(fds[i]);
563 if (ret < 0) {
564 perror("Can't close rpc_example fd ??");
565 }
566 }
567 return -1;
568 }
570 clientPackets = malloc(sizeof(char *) * num_comps);
571 if (!clientPackets) {
572 free(readMsg);
573 free(clientSems);
574 free(clientThreads);
575 for (i = 0; i < num_comps; i++) {
576 ret = close(fds[i]);
577 if (ret < 0) {
578 perror("Can't close rpc_example fd ??");
579 }
580 }
581 return -1;
582 }
584 for (i = 0; i < num_comps; i++) {
585 clientPackets[i] = malloc(512 * sizeof(char));
586 if (!clientPackets[i]) {
587 for (j = 0; j < i; j++) {
588 free(clientPackets[j]);
589 }
590 free(clientPackets);
591 free(readMsg);
592 free(clientSems);
593 free(clientThreads);
594 for (i = 0; i < num_comps; i++) {
595 ret = close(fds[i]);
596 if (ret < 0) {
597 perror("Can't close rpc_example fd ??");
598 }
599 }
600 return -1;
601 }
602 }
604 ret = pthread_create(&select_thread, NULL, test_select_thread,
605 (void *)num_comps);
606 if (ret < 0) {
607 perror("Can't create thread");
608 ret = -1;
609 }
611 clientThreads = malloc(sizeof(pthread_t) * num_comps);
612 if (!clientThreads) {
613 for (i = 0; i < num_comps; i++) {
614 ret = close(fds[i]);
615 if (ret < 0) {
616 perror("Can't close rpc_example fd ??");
617 }
618 }
619 free(fds);
620 return -1;
621 }
623 for ( i = 0; i < num_comps; i++) {
624 ret = sem_init(&clientSems[i], 0, 0);
625 args[i].fd = fds[i];
626 args[i].start_num = 1;
627 args[i].test_num = 3;
628 args[i].sem = &clientSems[i];
629 args[i].thread_num = i;
630 args[i].func_idx = func_idx;
631 readMsg[i] = true;
632 ret = pthread_create(&clientThreads[i], NULL, test_exec_call,
633 (void *)&args[i]);
634 if (ret < 0) {
635 perror("Can't create thread");
636 ret = -1;
637 break;
638 }
639 printf("Created thread %d\n", i);
640 }
642 for (j = 0; j < i; j++) {
643 printf("Join thread %d\n", j);
644 pthread_join(clientThreads[j], NULL);
645 }
647 free(clientThreads);
649 function = (struct rppc_function *)packet_buf;
650 function->fxn_id = FXN_IDX_FXNTRIPLE;
651 function->num_params = 1;
652 function->params[0].type = RPPC_PARAM_TYPE_ATOMIC;
653 function->params[0].size = sizeof(int);
654 function->params[0].data = i;
655 function->num_translations = 0;
657 /* Exec command: */
658 packet_len = sizeof(struct rppc_function) +\
659 (function->num_translations *\
660 sizeof(struct rppc_param_translation));
662 runTest = false;
663 if (send_cmd(fds[0], (char *)packet_buf, packet_len)) {
664 test_status = -1;
665 }
667 pthread_join(select_thread, NULL);
669 for (i = 0; i < num_comps; i++) {
670 free(clientPackets[i]);
671 }
672 free(clientPackets);
673 free(readMsg);
674 free(clientSems);
676 for (i = 0; i < num_comps; i++) {
677 /* Terminate connection and destroy rpc_example instance */
678 ret = close(fds[i]);
679 if (ret < 0) {
680 perror("Can't close rpc_example fd ??");
681 ret = -1;
682 }
683 printf("rpc_sample: Closed connection to %s!\n", connreq.name);
684 }
686 free(fds);
687 return ret;
688 }
690 int test_rpc_stress_multi_threads(int core_id, int num_threads, int func_idx)
691 {
692 int ret = 0;
693 int i = 0, j = 0;
694 int fd;
695 int packet_len;
696 char packet_buf[512] = {0};
697 pthread_t read_thread;
698 struct rppc_create_instance connreq;
699 struct rppc_function *function;
700 test_exec_args args[num_threads];
702 /* Connect to the rpc_example ServiceMgr on the specified core: */
703 if (core_id == 0) {
704 fd = open("/dev/rpmsg-omx0", O_RDWR);
705 if (fd < 0) {
706 perror("Can't open OMX device");
707 return -1;
708 }
709 strcpy(connreq.name, "rpmsg-omx0");
711 }
712 else if (core_id == 1) {
713 fd = open("/dev/rpc_example", O_RDWR);
714 if (fd < 0) {
715 perror("Can't open rpc_example device");
716 return -1;
717 }
718 strcpy(connreq.name, "rpc_example");
719 }
720 else if (core_id == 2) {
721 fd = open("/dev/rpmsg-omx2", O_RDWR);
722 if (fd < 0) {
723 perror("Can't open OMX device");
724 return -1;
725 }
726 strcpy(connreq.name, "rpmsg-omx2");
727 }
728 /* Create an rpc_example server instance, and rebind its address to this
729 * file descriptor.
730 */
731 ret = ioctl(fd, RPPC_IOC_CREATE, &connreq);
732 if (ret < 0) {
733 perror("Can't connect to rpc_example instance");
734 close(fd);
735 return -1;
736 }
737 printf("rpc_sample: Connected to %s\n", connreq.name);
739 clientThreads = malloc(sizeof(pthread_t) * num_threads);
740 if (!clientThreads) {
741 ret = close(fd);
742 return -1;
743 }
744 clientSems = malloc(sizeof(sem_t) * num_threads);
745 if (!clientSems) {
746 free(clientThreads);
747 ret = close(fd);
748 return -1;
749 }
751 readMsg = malloc(sizeof(bool) * num_threads);
752 if (!readMsg) {
753 free(clientSems);
754 free(clientThreads);
755 ret = close(fd);
756 return -1;
757 }
759 clientPackets = malloc(sizeof(char *) * num_threads);
760 if (!clientPackets) {
761 free(readMsg);
762 free(clientSems);
763 free(clientThreads);
764 ret = close(fd);
765 return -1;
766 }
768 for (i = 0; i < num_threads; i++) {
769 clientPackets[i] = malloc(512 * sizeof(char));
770 if (!clientPackets[i]) {
771 for (j = 0; j < i; j++) {
772 free(clientPackets[j]);
773 }
774 free(clientPackets);
775 free(readMsg);
776 free(clientSems);
777 free(clientThreads);
778 close(fd);
779 return -1;
780 }
781 }
783 ret = pthread_create(&read_thread, NULL, test_read_thread, (void *)fd);
784 if (ret < 0) {
785 perror("Can't create thread");
786 for (i = 0; i < num_threads; i++) {
787 free(clientPackets[i]);
788 }
789 free(clientPackets);
790 free(readMsg);
791 free(clientSems);
792 free(clientThreads);
793 close(fd);
794 return -1;
795 }
797 for ( i = 0; i < num_threads; i++) {
798 ret = sem_init(&clientSems[i], 0, 0);
799 args[i].fd = fd;
800 args[i].start_num = (i * NUM_ITERATIONS) + 1;
801 args[i].test_num = 2;
802 args[i].sem = &clientSems[i];
803 args[i].thread_num = i;
804 args[i].func_idx = func_idx;
805 readMsg[i] = true;
806 ret = pthread_create(&clientThreads[i], NULL, test_exec_call,
807 (void *)&args[i]);
808 if (ret < 0) {
809 perror("Can't create thread");
810 ret = -1;
811 break;
812 }
813 printf("Created thread %d\n", i);
814 }
816 for (j = 0; j < i; j++) {
817 printf("Join thread %d\n", j);
818 pthread_join(clientThreads[j], NULL);
819 sem_destroy(&clientSems[j]);
820 }
822 function = (struct rppc_function *)packet_buf;
823 function->fxn_id = FXN_IDX_FXNTRIPLE;
824 function->num_params = 1;
825 function->params[0].type = RPPC_PARAM_TYPE_ATOMIC;
826 function->params[0].size = sizeof(int);
827 function->params[0].data = i;
828 function->num_translations = 0;
830 /* Exec command: */
831 packet_len = sizeof(struct rppc_function) +\
832 (function->num_translations *\
833 sizeof(struct rppc_param_translation));
835 runTest = false;
836 if (send_cmd(fd, (char *)packet_buf, packet_len)) {
837 test_status = -1;
838 }
840 pthread_join(read_thread, NULL);
842 for (i = 0; i < num_threads; i++) {
843 free(clientPackets[i]);
844 }
845 free(clientPackets);
846 free(readMsg);
847 free(clientSems);
848 free(clientThreads);
850 /* Terminate connection and destroy rpc_example instance */
851 ret = close(fd);
852 if (ret < 0) {
853 perror("Can't close rpc_example fd ??");
854 ret = -1;
855 }
856 printf("rpc_sample: Closed connection to %s!\n", connreq.name);
858 return ret;
859 }
861 int test_rpc_stress_multi_srvmgr(int core_id, int num_comps, int func_idx)
862 {
863 int ret = 0;
864 int i = 0, j = 0;
865 int fd[num_comps];
866 struct rppc_create_instance connreq;
867 test_exec_args args[num_comps];
869 for (i = 0; i < num_comps; i++) {
870 /* Connect to the rpc_example ServiceMgr on the specified core: */
871 if (core_id == 0) {
872 fd[i] = open("/dev/rpmsg-omx0", O_RDWR);
873 if (fd[i] < 0) {
874 perror("Can't open OMX device");
875 ret = -1;
876 break;
877 }
878 strcpy(connreq.name, "rpmsg-omx0");
879 }
880 else if (core_id == 1) {
881 fd[i] = open("/dev/rpc_example", O_RDWR);
882 if (fd[i] < 0) {
883 perror("Can't open rpc_example device");
884 ret = -1;
885 break;
886 }
887 strcpy(connreq.name, "rpc_example");
888 }
889 else if (core_id == 2) {
890 fd[i] = open("/dev/rpmsg-omx2", O_RDWR);
891 if (fd[i] < 0) {
892 perror("Can't open OMX device");
893 ret = -1;
894 break;
895 }
896 strcpy(connreq.name, "rpmsg-omx2");
897 }
898 /* Create an rpc_example server instance, and rebind its address to this
899 * file descriptor.
900 */
901 ret = ioctl(fd[i], RPPC_IOC_CREATE, &connreq);
902 if (ret < 0) {
903 perror("Can't connect to rpc_example instance");
904 close(fd[i]);
905 break;
906 }
907 printf("rpc_sample: Connected to %s\n", connreq.name);
908 }
909 if (i != num_comps) {
910 /* cleanup */
911 for (j = 0; j < i; j++) {
912 ret = close(fd[j]);
913 if (ret < 0) {
914 perror("Can't close rpc_example fd ??");
915 }
916 }
917 return -1;
918 }
920 clientThreads = malloc(sizeof(pthread_t) * num_comps);
921 if (!clientThreads) {
922 for (i = 0; i < num_comps; i++) {
923 ret = close(fd[i]);
924 if (ret < 0) {
925 perror("Can't close rpc_example fd ??");
926 }
927 }
928 return -1;
929 }
931 for ( i = 0; i < num_comps; i++) {
932 args[i].fd = fd[i];
933 args[i].start_num = 1;
934 args[i].test_num = 1;
935 args[i].sem = NULL;
936 args[i].thread_num = i;
937 args[i].func_idx = func_idx;
938 ret = pthread_create(&clientThreads[i], NULL, test_exec_call,
939 (void *)&args[i]);
940 if (ret < 0) {
941 perror("Can't create thread");
942 ret = -1;
943 break;
944 }
945 printf("Created thread %d\n", i);
946 }
948 for (j = 0; j < i; j++) {
949 printf("Join thread %d\n", j);
950 pthread_join(clientThreads[j], NULL);
951 }
953 free(clientThreads);
955 for (i = 0; i < num_comps; i++) {
956 /* Terminate connection and destroy rpc_example instance */
957 ret = close(fd[i]);
958 if (ret < 0) {
959 perror("Can't close rpc_example fd ??");
960 ret = -1;
961 }
962 printf("rpc_sample: Closed connection to %s!\n", connreq.name);
963 }
965 return ret;
966 }
968 int main(int argc, char *argv[])
969 {
970 int ret;
971 int test_id = -1;
972 int core_id = 0;
973 int num_comps = 1;
974 int num_threads = 1;
975 int func_idx = 1;
976 int c;
978 while (1)
979 {
980 c = getopt (argc, argv, "t:c:x:l:f:");
981 if (c == -1)
982 break;
984 switch (c)
985 {
986 case 't':
987 test_id = atoi(optarg);
988 break;
989 case 'c':
990 core_id = atoi(optarg);
991 break;
992 case 'x':
993 num_comps = atoi(optarg);
994 break;
995 case 'l':
996 num_threads = atoi(optarg);
997 break;
998 case 'f':
999 func_idx = atoi(optarg);
1000 break;
1001 default:
1002 printf ("Unrecognized argument\n");
1003 }
1004 }
1006 if (test_id < 0 || test_id > 3) {
1007 printf("Invalid test id\n");
1008 return 1;
1009 }
1011 if (func_idx < FXN_IDX_FXNTRIPLE || func_idx >= FXN_IDX_MAX) {
1012 printf("Invalid function index\n");
1013 return 1;
1014 }
1015 testFunc = func_idx;
1017 if (func_idx == FXN_IDX_FXNADD3 || func_idx == FXN_IDX_FXNADDX) {
1018 if (init_sharedmem_funcs() < 0) {
1019 printf("failure: shmemallocator library must be present for this test function\n");
1020 return 1;
1021 }
1022 }
1024 switch (test_id) {
1025 case 1:
1026 /* multiple threads each with an RPMSG-RPC ServiceMgr instance */
1027 if (core_id < 0 || core_id > 2) {
1028 printf("Invalid core id\n");
1029 return 1;
1030 }
1031 if (num_comps < 0) {
1032 printf("Invalid num comps id\n");
1033 return 1;
1034 }
1035 ret = test_rpc_stress_multi_srvmgr(core_id, num_comps, func_idx);
1036 break;
1037 case 2:
1038 /* Multiple threads, 1 RPMSG-RPC ServiceMgr instances */
1039 if (core_id < 0 || core_id > 2) {
1040 printf("Invalid core id\n");
1041 return 1;
1042 }
1043 if (num_threads < 0) {
1044 printf("Invalid num threads\n");
1045 return 1;
1046 }
1047 ret = test_rpc_stress_multi_threads(core_id, num_threads, func_idx);
1048 break;
1049 case 3:
1050 /* 1 thread using multiple RPMSG-RPC ServiceMgr instances */
1051 if (core_id < 0 || core_id > 2) {
1052 printf("Invalid core id\n");
1053 return 1;
1054 }
1055 if (num_comps < 0) {
1056 printf("Invalid num comps id\n");
1057 return 1;
1058 }
1059 ret = test_rpc_stress_select(core_id, num_comps, func_idx);
1060 break;
1061 default:
1062 break;
1063 }
1065 if (ret < 0 || test_status < 0) {
1066 printf ("TEST STATUS: FAILED.\n");
1067 }
1068 else {
1069 printf ("TEST STATUS: PASSED.\n");
1070 }
1071 return 0;
1072 }