]> Gitweb @ Texas Instruments - Open Source Git Repositories - git.TI.com/gitweb - keystone-rtos/rm-lld.git/blob - test/armv7/linux/rm_linux_mt_client_test.c
Resolved code review comments and -Wall -Wexta warnings
[keystone-rtos/rm-lld.git] / test / armv7 / linux / rm_linux_mt_client_test.c
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:
53   * warning: unused parameter \91appTransport\92 [-Wunused-parameter]
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[] = "/tmp/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)
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(&param, 0, sizeof(param));
217     param.sched_priority = max_priority;
218     err = pthread_attr_setschedparam(&attr, &param);
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;
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)
245     pthread_join(*((pthread_t *)handle), NULL);
246     return;
250 Rm_Packet *transportAlloc(Rm_AppTransportHandle appTransport, uint32_t pktSize, Rm_PacketHandle *pktHandle)
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);
266 void transportFree (Rm_Packet *rm_pkt)
268     if (rm_pkt) {
269         free (rm_pkt);
270     }         
273 void transportReceive (void)
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;
281     
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     }
292     
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     }
305     
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);
323 int32_t transportSendRcv(Rm_AppTransportHandle appTransport, Rm_PacketHandle pktHandle)
325     sock_name_t *server_sock_name = (sock_name_t *)appTransport;
326     Rm_Packet   *rm_pkt = (Rm_Packet *)pktHandle;
327     
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();
334  
335     return (0);
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)
349     uint32_t           *thread_num = (uint32_t *)args;
350     Rm_ServiceReqInfo   request;
351     Rm_ServiceRespInfo  response;
352     uint32_t            i;
353     struct timespec     tim;
354     
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;
395 void resource_cleanup(void)
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     }
426 void connection_setup(void)
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");
435     
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);
464 void connection_close(void)
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);
475 int32_t client_init(void)
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);
508     
511 void client_cleanup(void)
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     }
522     
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     }
527     
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     }
534 int main(int argc, char *argv[])
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();
590     
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);