44099f7315a81abf071715f9989da3a0b1351c7a
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 /* Standard includes */
43 #include <stdio.h>
44 #include <errno.h>
45 #include <stdlib.h>
46 #include <string.h>
47 #include <unistd.h>
48 #include <pthread.h>
49 #include <time.h>
51 /* Socket Includes */
52 #include "sockutils.h"
53 #include "sockrmmsg.h"
55 /* RM Includes */
56 #include <ti/drv/rm/rm.h>
57 #include <ti/drv/rm/rm_transport.h>
58 #include <ti/drv/rm/rm_services.h>
60 /**********************************************************************
61 ************************** RM Test Symbols ***************************
62 **********************************************************************/
64 /* Total resource request iterations between threads */
65 #define REQUEST_ITERATIONS 16000
66 #define RESOURCE_PRINT_DIVISOR 1000
68 /* Test FALSE */
69 #define RM_TEST_FALSE 0
70 /* Test TRUE */
71 #define RM_TEST_TRUE 1
73 /* Socket timeout */
74 #define CLIENT_SOCK_TIMEOUT_USEC (500)
76 /* Application's registered RM transport indices */
77 #define MAP_ENTRY_SERVER_TO_CLIENT 0
78 /* Maximum number of registered RM transports */
79 #define MAX_MAPPING_ENTRIES 1
81 /* Error checking macro */
82 #define ERROR_CHECK(checkVal, resultVal, rmInstName, printMsg) \
83 if (resultVal != checkVal) { \
84 char errorMsgToPrint[] = printMsg; \
85 printf("Error : %s : ", rmInstName); \
86 printf("%s with error code : %d\n", errorMsgToPrint, resultVal); \
87 test_errors++; \
88 }
90 /**********************************************************************
91 ********************** RM Test Data Structures ***********************
92 **********************************************************************/
94 /* RM registered transport mapping structure */
95 typedef struct trans_map_entry_s {
96 /* Registered RM transport handle */
97 Rm_TransportHandle transport_handle;
98 /* Remote socket tied to the transport handle */
99 sock_name_t *remote_sock;
100 } trans_map_entry_t;
102 /**********************************************************************
103 ********************** Extern Variables ******************************
104 **********************************************************************/
106 /* Alloc and free OSAL variables */
107 extern uint32_t rmMallocCounter;
108 extern uint32_t rmFreeCounter;
110 /**********************************************************************
111 ********************** Global Variables ******************************
112 **********************************************************************/
114 /* Number of errors that occurred during the test */
115 uint16_t test_errors;
117 /* Non-Serial client instance name */
118 char client_name[RM_NAME_MAX_CHARS] = "RM_Client";
120 /* Non-Serial client instance handle */
121 Rm_Handle client_handle = NULL;
123 /* pthread mutex lock needed for testing */
124 pthread_mutex_t client_mutex_lock;
126 /* Client socket name */
127 char client_sock_name[] = "/tmp/var/run/rm/rm_client";
129 /* Client socket handles */
130 sock_h client_sock;
132 /* Transport map stores the RM transport handle to IPC MessageQ queue mapping */
133 trans_map_entry_t rm_trans_map[MAX_MAPPING_ENTRIES];
135 /* RM resource names (must match resource node names in GRL and policies */
136 char res_name_link_ram[RM_NAME_MAX_CHARS] = "link-ram";
138 uint32_t allocs[REQUEST_ITERATIONS];
140 /**********************************************************************
141 *************************** Test Functions ***************************
142 **********************************************************************/
144 uint32_t thread_num_one = 1;
145 uint32_t thread_num_two = 2;
147 typedef pthread_t task_handle;
149 #define DEFAULT_STACK_SIZE 0x8000
150 /** ============================================================================
151 * @n@b task_create
152 *
153 * @b Description
154 * @n Create thread to run the test program
155 *
156 * @param[in]
157 * @n None
158 *
159 * @return int32_t
160 * -1 - Error
161 * 0 - Success
162 * =============================================================================
163 */
164 static int task_create (void *(start_routine)(void *), void* args, void* handle)
165 {
166 int max_priority, err;
167 pthread_t thread;
168 pthread_attr_t attr;
169 struct sched_param param;
171 max_priority = sched_get_priority_max(SCHED_FIFO);
172 err = pthread_attr_init(&attr);
173 if (err) {
174 printf("pthread_attr_init failed: (%s)\n", strerror(err));
175 return err;
176 }
177 err = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
178 if (err) {
179 printf("pthread_attr_setdetachstate failed: (%s)\n", strerror(err));
180 return err;
181 }
182 err = pthread_attr_setstacksize(&attr, DEFAULT_STACK_SIZE);
183 if (err) {
184 printf("pthread_attr_setstacksize failed: (%s)\n", strerror(err));
185 return err;
186 }
187 err = pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED);
188 if (err) {
189 printf("pthread_attr_setinheritsched failed: (%s)\n", strerror(err));
190 return err;
191 }
192 err = pthread_attr_setschedpolicy(&attr, SCHED_FIFO);
193 if (err) {
194 printf("pthread_attr_setschedpolicy failed: (%s)\n", strerror(err));
195 return err;
196 }
197 memset(¶m, 0, sizeof(param));
198 param.sched_priority = max_priority;
199 err = pthread_attr_setschedparam(&attr, ¶m);
200 if (err) {
201 printf("pthread_attr_setschedparam failed: (%s)\n", strerror(err));
202 return err;
203 }
204 if (err) return err;
205 err = pthread_create(&thread, &attr, start_routine, args);
206 if (err) {
207 printf("pthread_create failed: (%s)\n", strerror(err));
208 return err;
209 }
210 if (err) return err;
211 *(pthread_t *)handle = thread;
212 return 0;
213 }
215 /** ============================================================================
216 * @n@b task_wait
217 *
218 * @b Description
219 * @n Wait for Task completion
220 *
221 * @return void
222 * =============================================================================
223 */
224 static void task_wait (void *handle)
225 {
226 pthread_join(*((pthread_t *)handle), NULL);
227 return;
228 }
231 Rm_Packet *transportAlloc(Rm_AppTransportHandle appTransport, uint32_t pktSize, Rm_PacketHandle *pktHandle)
232 {
233 Rm_Packet *rm_pkt = NULL;
235 rm_pkt = calloc(1, sizeof(*rm_pkt));
236 if (!rm_pkt) {
237 printf("Error: Can't malloc for RM send message (err: %s)\n", strerror(errno));
238 return (NULL);
239 }
240 rm_pkt->pktLenBytes = pktSize;
241 *pktHandle = rm_pkt;
243 return(rm_pkt);
244 }
246 void transportFree (Rm_Packet *rm_pkt)
247 {
248 if (rm_pkt) {
249 free (rm_pkt);
250 }
251 }
253 void transportReceive (void)
254 {
255 int32_t rm_result;
256 int retval;
257 int length = 0;
258 sock_name_t server_sock_addr;
259 Rm_Packet *rm_pkt = NULL;
260 struct sockaddr_un server_addr;
262 retval = sock_wait(client_sock, &length, NULL, -1);
263 if (retval == -2) {
264 /* Timeout */
265 return;
266 }
267 else if (retval < 0) {
268 printf("Error in reading from socket, error %d\n", retval);
269 return;
270 }
272 if (length < sizeof(*rm_pkt)) {
273 printf("invalid RM message length %d\n", length);
274 return;
275 }
276 rm_pkt = calloc(1, length);
277 if (!rm_pkt) {
278 printf("can't malloc for recv'd RM message (err: %s)\n",
279 strerror(errno));
280 return;
281 }
283 server_sock_addr.type = sock_addr_e;
284 server_sock_addr.s.addr = &server_addr;
285 retval = sock_recv(client_sock, (char *)rm_pkt, length, &server_sock_addr);
286 if (retval != length) {
287 printf("recv RM pkt failed from socket, received = %d, expected = %d\n",
288 retval, length);
289 return;
290 }
292 /* Provide packet to RM Server for processing */
293 if (rm_result = Rm_receivePacket(rm_trans_map[MAP_ENTRY_SERVER_TO_CLIENT].transport_handle, rm_pkt)) {
294 printf("RM failed to process received packet: %d\n", rm_result);
295 }
297 transportFree(rm_pkt);
298 }
300 int32_t transportSendRcv(Rm_AppTransportHandle appTransport, Rm_PacketHandle pktHandle)
301 {
302 sock_name_t *server_sock_name = (sock_name_t *)appTransport;
303 Rm_Packet *rm_pkt = (Rm_Packet *)pktHandle;
305 if (sock_send(client_sock, (char *)rm_pkt, (int) rm_pkt->pktLenBytes, server_sock_name)) {
306 printf("send data failed\n");
307 }
309 /* Wait for response from Server */
310 transportReceive();
312 return (0);
313 }
315 /** ============================================================================
316 * @n@b odd_test
317 *
318 * @b Description
319 * @n Resource request routine running as a separate thread
320 *
321 * @return void *
322 * =============================================================================
323 */
324 void *allocate_test (void *args)
325 {
326 uint32_t *thread_num = (uint32_t *)args;
327 Rm_ServiceHandle *service_handle = NULL;
328 int32_t result;
329 Rm_ServiceReqInfo request;
330 Rm_ServiceRespInfo response;
331 uint32_t i;
332 struct timespec tim;
334 tim.tv_sec = 0;
335 tim.tv_nsec = 1000;
337 service_handle = Rm_serviceOpenHandle(client_handle, &result);
338 ERROR_CHECK(RM_OK, result, client_name, "Service handle open failed");
340 if (service_handle) {
341 /* Init request - request one resource at a time as unspecified. Server
342 * will return next available resource */
343 memset(&request, 0, sizeof(request));
344 request.type = Rm_service_RESOURCE_ALLOCATE_INIT;
345 request.resourceName = res_name_link_ram;
346 request.resourceBase = RM_RESOURCE_BASE_UNSPECIFIED;
347 request.resourceLength = 1;
349 printf("Thread %d : Requesting %d resources...\n", *thread_num, REQUEST_ITERATIONS / 2);
350 for (i = 0; i < (REQUEST_ITERATIONS / 2); i++) {
351 memset(&response, 0, sizeof(response));
352 service_handle->Rm_serviceHandler(service_handle->rmHandle, &request, &response);
354 if (response.serviceState == RM_SERVICE_APPROVED) {
355 allocs[response.resourceBase]++;
356 nanosleep(&tim , NULL);
358 if ((i % RESOURCE_PRINT_DIVISOR) == 0) {
359 printf("Thread %d : Requested %d resources...\n", *thread_num, RESOURCE_PRINT_DIVISOR);
360 }
361 }
362 else {
363 printf("Error Thread %d : Allocate request was not approved for resource %d - Exiting...\n",
364 *thread_num, request.resourceBase);
365 test_errors++;
366 goto error_exit;
367 }
368 }
369 }
371 error_exit:
372 if (service_handle) {
373 Rm_serviceCloseHandle(service_handle);
374 }
376 pthread_exit((void*) 0);
377 return NULL;
378 }
380 void resource_cleanup(void)
381 {
382 Rm_ServiceHandle *service_handle = NULL;
383 int32_t result;
384 Rm_ServiceReqInfo request;
385 Rm_ServiceRespInfo response;
386 uint32_t i;
388 service_handle = Rm_serviceOpenHandle(client_handle, &result);
389 ERROR_CHECK(RM_OK, result, client_name, "Service handle open failed");
391 if (service_handle) {
392 printf("Freeing all %d resources...\n", REQUEST_ITERATIONS);
393 for (i = 0; i < (REQUEST_ITERATIONS); i++) {
394 while (allocs[i]) {
395 memset(&request, 0, sizeof(request));
396 request.type = Rm_service_RESOURCE_FREE;
397 request.resourceName = res_name_link_ram;
398 request.resourceBase = i;
399 request.resourceLength = 1;
401 memset(&response, 0, sizeof(response));
402 service_handle->Rm_serviceHandler(service_handle->rmHandle, &request, &response);
404 if (response.serviceState != RM_SERVICE_APPROVED) {
405 printf("Error: Free request was not approved for resource %d - Exiting...\n",
406 request.resourceBase);
407 test_errors++;
408 }
410 allocs[i]--;
411 }
412 }
414 Rm_serviceCloseHandle(service_handle);
415 }
416 }
418 void connection_setup(void)
419 {
420 Rm_TransportCfg rm_trans_cfg;
421 int32_t rm_result;
422 int i;
423 sock_name_t sock_name;
424 int32_t result = 0;
425 char server_sock_name[] = RM_SERVER_SOCKET_NAME;
427 printf("Setting up socket connection to RM Server\n");
429 /* Initialize the transport map */
430 for (i = 0; i < MAX_MAPPING_ENTRIES; i++) {
431 rm_trans_map[i].transport_handle = NULL;
432 }
434 sock_name.type = sock_name_e;
435 sock_name.s.name = client_sock_name;
437 client_sock = sock_open(&sock_name);
438 if (!client_sock) {
439 printf("Client socket open failed\n");
440 exit(EXIT_FAILURE);
441 }
443 rm_trans_map[MAP_ENTRY_SERVER_TO_CLIENT].remote_sock = calloc(1, sizeof(sock_name_t));
444 rm_trans_map[MAP_ENTRY_SERVER_TO_CLIENT].remote_sock->type = sock_name_e;
445 rm_trans_map[MAP_ENTRY_SERVER_TO_CLIENT].remote_sock->s.name = calloc(1, strlen(server_sock_name)+1);
446 strncpy(rm_trans_map[MAP_ENTRY_SERVER_TO_CLIENT].remote_sock->s.name, server_sock_name, strlen(server_sock_name)+1);
448 /* Register the Server with the Client instance */
449 rm_trans_cfg.rmHandle = client_handle;
450 rm_trans_cfg.appTransportHandle = (Rm_AppTransportHandle) rm_trans_map[MAP_ENTRY_SERVER_TO_CLIENT].remote_sock;
451 rm_trans_cfg.remoteInstType = Rm_instType_SERVER;
452 rm_trans_cfg.transportCallouts.rmAllocPkt = transportAlloc;
453 rm_trans_cfg.transportCallouts.rmSendPkt = transportSendRcv;
454 rm_trans_map[MAP_ENTRY_SERVER_TO_CLIENT].transport_handle = Rm_transportRegister(&rm_trans_cfg, &rm_result);
455 }
457 void connection_close(void)
458 {
459 int32_t result;
461 printf("Closing connection to RM Server socket\n");
462 result = Rm_transportUnregister(rm_trans_map[MAP_ENTRY_SERVER_TO_CLIENT].transport_handle);
463 ERROR_CHECK(RM_OK, result, client_name, "Unregister of Server transport failed");
465 sock_close(client_sock);
466 }
468 int32_t client_init(void)
469 {
470 Rm_InitCfg rm_init_cfg;
471 int pthread_result;
472 int32_t result;
474 /* Initialize the pthread mutex */
475 if (pthread_result = pthread_mutex_init(&client_mutex_lock, NULL)) {
476 printf("Error : Failed to init client pthread mutex with error code: \n", pthread_result);
477 test_errors++;
478 goto error_exit;
479 }
481 printf("Initializing RM Client\n");
482 memset(&rm_init_cfg, 0, sizeof(rm_init_cfg));
483 rm_init_cfg.instName = client_name;
484 rm_init_cfg.instType = Rm_instType_CLIENT;
485 rm_init_cfg.mtSemObj = (uint32_t *) &client_mutex_lock;
486 client_handle = Rm_init(&rm_init_cfg, &result);
487 ERROR_CHECK(RM_OK, result, client_name, "Initialization failed");
488 if (result != RM_OK) {
489 goto error_exit;
490 }
492 return (RM_TEST_TRUE);
493 error_exit:
494 return (RM_TEST_FALSE);
496 }
498 void client_cleanup(void)
499 {
500 int32_t result;
501 int pthread_result;
503 printf("Deleting RM Client\n");
505 if (client_handle) {
506 result = Rm_delete(client_handle, RM_TEST_TRUE);
507 ERROR_CHECK(RM_OK, result, client_name, "Instance delete failed");
508 }
510 if (pthread_result = pthread_mutex_destroy(&client_mutex_lock)) {
511 printf("Error : Failed to destroy client pthread mutex with error code: \n", pthread_result);
512 }
513 }
515 int main(int argc, char *argv[])
516 {
517 int32_t result;
518 int32_t malloc_free_diff;
519 task_handle first_th;
520 task_handle second_th;
521 int status;
522 uint32_t i;
524 printf("*********************************************************\n");
525 printf("******** RM Linux Multi-Threaded Client Testing *********\n");
526 printf("*********************************************************\n");
528 printf("RM Version : 0x%08x\nVersion String: %s\n", Rm_getVersion(), Rm_getVersionStr());
530 test_errors = 0;
531 memset(&allocs[0], 0, sizeof(allocs));
533 if (client_init()) {
534 connection_setup();
536 printf("Creating first allocate_test thread\n");
537 if ((status = task_create(allocate_test, (void *)&thread_num_one, &first_th))) {
538 printf("ERROR: 1st \"Allocate Test\" task-create failed (%d)\n", status);
539 goto cleanup_test;
540 }
541 printf("Creating second allocate_test thread\n");
542 if ((status = task_create(allocate_test, (void *)&thread_num_two, &second_th))) {
543 printf("ERROR: 2nd \"Allocate Test\" task-create failed (%d)\n", status);
544 goto cleanup_test;
545 }
547 task_wait(&first_th);
548 task_wait(&second_th);
550 if (!test_errors) {
551 for (i = 0; i < REQUEST_ITERATIONS; i++) {
552 if (allocs[i] != 1) {
553 printf ("FAILED: Resource %d not allocated exactly once\n", i);
554 test_errors++;
555 }
556 }
558 if (!test_errors) {
559 printf("PASSED: All Resources allocated once\n");
560 }
561 }
563 resource_cleanup();
564 cleanup_test:
565 connection_close();
566 }
567 client_cleanup();
569 printf ("---------------------------------------------------------\n");
570 printf ("------------------ Memory Leak Check --------------------\n");
571 printf ("- : malloc count | free count -\n");
572 printf ("- Example Completion : %6d | %6d -\n", rmMallocCounter, rmFreeCounter);
573 malloc_free_diff = rmMallocCounter - rmFreeCounter;
574 if (malloc_free_diff > 0) {
575 printf ("- FAILED - %6d unfreed mallocs -\n", malloc_free_diff);
576 test_errors++;
577 }
578 else if (malloc_free_diff < 0) {
579 printf ("- FAILED - %6d more frees than mallocs -\n", -malloc_free_diff);
580 test_errors++;
581 }
582 else {
583 printf ("- PASSED -\n");
584 }
585 printf ("---------------------------------------------------------\n");
586 printf ("\n");
588 printf ("---------------------------------------------------------\n");
589 printf ("------------------ Example Completion -------------------\n");
590 if (test_errors) {
591 printf ("- Test Errors: %-32d -\n", test_errors);
592 }
593 printf ("---------------------------------------------------------\n");
594 printf ("\n");
596 return (0);
597 }