9b11506ac67334bf26b8cbe98cb3f9247a656b51
1 /*
2 * rm_linux_mt_client_test.c
3 *
4 * RM test that runs clients from multiple threads to test the
5 * multi-threaded serialization capabilities of RM clients. The clients
6 * communicate with the RM server of sockets.
7 *
8 * ============================================================================
9 *
10 * Copyright (c) 2012-2014, Texas Instruments Incorporated
11 * All rights reserved.
12 *
13 * Redistribution and use in source and binary forms, with or without
14 * modification, are permitted provided that the following conditions
15 * are met:
16 *
17 * * Redistributions of source code must retain the above copyright
18 * notice, this list of conditions and the following disclaimer.
19 *
20 * * Redistributions in binary form must reproduce the above copyright
21 * notice, this list of conditions and the following disclaimer in the
22 * documentation and/or other materials provided with the distribution.
23 *
24 * * Neither the name of Texas Instruments Incorporated nor the names of
25 * its contributors may be used to endorse or promote products derived
26 * from this software without specific prior written permission.
27 *
28 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
29 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
30 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
31 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
32 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
33 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
34 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
35 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
36 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
37 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
38 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
39 *
40 */
42 /*
43 * Shut off: remark #880-D: parameter "appTransport" was never referenced
44 *
45 * This is better than removing the argument since removal would break
46 * backwards compatibility
47 */
48 #ifdef _TMS320C6X
49 #pragma diag_suppress 880
50 #pragma diag_suppress 681
51 #elif defined(__GNUC__)
52 /* Same for GCC:
54 */
55 #pragma GCC diagnostic ignored "-Wunused-parameter"
56 #endif
58 /* Standard includes */
59 #include <stdio.h>
60 #include <errno.h>
61 #include <stdlib.h>
62 #include <string.h>
63 #include <unistd.h>
64 #include <pthread.h>
65 #include <time.h>
67 /* Socket Includes */
68 #include "sockutils.h"
69 #include "sockrmmsg.h"
71 /* RM Includes */
72 #include <ti/drv/rm/rm.h>
73 #include <ti/drv/rm/rm_transport.h>
74 #include <ti/drv/rm/rm_services.h>
76 /**********************************************************************
77 ************************** RM Test Symbols ***************************
78 **********************************************************************/
80 /* Total resource request iterations between threads */
81 #define REQUEST_ITERATIONS 16000
82 #define RESOURCE_PRINT_DIVISOR 1000
84 /* Test FALSE */
85 #define RM_TEST_FALSE 0
86 /* Test TRUE */
87 #define RM_TEST_TRUE 1
89 /* Socket timeout */
90 #define CLIENT_SOCK_TIMEOUT_USEC (500)
92 /* Application's registered RM transport indices */
93 #define MAP_ENTRY_SERVER_TO_CLIENT 0
94 /* Maximum number of registered RM transports */
95 #define MAX_MAPPING_ENTRIES 1
97 /* Error checking macro */
98 #define ERROR_CHECK(checkVal, resultVal, rmInstName, printMsg) \
99 if (resultVal != checkVal) { \
100 char errorMsgToPrint[] = printMsg; \
101 printf("Error : %s : ", rmInstName); \
102 printf("%s with error code : %d\n", errorMsgToPrint, resultVal); \
103 test_errors++; \
104 }
106 /**********************************************************************
107 ********************** RM Test Data Structures ***********************
108 **********************************************************************/
110 /* RM registered transport mapping structure */
111 typedef struct trans_map_entry_s {
112 /* Registered RM transport handle */
113 Rm_TransportHandle transport_handle;
114 /* Remote socket tied to the transport handle */
115 sock_name_t *remote_sock;
116 } trans_map_entry_t;
118 /**********************************************************************
119 ********************** Extern Variables ******************************
120 **********************************************************************/
122 /* Alloc and free OSAL variables */
123 extern uint32_t rmMallocCounter;
124 extern uint32_t rmFreeCounter;
125 extern int32_t rmByteAlloc;
126 extern int32_t rmByteFree;
129 /**********************************************************************
130 ********************** Global Variables ******************************
131 **********************************************************************/
133 /* Number of errors that occurred during the test */
134 uint16_t test_errors;
136 /* RM Client Variables */
137 char client_name[RM_NAME_MAX_CHARS] = "RM_Client";
138 Rm_Handle client_handle = NULL;
139 Rm_ServiceHandle *service_handle = NULL;
141 /* pthread mutex lock needed for testing */
142 pthread_mutex_t client_mutex_lock;
144 /* Client socket name */
145 char client_sock_name[] = "/var/run/rm/rm_client";
147 /* Client socket handles */
148 sock_h client_sock;
150 /* Transport map stores the RM transport handle to IPC MessageQ queue mapping */
151 trans_map_entry_t rm_trans_map[MAX_MAPPING_ENTRIES];
153 /* RM resource names (must match resource node names in GRL and policies */
154 char res_name_link_ram[RM_NAME_MAX_CHARS] = "link-ram";
156 /* Used to track allocations in each thread */
157 uint32_t allocs[REQUEST_ITERATIONS];
159 /**********************************************************************
160 *************************** Test Functions ***************************
161 **********************************************************************/
163 uint32_t thread_num_one = 1;
164 uint32_t thread_num_two = 2;
166 typedef pthread_t task_handle;
168 #define DEFAULT_STACK_SIZE 0x8000
169 /** ============================================================================
170 * @n@b task_create
171 *
172 * @b Description
173 * @n Create thread to run the test program
174 *
175 * @param[in]
176 * @n None
177 *
178 * @return int32_t
179 * -1 - Error
180 * 0 - Success
181 * =============================================================================
182 */
183 static int task_create (void *(start_routine)(void *), void* args, void* handle)
184 {
185 int max_priority, err;
186 pthread_t thread;
187 pthread_attr_t attr;
188 struct sched_param param;
190 max_priority = sched_get_priority_max(SCHED_FIFO);
191 err = pthread_attr_init(&attr);
192 if (err) {
193 printf("pthread_attr_init failed: (%s)\n", strerror(err));
194 return err;
195 }
196 err = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
197 if (err) {
198 printf("pthread_attr_setdetachstate failed: (%s)\n", strerror(err));
199 return err;
200 }
201 err = pthread_attr_setstacksize(&attr, DEFAULT_STACK_SIZE);
202 if (err) {
203 printf("pthread_attr_setstacksize failed: (%s)\n", strerror(err));
204 return err;
205 }
206 err = pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED);
207 if (err) {
208 printf("pthread_attr_setinheritsched failed: (%s)\n", strerror(err));
209 return err;
210 }
211 err = pthread_attr_setschedpolicy(&attr, SCHED_FIFO);
212 if (err) {
213 printf("pthread_attr_setschedpolicy failed: (%s)\n", strerror(err));
214 return err;
215 }
216 memset(¶m, 0, sizeof(param));
217 param.sched_priority = max_priority;
218 err = pthread_attr_setschedparam(&attr, ¶m);
219 if (err) {
220 printf("pthread_attr_setschedparam failed: (%s)\n", strerror(err));
221 return err;
222 }
223 if (err) return err;
224 err = pthread_create(&thread, &attr, start_routine, args);
225 if (err) {
226 printf("pthread_create failed: (%s)\n", strerror(err));
227 return err;
228 }
229 if (err) return err;
230 *(pthread_t *)handle = thread;
231 return 0;
232 }
234 /** ============================================================================
235 * @n@b task_wait
236 *
237 * @b Description
238 * @n Wait for Task completion
239 *
240 * @return void
241 * =============================================================================
242 */
243 static void task_wait (void *handle)
244 {
245 pthread_join(*((pthread_t *)handle), NULL);
246 return;
247 }
250 Rm_Packet *transportAlloc(Rm_AppTransportHandle appTransport, uint32_t pktSize, Rm_PacketHandle *pktHandle)
251 {
252 Rm_Packet *rm_pkt = NULL;
254 rm_pkt = calloc(1, sizeof(*rm_pkt));
255 if (!rm_pkt) {
256 printf("Error : Can't malloc for RM send message (err: %s)\n", strerror(errno));
257 test_errors++;
258 return (NULL);
259 }
260 rm_pkt->pktLenBytes = pktSize;
261 *pktHandle = rm_pkt;
263 return(rm_pkt);
264 }
266 void transportFree (Rm_Packet *rm_pkt)
267 {
268 if (rm_pkt) {
269 free (rm_pkt);
270 }
271 }
273 void transportReceive (void)
274 {
275 int32_t rm_result;
276 int retval;
277 int length = 0;
278 sock_name_t server_sock_addr;
279 Rm_Packet *rm_pkt = NULL;
280 struct sockaddr_un server_addr;
282 retval = sock_wait(client_sock, &length, NULL, -1);
283 if (retval == -2) {
284 /* Timeout */
285 return;
286 }
287 else if (retval < 0) {
288 printf("Error in reading from socket, error %d\n", retval);
289 test_errors++;
290 return;
291 }
293 if (length < ((int)sizeof(*rm_pkt))) {
294 printf("invalid RM message length %d\n", length);
295 test_errors++;
296 return;
297 }
298 rm_pkt = calloc(1, length);
299 if (!rm_pkt) {
300 printf("can't malloc for recv'd RM message (err: %s)\n",
301 strerror(errno));
302 test_errors++;
303 return;
304 }
306 server_sock_addr.type = sock_addr_e;
307 server_sock_addr.s.addr = &server_addr;
308 retval = sock_recv(client_sock, (char *)rm_pkt, length, &server_sock_addr);
309 if (retval != length) {
310 printf("recv RM pkt failed from socket, received = %d, expected = %d\n",
311 retval, length);
312 return;
313 }
315 /* Provide packet to RM Server for processing */
316 if ((rm_result = Rm_receivePacket(rm_trans_map[MAP_ENTRY_SERVER_TO_CLIENT].transport_handle, rm_pkt))) {
317 printf("RM failed to process received packet: %d\n", rm_result);
318 }
320 transportFree(rm_pkt);
321 }
323 int32_t transportSendRcv(Rm_AppTransportHandle appTransport, Rm_PacketHandle pktHandle)
324 {
325 sock_name_t *server_sock_name = (sock_name_t *)appTransport;
326 Rm_Packet *rm_pkt = (Rm_Packet *)pktHandle;
328 if (sock_send(client_sock, (char *)rm_pkt, (int) rm_pkt->pktLenBytes, server_sock_name)) {
329 printf("send data failed\n");
330 }
332 /* Wait for response from Server */
333 transportReceive();
335 return (0);
336 }
338 /** ============================================================================
339 * @n@b odd_test
340 *
341 * @b Description
342 * @n Resource request routine running as a separate thread
343 *
344 * @return void *
345 * =============================================================================
346 */
347 void *allocate_test (void *args)
348 {
349 uint32_t *thread_num = (uint32_t *)args;
350 Rm_ServiceReqInfo request;
351 Rm_ServiceRespInfo response;
352 uint32_t i;
353 struct timespec tim;
355 tim.tv_sec = 0;
356 tim.tv_nsec = 1000;
358 if (service_handle) {
359 /* Init request - request one resource at a time as unspecified. Server
360 * will return next available resource */
361 memset(&request, 0, sizeof(request));
362 request.type = Rm_service_RESOURCE_ALLOCATE_INIT;
363 request.resourceName = res_name_link_ram;
364 request.resourceBase = RM_RESOURCE_BASE_UNSPECIFIED;
365 request.resourceLength = 1;
367 printf("Thread %d : Requesting %d resources...\n", *thread_num, REQUEST_ITERATIONS / 2);
368 for (i = 0; i < (REQUEST_ITERATIONS / 2); i++) {
369 memset(&response, 0, sizeof(response));
370 service_handle->Rm_serviceHandler(service_handle->rmHandle, &request, &response);
372 if (response.serviceState == RM_SERVICE_APPROVED) {
373 allocs[response.resourceBase]++;
374 nanosleep(&tim , NULL);
376 if ((i % RESOURCE_PRINT_DIVISOR) == 0) {
377 printf("Thread %d : Requested %d resources...\n", *thread_num, RESOURCE_PRINT_DIVISOR);
378 }
379 }
380 else {
381 printf("Error Thread %d : Allocate request was not approved for resource %d\n",
382 *thread_num, request.resourceBase);
383 test_errors++;
384 goto error_exit;
385 }
386 }
387 }
389 error_exit:
390 printf("Thread %d : Exiting...\n", *thread_num);
391 pthread_exit((void*) 0);
392 return NULL;
393 }
395 void resource_cleanup(void)
396 {
397 Rm_ServiceReqInfo request;
398 Rm_ServiceRespInfo response;
399 uint32_t i;
401 if (service_handle) {
402 printf("Freeing all %d resources...\n", REQUEST_ITERATIONS);
403 for (i = 0; i < REQUEST_ITERATIONS; i++) {
404 while (allocs[i]) {
405 memset(&request, 0, sizeof(request));
406 request.type = Rm_service_RESOURCE_FREE;
407 request.resourceName = res_name_link_ram;
408 request.resourceBase = i;
409 request.resourceLength = 1;
411 memset(&response, 0, sizeof(response));
412 service_handle->Rm_serviceHandler(service_handle->rmHandle, &request, &response);
414 if (response.serviceState != RM_SERVICE_APPROVED) {
415 printf("Error : Free request was not approved for resource %d - Exiting...\n",
416 request.resourceBase);
417 test_errors++;
418 }
420 allocs[i]--;
421 }
422 }
423 }
424 }
426 void connection_setup(void)
427 {
428 Rm_TransportCfg rm_trans_cfg;
429 int32_t rm_result;
430 int i;
431 sock_name_t sock_name;
432 char server_sock_name[] = RM_SERVER_SOCKET_NAME;
434 printf("Setting up socket connection to RM Server\n");
436 /* Initialize the transport map */
437 for (i = 0; i < MAX_MAPPING_ENTRIES; i++) {
438 rm_trans_map[i].transport_handle = NULL;
439 }
441 sock_name.type = sock_name_e;
442 sock_name.s.name = client_sock_name;
444 client_sock = sock_open(&sock_name);
445 if (!client_sock) {
446 printf("Client socket open failed\n");
447 exit(EXIT_FAILURE);
448 }
450 rm_trans_map[MAP_ENTRY_SERVER_TO_CLIENT].remote_sock = calloc(1, sizeof(sock_name_t));
451 rm_trans_map[MAP_ENTRY_SERVER_TO_CLIENT].remote_sock->type = sock_name_e;
452 rm_trans_map[MAP_ENTRY_SERVER_TO_CLIENT].remote_sock->s.name = calloc(1, strlen(server_sock_name)+1);
453 strncpy(rm_trans_map[MAP_ENTRY_SERVER_TO_CLIENT].remote_sock->s.name, server_sock_name, strlen(server_sock_name)+1);
455 /* Register the Server with the Client instance */
456 rm_trans_cfg.rmHandle = client_handle;
457 rm_trans_cfg.appTransportHandle = (Rm_AppTransportHandle) rm_trans_map[MAP_ENTRY_SERVER_TO_CLIENT].remote_sock;
458 rm_trans_cfg.remoteInstType = Rm_instType_SERVER;
459 rm_trans_cfg.transportCallouts.rmAllocPkt = transportAlloc;
460 rm_trans_cfg.transportCallouts.rmSendPkt = transportSendRcv;
461 rm_trans_map[MAP_ENTRY_SERVER_TO_CLIENT].transport_handle = Rm_transportRegister(&rm_trans_cfg, &rm_result);
462 }
464 void connection_close(void)
465 {
466 int32_t result;
468 printf("Closing connection to RM Server socket\n");
469 result = Rm_transportUnregister(rm_trans_map[MAP_ENTRY_SERVER_TO_CLIENT].transport_handle);
470 ERROR_CHECK(RM_OK, result, client_name, "Unregister of Server transport failed");
472 sock_close(client_sock);
473 }
475 int32_t client_init(void)
476 {
477 Rm_InitCfg rm_init_cfg;
478 int pthread_result;
479 int32_t result;
481 /* Initialize the pthread mutex */
482 if ((pthread_result = pthread_mutex_init(&client_mutex_lock, NULL))) {
483 printf("Error : Failed to init client pthread mutex with error code: %d\n", pthread_result);
484 test_errors++;
485 goto error_exit;
486 }
488 printf("Initializing RM Client\n");
489 memset(&rm_init_cfg, 0, sizeof(rm_init_cfg));
490 rm_init_cfg.instName = client_name;
491 rm_init_cfg.instType = Rm_instType_CLIENT;
492 rm_init_cfg.mtSemObj = (uint32_t *) &client_mutex_lock;
493 client_handle = Rm_init(&rm_init_cfg, &result);
494 ERROR_CHECK(RM_OK, result, client_name, "Initialization failed");
495 if (result != RM_OK) {
496 goto error_exit;
497 }
499 service_handle = Rm_serviceOpenHandle(client_handle, &result);
500 ERROR_CHECK(RM_OK, result, client_name, "Service handle open failed");
501 if (result != RM_OK) {
502 goto error_exit;
503 }
505 return (RM_TEST_TRUE);
506 error_exit:
507 return (RM_TEST_FALSE);
509 }
511 void client_cleanup(void)
512 {
513 int32_t result;
514 int pthread_result;
516 printf("Deleting RM Client\n");
518 if (service_handle) {
519 result = Rm_serviceCloseHandle(service_handle);
520 ERROR_CHECK(RM_OK, result, client_name, "Service handle close failed");
521 }
523 if (client_handle) {
524 result = Rm_delete(client_handle, RM_TEST_TRUE);
525 ERROR_CHECK(RM_OK, result, client_name, "Instance delete failed");
526 }
528 if ((pthread_result = pthread_mutex_destroy(&client_mutex_lock))) {
529 printf("Error : Failed to destroy client pthread mutex with error code: %d\n", pthread_result);
530 test_errors++;
531 }
532 }
534 int main(int argc, char *argv[])
535 {
536 int32_t malloc_free_diff;
537 int32_t byte_free_diff;
538 task_handle first_th;
539 task_handle second_th;
540 int status;
541 uint32_t i;
543 printf("*********************************************************\n");
544 printf("******** RM Linux Multi-Threaded Client Testing *********\n");
545 printf("*********************************************************\n");
547 printf("RM Version : 0x%08x\nVersion String: %s\n", Rm_getVersion(), Rm_getVersionStr());
549 test_errors = 0;
550 memset(&allocs[0], 0, sizeof(allocs));
552 if (client_init()) {
553 connection_setup();
555 printf("Creating first allocate_test thread\n");
556 if ((status = task_create(allocate_test, (void *)&thread_num_one, &first_th))) {
557 printf("ERROR : 1st \"Allocate Test\" task-create failed (%d)\n", status);
558 test_errors++;
559 goto cleanup_test;
560 }
561 printf("Creating second allocate_test thread\n");
562 if ((status = task_create(allocate_test, (void *)&thread_num_two, &second_th))) {
563 printf("ERROR : 2nd \"Allocate Test\" task-create failed (%d)\n", status);
564 test_errors++;
565 goto cleanup_test;
566 }
568 task_wait(&first_th);
569 task_wait(&second_th);
571 if (!test_errors) {
572 printf("Threads complete - Checking for allocation errors\n");
573 for (i = 0; i < REQUEST_ITERATIONS; i++) {
574 if (allocs[i] != 1) {
575 printf ("FAILED : Resource %d not allocated exactly once\n", i);
576 test_errors++;
577 }
578 }
580 if (!test_errors) {
581 printf("PASSED : All Resources allocated once\n");
582 }
583 }
585 resource_cleanup();
586 cleanup_test:
587 connection_close();
588 }
589 client_cleanup();
591 printf ("---------------------------------------------------------\n");
592 printf ("------------------ Memory Leak Check --------------------\n");
593 printf ("- : malloc count | free count -\n");
594 printf ("- Example Completion : %6d | %6d -\n", rmMallocCounter, rmFreeCounter);
595 printf ("- (bytes) : %8d | %8d -\n", rmByteAlloc, rmByteFree);
596 malloc_free_diff = rmMallocCounter - rmFreeCounter;
597 byte_free_diff = rmByteAlloc - rmByteFree;
598 if (malloc_free_diff > 0) {
599 printf ("- FAILED : %6d unfreed mallocs -\n", malloc_free_diff);
600 test_errors++;
601 }
602 else if (byte_free_diff > 0) {
603 printf ("- FAILED : %6d unfreed bytes -\n", byte_free_diff);
604 test_errors++;
605 }
606 else if (malloc_free_diff < 0) {
607 printf ("- FAILED : %6d more frees than mallocs -\n", -malloc_free_diff);
608 test_errors++;
609 }
610 else if (byte_free_diff < 0) {
611 printf ("- FAILED : %6d more bytes freed than malloc'd -\n", -byte_free_diff);
612 test_errors++;
613 }
614 else {
615 printf ("- PASSED -\n");
616 }
617 printf ("---------------------------------------------------------\n");
618 printf ("\n");
620 printf ("---------------------------------------------------------\n");
621 printf ("------------------ Example Completion -------------------\n");
622 if (test_errors) {
623 printf ("- FAILED : Test Errors: %-23d -\n", test_errors);
624 }
625 printf ("---------------------------------------------------------\n");
626 printf ("\n");
628 return (0);
629 }