]> Gitweb @ Texas Instruments - Open Source Git Repositories - git.TI.com/gitweb - keystone-rtos/rm-lld.git/blob - test/k2k/armv7/linux/rm_server.c
Added optional input for max logfile size
[keystone-rtos/rm-lld.git] / test / k2k / armv7 / linux / rm_server.c
1 /*
2  * Copyright (C) 2013-2014 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     sprintf(lineno_a, "%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     fstat(fileno(rmsrv_cfg.logfile_p), &fbuf);
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     }
159     fprintf(rmsrv_cfg.logfile_p, "%s", rmsrv_log_buf);
160     fflush(rmsrv_cfg.logfile_p);
163 Rm_Packet *transportAlloc(Rm_AppTransportHandle appTransport, uint32_t pktSize, Rm_PacketHandle *pktHandle)
165     Rm_Packet *rm_pkt = NULL;
167     rm_pkt = calloc(1, sizeof(*rm_pkt));
168     if (!rm_pkt) {
169         error_msg("Failed to malloc RM packet (err: %s)\n",
170                   strerror(errno));
171         return (NULL);
172     }
173     rm_pkt->pktLenBytes = pktSize;
174     *pktHandle = rm_pkt;
176     return(rm_pkt);
179 void transportFree (Rm_Packet *rm_pkt)
181     int32_t status;
183     if (rm_pkt) {
184         free (rm_pkt);
185     }         
188 int32_t transportSend (Rm_AppTransportHandle appTransport, Rm_PacketHandle pktHandle)
190     sock_name_t *client_sock_name = (sock_name_t *)appTransport;
191     Rm_Packet   *rm_pkt = (Rm_Packet *)pktHandle;
192     
193     if (sock_send(server_sock, (char *)rm_pkt, (int) rm_pkt->pktLenBytes, client_sock_name)) {
194         error_msg("Failed to send RM packet\n");
195     }
196     else {
197         /* Print resources after sending response */
198         Rm_resourceStatus(server_h, 1);
199     }
201     transportFree(rm_pkt);
202     return (0);
205 int rm_server_run(void *grl, void *policy, void *lin_dtb, int is_daemon)
207     Rm_InitCfg          rm_init_cfg;
208     Rm_TransportCfg     rm_trans_cfg;
209     int32_t             rm_result;
210     trans_map_entry_t  *trans_map = NULL;
211     trans_map_entry_t  *new_map_entry;
212     trans_map_entry_t  *map_index;
213     int                 retval;
214     int                 length = 0;
215     sock_name_t         serv_sock_name;
216     sock_name_t         client_sock_addr;
217     Rm_Packet          *rm_pkt = NULL;
218     char                pkt_src[RM_NAME_MAX_CHARS];
219     struct sockaddr_un  client_addr; 
220     int                 signal_fd = -1;
221     char                rm_socket_name[] = RM_SERVER_SOCKET_NAME;
223     rmsrv_cfg.logfile_p = fopen(RMSERVER_DAEMON_LOG_FILE_NAME, "w+");
224     if (!rmsrv_cfg.logfile_p) {
225         printf("Error in opening log file %s (%s)", RMSERVER_DAEMON_LOG_FILE_NAME, strerror(errno));
226     }
228     debug_msg("Starting RM server");
229     
230     /* Create the Server instance */
231     memset(&rm_init_cfg, 0, sizeof(rm_init_cfg));
232     rm_init_cfg.instName = server_name;
233     rm_init_cfg.instType = Rm_instType_SERVER;
234     rm_init_cfg.instCfg.serverCfg.globalResourceList = grl;
235     rm_init_cfg.instCfg.serverCfg.linuxDtb = lin_dtb;
236     rm_init_cfg.instCfg.serverCfg.globalPolicy = policy;
237     server_h = Rm_init(&rm_init_cfg, &rm_result);
238     ERROR_CHECK(RM_OK, rm_result, server_name, "Initialization failed\n");
240     debug_msg("RM Server initialized with name: %s", server_name);
242     Rm_resourceStatus(server_h, 1);
243     
244     serv_sock_name.type = sock_name_e;
245     serv_sock_name.s.name = rm_socket_name;
246     server_sock = sock_open (&serv_sock_name);
247     if (!server_sock) {
248         error_msg("Error when opening socket %s", rm_socket_name);
249         return -1;
250     }
252     if (is_daemon){
253         signal_fd = daemon_signal_fd();
254     }
256     while(1) {
257         info_msg("Waiting for messages from Clients\n");
258         retval = sock_wait(server_sock, &length, NULL, signal_fd);
259         if (retval < 0) {
260             error_msg("Error in reading from socket\n");
261             goto loop_continue;
262         }
264         if (length < sizeof(rm_pkt)) {
265             error_msg("invalid RM message length %d\n", length);
266             goto loop_continue;
267         }
268         rm_pkt = calloc(1, length);
269         if (!rm_pkt) {
270             error_msg("can't malloc for recv'd RM message (err: %s)\n",
271                       strerror(errno));
272             goto loop_continue;
273         }
275         client_sock_addr.type = sock_addr_e;
276         client_sock_addr.s.addr = &client_addr;
277         retval = sock_recv(server_sock, (char *)rm_pkt, length, &client_sock_addr);
278         if (retval != length) {
279             error_msg("recv RM pkt failed from socket, received = %d, expected = %d\n",
280                       retval, length);
281             goto loop_continue;
282         }
284         info_msg("Received RM pkt of size %d bytes from socket %s\n", length, client_sock_addr.s.addr->sun_path);
285         if (Rm_receiveGetPktSrcName(rm_pkt, &pkt_src[0], RM_NAME_MAX_CHARS) == RM_OK) {
286             info_msg("    RM pkt originated from %s instance\n", &pkt_src[0]);
287         }
288         if (Rm_receiveGetPktServiceSrcName(rm_pkt, &pkt_src[0], RM_NAME_MAX_CHARS) == RM_OK) {
289             info_msg("    Service request within RM pkt originated from %s instance\n", &pkt_src[0]);
290         }
292         map_index = trans_map;
293         while(map_index != NULL) {
294             if (strncmp(map_index->remote_sock->s.addr->sun_path,
295                         client_addr.sun_path, 
296                         sizeof(client_addr.sun_path)) == 0) {
297                 break;
298             }
299             map_index = map_index->n;
300         }
302         if (!map_index) {
303             new_map_entry = calloc(1, sizeof(*new_map_entry));
304             new_map_entry->remote_sock = calloc(1, sizeof(sock_name_t));
305             new_map_entry->remote_sock->s.addr = calloc(1, sizeof(struct sockaddr_un));
306             new_map_entry->remote_sock->type = sock_addr_e;
307             memcpy(new_map_entry->remote_sock->s.addr, &client_addr, sizeof(struct sockaddr_un));
308                         
309             /* Register the Client with the Server instance */
310             rm_trans_cfg.rmHandle = server_h;
311             rm_trans_cfg.appTransportHandle = (Rm_AppTransportHandle)new_map_entry->remote_sock;
312             rm_trans_cfg.remoteInstType = Rm_instType_CLIENT;
313             rm_trans_cfg.transportCallouts.rmAllocPkt = transportAlloc;
314             rm_trans_cfg.transportCallouts.rmSendPkt = transportSend;
315             new_map_entry->trans_handle = Rm_transportRegister(&rm_trans_cfg, &rm_result);
317             new_map_entry->n = NULL;
319             if (trans_map == NULL) {
320                 trans_map = new_map_entry;
321             }
322             else {
323                 map_index = trans_map;
325                 while(map_index->n != NULL) {
326                     map_index = map_index->n;
327                 }
328                 map_index->n = new_map_entry;
329             }
331             map_index = new_map_entry;
332         }
334         /* Provide packet to RM Server for processing */       
335         if (rm_result = Rm_receivePacket(map_index->trans_handle, rm_pkt)) {
336             error_msg("RM failed to process received packet: %d\n", rm_result);
337         }
338         
339 loop_continue:
340         /* Cleanups */
341         length = 0;
342         transportFree(rm_pkt);
343         memset(&client_sock_addr, 0, sizeof(sock_name_t));
344         memset(&client_addr, 0, sizeof(struct sockaddr_un));
345     }   
348 char *get_pid_file_name(void) {
349         static char pid_file_name[] = RMSERVER_DAEMON_PID_FILE_NAME;
351         return pid_file_name;
354 static void print_usage(char *appname)
356     printf ("Usage: %s [OPTION]... [GRL] [POLICY]\n", appname);
357     printf ("Run a resource manager server with the specified [GRL] and [POLICY]\n"
358             "[GRL] and [POLICY] must be device tree blob (DTB) files\n"
359             "Example: rmserver grl.dtb policy.dtb\n\n"
360             "Configuration:\n"
361             "  -s, --logsize MAXLOGSIZE  MAXLOGSIZE bytes will be written to the\n"
362             "                            log file before the log is reset.  On\n"
363             "                            reset, the log file will be wiped.\n"
364             "\n"
365             "                            The default for MAXLOGSIZE is 8MB if\n"
366             "                            logsize is not specified\n"
367             "Optional Input:\n"
368             "  -l, --lindtb [LINUX_DTB]  Optionally, provide a Linux DTB file\n"
369             "                            that RM will use to reserve resources\n"
370             "                            for Linux.  The GRL must have the\n"
371             "                            proper Linux DTB resource mappings\n"
372             "                            for this feature to work\n"
373             "Miscellaneous:\n"
374             "  -n, --nodaemon            do not daemonize, run in foreground\n"
375             "  -k, --kill                kill the existing daemon\n"
376             "  -h, --help                print this message\n"
377             "\n"
378             "rmserver will run as a daemon by default.\n\n");
381 int main(int argc, char *argv[])
383     int          opt;
384     int          daemonize = 1, kill = 0;
385     int          fd;
386     struct stat  file_stat;
387     pid_t        pid;
388     char        *grl_file;
389     char        *policy_file;
390     char        *lin_dtb_file = NULL;
391     void        *grl;
392     void        *policy;
393     void        *lin_dtb = NULL;
394     
395     const struct option longopts[] =
396     {
397         {"nodaemon", no_argument,       0, 'n'},
398         {"kill",         no_argument,       0, 'k'},
399         {"help",     no_argument,       0, 'h'},
400         {"lindtb",   required_argument, 0, 'l'},
401         {"logsize",  required_argument, 0, 's'},
402         {0,          0,                 0,   0},
403     };
405     rmsrv_cfg.logfile_max_len = DEFAULT_LOG_LEN;
407     while((opt = getopt_long(argc, argv, "nkhl:s:", longopts, NULL)) != -1) {
408         switch (opt) {
409             case 'n':
410                 daemonize = 0;
411                 break;
412             case 'k':
413                 kill = 1;
414                 break;
415             case 'l':
416                 lin_dtb_file = optarg;
417                 break;
418             case 's':
419                 rmsrv_cfg.logfile_max_len = strtol(optarg, NULL, 0);
420                 break;
421             case 'h':
422             default:
423                 print_usage(argv[0]);
424                 exit(EXIT_SUCCESS);
425         }
426     }
428     if (!kill) {
429         /* GRL and Policy must always be provided */
430         if (optind == (argc - 2)) {
431             /* First must be GRL */
432             grl_file = argv[optind++];
433             /* Second must be policy */
434             policy_file = argv[optind++];  
435         }
436         else {
437             printf("GRL or policy not provided\n\n");
438             print_usage(argv[0]);
439             exit(EXIT_FAILURE);
440         }
442         /* mmap the GRL */
443         fd = open(grl_file, O_RDONLY);
444         if (fd == -1) {
445             printf("Error opening GRL: %s\n", strerror(errno));
446             exit(EXIT_FAILURE);
447         }
448         /* Obtain file size */
449         if (fstat(fd, &file_stat) == -1) {
450             printf("Error getting GRL size\n");
451             exit(EXIT_FAILURE);
452         }
453         grl = mmap(NULL, file_stat.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
454         if (grl == MAP_FAILED) {
455             printf("mmap of GRL failed\n");
456             exit(EXIT_FAILURE);
457         }
459         /* mmap the Global Policy */
460         fd = open(policy_file, O_RDONLY);
461         if (fd == -1) {
462             printf("Error opening Global Policy: %s\n", strerror(errno));
463             exit(EXIT_FAILURE);
464         }
465         /* Obtain file size */
466         if (fstat(fd, &file_stat) == -1) {
467             printf("Error getting Global Policy size\n");
468             exit(EXIT_FAILURE);
469         }
470         policy = mmap(NULL, file_stat.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
471         if (policy == MAP_FAILED) {
472             printf("mmap of Global Policy failed\n");
473             exit(EXIT_FAILURE);
474         }
476         if (lin_dtb_file) {
477             /* mmap the Linux DTB if it was provided */
478             fd = open(lin_dtb_file, O_RDONLY);
479             if (fd == -1) {
480                 printf("Error opening Linux DTB: %s\n", strerror(errno));
481                 exit(EXIT_FAILURE);
482             }
483             /* Obtain file size */
484             if (fstat(fd, &file_stat) == -1) {
485                 printf("Error getting Linux DTB size\n");
486                 exit(EXIT_FAILURE);
487             }
488             lin_dtb = mmap(NULL, file_stat.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
489             if (lin_dtb == MAP_FAILED) {
490                 printf("mmap of Linux DTB failed\n");
491                 exit(EXIT_FAILURE);
492             }
493         }        
494     }
496     if (daemonize) {
497         if (kill) {
498             printf("Killing %s\n", argv[0]);
499         }
500         else {
501             printf("Starting %s\n", argv[0]);
502         }
504         /* Reset signal handlers */
505         if (daemon_reset_sigs(-1) < 0) {
506             printf("Failed to reset all signal handlers: %s\n", strerror(errno));
507             exit(EXIT_FAILURE);
508         }
510         /* Unblock signals */
511         if (daemon_unblock_sigs(-1) < 0) {
512             printf("Failed to unblock all signals: %s\n", strerror(errno));
513             exit(EXIT_FAILURE);
514         }
516         if (check_and_create_path (get_pid_file_name()) < 0) {
517             printf("Failed to create pid file path: %s\n", get_pid_file_name());
518             exit(EXIT_FAILURE);
519         }
521         /* set daemon id string */
522         daemon_log_ident = daemon_ident_from_argv0(argv[0]);
523         daemon_pid_file_proc = (daemon_pid_file_proc_t) get_pid_file_name;
525         if (kill) {
526             if (daemon_pid_file_kill_wait(SIGTERM, 5) < 0) {
527                 printf("Failed to kill daemon: %s\n", strerror(errno));
528                 exit(EXIT_FAILURE);
529             }
530             exit(EXIT_SUCCESS);
531         }
533         /* Single instance */
534         if ((pid = daemon_pid_file_is_running()) >= 0) {
535             printf("Daemon already running on PID file %u\n", pid);
536             exit(EXIT_FAILURE);
537         }
539         if (daemon_retval_init() < 0) {
540             printf("Failed to create pipe.\n");
541             exit(EXIT_FAILURE);
542         }
544         /* Do the fork */
545         if ((pid = daemon_fork()) < 0) {
546             daemon_retval_done();
547             printf("Error in daemon fork %s\n", strerror(errno));
548             exit(EXIT_FAILURE);
549         } 
550         else if (pid) { /* The parent */
551             int ret;
553             /* Wait for 20 seconds for the return value passed from the daemon process */
554             if ((ret = daemon_retval_wait(20)) < 0) {
555                 printf("Could not receive return value from daemon process: %s\n", strerror(errno));
556                 return -1;
557             }
559             printf("Daemon returned %i as return value.\n", ret);
560             return ret;
561         }
563         /* Close FDs */
564         if (daemon_close_all(-1) < 0) {
565             printf("Failed to close all file descriptors: %s\n", strerror(errno));
567             /* Send the error condition to the parent process */
568             daemon_retval_send(1);
569             goto close_n_exit;
570         }
572         /* Create the PID file */
573         if (daemon_pid_file_create() < 0) {
574             printf("Could not create PID file (%s).\n", strerror(errno));
575             daemon_retval_send(2);
576             goto close_n_exit;
577         }
579         /* Initialize signal handling */
580         if (daemon_signal_init(SIGINT, SIGTERM, SIGQUIT, SIGHUP, 0) < 0) {
581             printf("Could not register signal handlers (%s).\n", strerror(errno));
582             daemon_retval_send(3);
583             goto close_n_exit;
584         }
586         /* Send OK to parent process */
587         daemon_retval_send(0);
588     }
590     rm_server_run(grl, policy, lin_dtb, daemonize);
592 close_n_exit:
593     printf("Exiting %s daemon\n", argv[0]);
594     if (daemonize) {
595         daemon_retval_send(255);
596         daemon_signal_done();
597         daemon_pid_file_remove();
598     }