]> Gitweb @ Texas Instruments - Open Source Git Repositories - git.TI.com/gitweb - keystone-rtos/rm-lld.git/blob - test/armv7/linux/rm_server.c
6e146167b3a205c84f1a10ce4341cc3f7a8743f4
[keystone-rtos/rm-lld.git] / test / armv7 / linux / rm_server.c
1 /*
2  * Copyright (C) 2013-2015 Texas Instruments Incorporated - http://www.ti.com/
3  *
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
15  *    distribution.
16  *
17  *    Neither the name of Texas Instruments Incorporated nor the names of
18  *    its contributors may be used to endorse or promote products derived
19  *    from this software without specific prior written permission.
20  *
21  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24  *  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25  *  OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26  *  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27  *  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28  *  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29  *  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30  *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31  *  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  */
34 /* Standard includes */
35 #include <stdio.h>
36 #include <errno.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #include <sys/mman.h>
40 #include <sys/stat.h>
41 #include <signal.h>
42 #include <fcntl.h>
43 #include <getopt.h>
44 #include <unistd.h>
46 #include <libdaemon/daemon.h>
48 /* Socket Includes */
49 #include "serverlogutil.h"
50 #include "sockutils.h"
51 #include "sockrmmsg.h"
53 /* RM includes */
54 #include <ti/drv/rm/rm.h>
55 #include <ti/drv/rm/rm_transport.h>
57 #define RMSERVER_DAEMON_PID_FILE_NAME "/var/run/rmServer/pid"
59 /* Error checking macro */
60 #define ERROR_CHECK(checkVal, resultVal, rmInstName, printMsg)            \
61     if (resultVal != checkVal) {                                          \
62         char errorMsgToPrint[] = printMsg;                                \
63         error_msg("%s : ", rmInstName);                                      \
64         error_msg("%s with error code : %d\n", errorMsgToPrint, resultVal);  \
65         exit(EXIT_FAILURE);                                               \
66     }
68 /* logging errors */
69 #define error_msg(...) rmsrv_log(LOG_ERR, __func__, __FILE__, __LINE__, __VA_ARGS__);
70 /* logging warnings */
71 #define warning_msg(...) rmsrv_log(LOG_WARNING, __func__, __FILE__, __LINE__, __VA_ARGS__);
72 /* logging information */
73 #define info_msg(...) rmsrv_log(LOG_INFO, __func__, __FILE__, __LINE__, __VA_ARGS__);
74 /* logging debug information */
75 #define debug_msg(...) rmsrv_log(LOG_DEBUG, __func__, __FILE__, __LINE__, __VA_ARGS__);
77 #define LOG_APPEND(x)                                      \
78     do {                                                   \
79         int len;                                           \
80         len = MAX_PRE_LOG_BUF_LEN - strlen(rmsrv_log_buf); \
81         if (len > 0) {                                     \
82             strncat(rmsrv_log_buf, x, len);                \
83         }                                                  \
84         else {                                             \
85             return;                                        \
86         }                                                  \
87     } while(0)
89 /* RM registered transport mapping structure */
90 typedef struct trans_map_entry_s {
91     /* Registered RM transport handle */
92     Rm_TransportHandle        trans_handle;
93     /* Remote socket tied to the transport handle */
94     sock_name_t              *remote_sock;
95     /* Next entry in the transport map */
96     struct trans_map_entry_s *n;
97 } trans_map_entry_t;
99 /**********************************************************************
100  ********************** Global Variables ******************************
101  **********************************************************************/
103 /* RM Server instance name (must match with RM Global Resource List (GRL) and policies */
104 char           server_name[RM_NAME_MAX_CHARS] = "RM_Server";
106 Rm_Handle      server_h;
108 sock_h         server_sock = NULL;
110 rmserver_cfg_t rmsrv_cfg;
112 char           rmsrv_log_buf[MAX_PRE_LOG_BUF_LEN];
114 /**********************************************************************
115  ********************** External Variables ****************************
116  **********************************************************************/
118 extern int   optind;
119 extern char *optarg;
121 /**********************************************************************
122  ************************** Server Functions **************************
123  **********************************************************************/
125 /* RM Server logging utility (need to move it to another file) */
126 void rmsrv_log(const int loglevel, const char* functionName, const char* fileName, const int lineNo, const char* format, ...)
128     int         len;
129     char        lineno_a[32];
130     va_list     args;
131     struct stat fbuf;
133     snprintf(lineno_a, MAX_PRE_LOG_BUF_LEN, "%d", lineNo);
135     rmsrv_log_buf[0] = 0;
137     LOG_APPEND(fileName);
138     LOG_APPEND(":");
139     LOG_APPEND(lineno_a);
140     LOG_APPEND(":");
141     LOG_APPEND(functionName);
142     LOG_APPEND(":");
144     len = MAX_PRE_LOG_BUF_LEN - strlen(rmsrv_log_buf);
145     if (len <= 0) {
146         return;
147     }
149     va_start(args, format);
150     vsnprintf(&rmsrv_log_buf[strlen(rmsrv_log_buf)], len, format, args);
151     va_end(args);
153     /* logfile reset if going over max_len */
154     if (fstat(fileno(rmsrv_cfg.logfile_p), &fbuf) == 0) {
155         if ((fbuf.st_size + strlen(rmsrv_log_buf)) > rmsrv_cfg.logfile_max_len) {
156             freopen(RMSERVER_DAEMON_LOG_FILE_NAME, "w+", rmsrv_cfg.logfile_p);
157         }
158     }
160     fprintf(rmsrv_cfg.logfile_p, "%s", rmsrv_log_buf);
161     fflush(rmsrv_cfg.logfile_p);
164 Rm_Packet *transportAlloc(Rm_AppTransportHandle appTransport, uint32_t pktSize, Rm_PacketHandle *pktHandle)
166     Rm_Packet *rm_pkt = NULL;
168     rm_pkt = calloc(1, sizeof(*rm_pkt));
169     if (!rm_pkt) {
170         error_msg("Failed to malloc RM packet (err: %s)\n",
171                   strerror(errno));
172         return (NULL);
173     }
174     rm_pkt->pktLenBytes = pktSize;
175     *pktHandle = rm_pkt;
177     return(rm_pkt);
180 void transportFree (Rm_Packet *rm_pkt)
182     int32_t status;
184     if (rm_pkt) {
185         free (rm_pkt);
186     }         
189 int32_t transportSend (Rm_AppTransportHandle appTransport, Rm_PacketHandle pktHandle)
191     sock_name_t *client_sock_name = (sock_name_t *)appTransport;
192     Rm_Packet   *rm_pkt = (Rm_Packet *)pktHandle;
193     
194     if (sock_send(server_sock, (char *)rm_pkt, (int) rm_pkt->pktLenBytes, client_sock_name)) {
195         error_msg("Failed to send RM packet\n");
196     }
197     else {
198         /* Print resources after sending response */
199         Rm_resourceStatus(server_h, 1);
200     }
202     transportFree(rm_pkt);
203     return (0);
206 int rm_server_run(void *grl, void *policy, void *lin_dtb, int is_daemon)
208     Rm_InitCfg          rm_init_cfg;
209     Rm_TransportCfg     rm_trans_cfg;
210     int32_t             rm_result;
211     trans_map_entry_t  *trans_map = NULL;
212     trans_map_entry_t  *new_map_entry;
213     trans_map_entry_t  *map_index;
214     int                 retval;
215     int                 length = 0;
216     sock_name_t         serv_sock_name;
217     sock_name_t         client_sock_addr;
218     Rm_Packet          *rm_pkt = NULL;
219     char                pkt_src[RM_NAME_MAX_CHARS];
220     struct sockaddr_un  client_addr; 
221     int                 signal_fd = -1;
222     char                rm_socket_name[] = RM_SERVER_SOCKET_NAME;
224     rmsrv_cfg.logfile_p = fopen(RMSERVER_DAEMON_LOG_FILE_NAME, "w+");
225     if (!rmsrv_cfg.logfile_p) {
226         printf("Error in opening log file %s (%s)", RMSERVER_DAEMON_LOG_FILE_NAME, strerror(errno));
227     }
229     debug_msg("Starting RM server");
230     
231     /* Create the Server instance */
232     memset(&rm_init_cfg, 0, sizeof(rm_init_cfg));
233     rm_init_cfg.instName = server_name;
234     rm_init_cfg.instType = Rm_instType_SERVER;
235     rm_init_cfg.instCfg.serverCfg.globalResourceList = grl;
236     rm_init_cfg.instCfg.serverCfg.linuxDtb = lin_dtb;
237     rm_init_cfg.instCfg.serverCfg.globalPolicy = policy;
238     server_h = Rm_init(&rm_init_cfg, &rm_result);
239     ERROR_CHECK(RM_OK, rm_result, server_name, "Initialization failed\n");
241     debug_msg("RM Server initialized with name: %s", server_name);
243     Rm_resourceStatus(server_h, 1);
244     
245     serv_sock_name.type = sock_name_e;
246     serv_sock_name.s.name = rm_socket_name;
247     server_sock = sock_open (&serv_sock_name);
248     if (!server_sock) {
249         error_msg("Error when opening socket %s", rm_socket_name);
250         return -1;
251     }
253     if (is_daemon){
254         signal_fd = daemon_signal_fd();
255     }
257     while(1) {
258         info_msg("Waiting for messages from Clients\n");
259         retval = sock_wait(server_sock, &length, NULL, signal_fd);
260         if (retval < 0) {
261             error_msg("Error in reading from socket\n");
262             goto loop_continue;
263         }
265         if (length < sizeof(rm_pkt)) {
266             error_msg("invalid RM message length %d\n", length);
267             goto loop_continue;
268         }
269         rm_pkt = calloc(1, length);
270         if (!rm_pkt) {
271             error_msg("can't malloc for recv'd RM message (err: %s)\n",
272                       strerror(errno));
273             goto loop_continue;
274         }
276         client_sock_addr.type = sock_addr_e;
277         client_sock_addr.s.addr = &client_addr;
278         retval = sock_recv(server_sock, (char *)rm_pkt, length, &client_sock_addr);
279         if (retval != length) {
280             error_msg("recv RM pkt failed from socket, received = %d, expected = %d\n",
281                       retval, length);
282             goto loop_continue;
283         }
285         info_msg("Received RM pkt of size %d bytes from socket %s\n", length, client_sock_addr.s.addr->sun_path);
286         if (Rm_receiveGetPktSrcName(rm_pkt, &pkt_src[0], RM_NAME_MAX_CHARS) == RM_OK) {
287             info_msg("    RM pkt originated from %s instance\n", &pkt_src[0]);
288         }
289         if (Rm_receiveGetPktServiceSrcName(rm_pkt, &pkt_src[0], RM_NAME_MAX_CHARS) == RM_OK) {
290             info_msg("    Service request within RM pkt originated from %s instance\n", &pkt_src[0]);
291         }
293         map_index = trans_map;
294         while(map_index != NULL) {
295             if (strncmp(map_index->remote_sock->s.addr->sun_path,
296                         client_addr.sun_path, 
297                         sizeof(client_addr.sun_path)) == 0) {
298                 break;
299             }
300             map_index = map_index->n;
301         }
303         if (!map_index) {
304             new_map_entry = calloc(1, sizeof(*new_map_entry));
305             new_map_entry->remote_sock = calloc(1, sizeof(sock_name_t));
306             new_map_entry->remote_sock->s.addr = calloc(1, sizeof(struct sockaddr_un));
307             new_map_entry->remote_sock->type = sock_addr_e;
308             memcpy(new_map_entry->remote_sock->s.addr, &client_addr, sizeof(struct sockaddr_un));
309                         
310             /* Register the Client with the Server instance */
311             rm_trans_cfg.rmHandle = server_h;
312             rm_trans_cfg.appTransportHandle = (Rm_AppTransportHandle)new_map_entry->remote_sock;
313             rm_trans_cfg.remoteInstType = Rm_instType_CLIENT;
314             rm_trans_cfg.transportCallouts.rmAllocPkt = transportAlloc;
315             rm_trans_cfg.transportCallouts.rmSendPkt = transportSend;
316             new_map_entry->trans_handle = Rm_transportRegister(&rm_trans_cfg, &rm_result);
318             new_map_entry->n = NULL;
320             if (trans_map == NULL) {
321                 trans_map = new_map_entry;
322             }
323             else {
324                 map_index = trans_map;
326                 while(map_index->n != NULL) {
327                     map_index = map_index->n;
328                 }
329                 map_index->n = new_map_entry;
330             }
332             map_index = new_map_entry;
333         }
335         /* Provide packet to RM Server for processing */       
336         if (rm_result = Rm_receivePacket(map_index->trans_handle, rm_pkt)) {
337             error_msg("RM failed to process received packet: %d\n", rm_result);
338         }
339         
340 loop_continue:
341         /* Cleanups */
342         length = 0;
343         transportFree(rm_pkt);
344         memset(&client_sock_addr, 0, sizeof(sock_name_t));
345         memset(&client_addr, 0, sizeof(struct sockaddr_un));
346     }   
349 char *get_pid_file_name(void) {
350         static char pid_file_name[] = RMSERVER_DAEMON_PID_FILE_NAME;
352         return pid_file_name;
355 static void print_usage(char *appname)
357     printf ("Usage: %s [OPTION]... [GRL] [POLICY]\n", appname);
358     printf ("Run a resource manager server with the specified [GRL] and [POLICY]\n"
359             "[GRL] and [POLICY] must be device tree blob (DTB) files\n"
360             "Example: rmserver grl.dtb policy.dtb\n\n"
361             "Configuration:\n"
362             "  -s, --logsize MAXLOGSIZE  MAXLOGSIZE bytes will be written to the\n"
363             "                            log file before the log is reset.  On\n"
364             "                            reset, the log file will be wiped.\n"
365             "\n"
366             "                            The default for MAXLOGSIZE is 8MB if\n"
367             "                            logsize is not specified\n"
368             "Optional Input:\n"
369             "  -l, --lindtb [LINUX_DTB]  Optionally, provide a Linux DTB file\n"
370             "                            that RM will use to reserve resources\n"
371             "                            for Linux.  The GRL must have the\n"
372             "                            proper Linux DTB resource mappings\n"
373             "                            for this feature to work\n"
374             "Miscellaneous:\n"
375             "  -n, --nodaemon            do not daemonize, run in foreground\n"
376             "  -k, --kill                kill the existing daemon\n"
377             "  -h, --help                print this message\n"
378             "\n"
379             "rmserver will run as a daemon by default.\n\n");
382 int main(int argc, char *argv[])
384     int          opt;
385     int          daemonize = 1, kill = 0;
386     int          fd;
387     struct stat  file_stat;
388     pid_t        pid;
389     char        *grl_file = NULL;
390     char        *policy_file = NULL;
391     char        *lin_dtb_file = NULL;
392     void        *grl = NULL;
393     void        *policy = NULL;
394     void        *lin_dtb = NULL;
395     
396     const struct option longopts[] =
397     {
398         {"nodaemon", no_argument,       0, 'n'},
399         {"kill",     no_argument,       0, 'k'},
400         {"help",     no_argument,       0, 'h'},
401         {"lindtb",   required_argument, 0, 'l'},
402         {"logsize",  required_argument, 0, 's'},
403         {0,          0,                 0,   0},
404     };
406     rmsrv_cfg.logfile_max_len = DEFAULT_LOG_LEN;
408     while((opt = getopt_long(argc, argv, "nkhl:s:", longopts, NULL)) != -1) {
409         switch (opt) {
410             case 'n':
411                 daemonize = 0;
412                 break;
413             case 'k':
414                 kill = 1;
415                 break;
416             case 'l':
417                 lin_dtb_file = optarg;
418                 break;
419             case 's':
420                 rmsrv_cfg.logfile_max_len = strtol(optarg, NULL, 0);
421                 break;
422             case 'h':
423             default:
424                 print_usage(argv[0]);
425                 exit(EXIT_SUCCESS);
426         }
427     }
429     if (!kill) {
430         /* GRL and Policy must always be provided */
431         if (optind == (argc - 2)) {
432             /* First must be GRL */
433             grl_file = argv[optind++];
434             /* Second must be policy */
435             policy_file = argv[optind++];  
436         }
437         else {
438             printf("GRL or policy not provided\n\n");
439             print_usage(argv[0]);
440             exit(EXIT_FAILURE);
441         }
443         /* mmap the GRL */
444         fd = open(grl_file, O_RDONLY);
445         if (fd == -1) {
446             printf("Error opening GRL: %s\n", strerror(errno));
447             exit(EXIT_FAILURE);
448         }
449         /* Obtain file size */
450         if (fstat(fd, &file_stat) == -1) {
451             printf("Error getting GRL size\n");
452             exit(EXIT_FAILURE);
453         }
454         grl = mmap(NULL, file_stat.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
455         if (grl == MAP_FAILED) {
456             printf("mmap of GRL failed\n");
457             exit(EXIT_FAILURE);
458         }
460         /* mmap the Global Policy */
461         fd = open(policy_file, O_RDONLY);
462         if (fd == -1) {
463             printf("Error opening Global Policy: %s\n", strerror(errno));
464             exit(EXIT_FAILURE);
465         }
466         /* Obtain file size */
467         if (fstat(fd, &file_stat) == -1) {
468             printf("Error getting Global Policy size\n");
469             exit(EXIT_FAILURE);
470         }
471         policy = mmap(NULL, file_stat.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
472         if (policy == MAP_FAILED) {
473             printf("mmap of Global Policy failed\n");
474             exit(EXIT_FAILURE);
475         }
477         if (lin_dtb_file) {
478             /* mmap the Linux DTB if it was provided */
479             fd = open(lin_dtb_file, O_RDONLY);
480             if (fd == -1) {
481                 printf("Error opening Linux DTB: %s\n", strerror(errno));
482                 exit(EXIT_FAILURE);
483             }
484             /* Obtain file size */
485             if (fstat(fd, &file_stat) == -1) {
486                 printf("Error getting Linux DTB size\n");
487                 exit(EXIT_FAILURE);
488             }
489             lin_dtb = mmap(NULL, file_stat.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
490             if (lin_dtb == MAP_FAILED) {
491                 printf("mmap of Linux DTB failed\n");
492                 exit(EXIT_FAILURE);
493             }
494         }        
495     }
497     if (daemonize) {
498         if (kill) {
499             printf("Killing %s\n", argv[0]);
500         }
501         else {
502             printf("Starting %s\n", argv[0]);
503         }
505         /* Reset signal handlers */
506         if (daemon_reset_sigs(-1) < 0) {
507             printf("Failed to reset all signal handlers: %s\n", strerror(errno));
508             exit(EXIT_FAILURE);
509         }
511         /* Unblock signals */
512         if (daemon_unblock_sigs(-1) < 0) {
513             printf("Failed to unblock all signals: %s\n", strerror(errno));
514             exit(EXIT_FAILURE);
515         }
517         if (check_and_create_path (get_pid_file_name()) < 0) {
518             printf("Failed to create pid file path: %s\n", get_pid_file_name());
519             exit(EXIT_FAILURE);
520         }
522         /* set daemon id string */
523         daemon_log_ident = daemon_ident_from_argv0(argv[0]);
524         daemon_pid_file_proc = (daemon_pid_file_proc_t) get_pid_file_name;
526         if (kill) {
527             if (daemon_pid_file_kill_wait(SIGTERM, 5) < 0) {
528                 printf("Failed to kill daemon: %s\n", strerror(errno));
529                 exit(EXIT_FAILURE);
530             }
531             daemon_pid_file_remove();
532             exit(EXIT_SUCCESS);
533         }
535         /* Single instance */
536         if ((pid = daemon_pid_file_is_running()) >= 0) {
537             printf("Daemon already running on PID file %u\n", pid);
538             exit(EXIT_FAILURE);
539         }
541         if (daemon_retval_init() < 0) {
542             printf("Failed to create pipe.\n");
543             exit(EXIT_FAILURE);
544         }
546         /* Do the fork */
547         if ((pid = daemon_fork()) < 0) {
548             daemon_retval_done();
549             printf("Error in daemon fork %s\n", strerror(errno));
550             exit(EXIT_FAILURE);
551         } 
552         else if (pid) { /* The parent */
553             int ret;
555             /* Wait for 20 seconds for the return value passed from the daemon process */
556             if ((ret = daemon_retval_wait(20)) < 0) {
557                 printf("Could not receive return value from daemon process: %s\n", strerror(errno));
558                 return -1;
559             }
561             printf("Daemon returned %i as return value.\n", ret);
562             return ret;
563         }
565         /* Close FDs */
566         if (daemon_close_all(-1) < 0) {
567             printf("Failed to close all file descriptors: %s\n", strerror(errno));
569             /* Send the error condition to the parent process */
570             daemon_retval_send(1);
571             goto close_n_exit;
572         }
574         /* Create the PID file */
575         if (daemon_pid_file_create() < 0) {
576             printf("Could not create PID file (%s).\n", strerror(errno));
577             daemon_retval_send(2);
578             goto close_n_exit;
579         }
581         /* Initialize signal handling */
582         if (daemon_signal_init(SIGINT, SIGTERM, SIGQUIT, SIGHUP, 0) < 0) {
583             printf("Could not register signal handlers (%s).\n", strerror(errno));
584             daemon_retval_send(3);
585             goto close_n_exit;
586         }
588         /* Send OK to parent process */
589         daemon_retval_send(0);
590     }
591     else {
592         if (kill) {
593             printf("Can't kill undaemonized RM server\n");
594             exit(EXIT_FAILURE);
595         }
596     }
597     
598     rm_server_run(grl, policy, lin_dtb, daemonize);
600 close_n_exit:
601     printf("Exiting %s daemon\n", argv[0]);
602     if (daemonize) {
603         daemon_retval_send(255);
604         daemon_signal_done();
605         daemon_pid_file_remove();
606     }