]> 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
44099f7315a81abf071715f9989da3a0b1351c7a
[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  */
41  
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)
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(&param, 0, sizeof(param));
198     param.sched_priority = max_priority;
199     err = pthread_attr_setschedparam(&attr, &param);
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;
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)
226     pthread_join(*((pthread_t *)handle), NULL);
227     return;
231 Rm_Packet *transportAlloc(Rm_AppTransportHandle appTransport, uint32_t pktSize, Rm_PacketHandle *pktHandle)
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);
246 void transportFree (Rm_Packet *rm_pkt)
248     if (rm_pkt) {
249         free (rm_pkt);
250     }         
253 void transportReceive (void)
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;    
261     
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     }
271     
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     }
282     
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);
300 int32_t transportSendRcv(Rm_AppTransportHandle appTransport, Rm_PacketHandle pktHandle)
302     sock_name_t *server_sock_name = (sock_name_t *)appTransport;
303     Rm_Packet   *rm_pkt = (Rm_Packet *)pktHandle;
304     
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();
311  
312     return (0);
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)
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;
333     
334     tim.tv_sec = 0;
335     tim.tv_nsec = 1000;
336     
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     }
375     
376     pthread_exit((void*) 0);
377     return NULL;
380 void resource_cleanup(void)
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         }
413         
414         Rm_serviceCloseHandle(service_handle);
415     }
418 void connection_setup(void)
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");
428     
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);    
457 void connection_close(void)
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);
468 int32_t client_init(void)
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);
495     
498 void client_cleanup(void)
500     int32_t result;
501     int     pthread_result;
503     printf("Deleting RM Client\n");
504     
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     }
509     
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     }
515 int main(int argc, char *argv[])
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();
568     
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);