]> Gitweb @ Texas Instruments - Open Source Git Repositories - git.TI.com/gitweb - keystone-rtos/rm-lld.git/blobdiff - test/k2k/armv7/linux/rm_server.c
Fixed bug in daemon kill and updated k2k RM server source
[keystone-rtos/rm-lld.git] / test / k2k / armv7 / linux / rm_server.c
index 1b7a31c448dfa1f7e7491b7cbd336e1ea26980d3..450cdf44d9c79e08d23c035ca67058dda2e985b7 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013 Texas Instruments Incorporated - http://www.ti.com/
+ * Copyright (C) 2013-2014 Texas Instruments Incorporated - http://www.ti.com/
  *
  *
  *  Redistribution and use in source and binary forms, with or without
 #include <string.h>
 #include <sys/mman.h>
 #include <sys/stat.h>
+#include <signal.h>
 #include <fcntl.h>
-#include <time.h>
+#include <getopt.h>
+#include <unistd.h>
+
+#include <libdaemon/daemon.h>
 
 /* Socket Includes */
+#include "serverlogutil.h"
 #include "sockutils.h"
 #include "sockrmmsg.h"
 
 #include <ti/drv/rm/rm.h>
 #include <ti/drv/rm/rm_transport.h>
 
-#define error_msg printf
-#define info_msg  printf
+#define RMSERVER_DAEMON_PID_FILE_NAME "/var/run/rmServer/pid"
+#define RMSERVER_DAEMON_LOG_FILE_NAME "/var/log/rmServer.log"
 
 /* Socket timeout */
 #define SERVER_SOCK_TIMEOUT_USEC     (500)
 
-/* Seconds since last request to print resources */
-#define SECONDS_SINCE_LAST_REQUEST   (5)
-
 /* Error checking macro */
 #define ERROR_CHECK(checkVal, resultVal, rmInstName, printMsg)            \
     if (resultVal != checkVal) {                                          \
         char errorMsgToPrint[] = printMsg;                                \
-        printf("%s : ", rmInstName);                                      \
-        printf("%s with error code : %d\n", errorMsgToPrint, resultVal);  \
+        error_msg("%s : ", rmInstName);                                      \
+        error_msg("%s with error code : %d\n", errorMsgToPrint, resultVal);  \
         exit(EXIT_FAILURE);                                               \
     }
 
+/* logging errors */
+#define error_msg(...) rmsrv_log(LOG_ERR, __func__, __FILE__, __LINE__, __VA_ARGS__);
+/* logging warnings */
+#define warning_msg(...) rmsrv_log(LOG_WARNING, __func__, __FILE__, __LINE__, __VA_ARGS__);
+/* logging information */
+#define info_msg(...) rmsrv_log(LOG_INFO, __func__, __FILE__, __LINE__, __VA_ARGS__);
+/* logging debug information */
+#define debug_msg(...) rmsrv_log(LOG_DEBUG, __func__, __FILE__, __LINE__, __VA_ARGS__);
+
+#define LOG_APPEND(x)                              \
+    do {                                           \
+        int len;                                   \
+        len = MAX_LOG_LEN - strlen(rmsrv_log_buf); \
+        if (len > 0) {                             \
+            strncat(rmsrv_log_buf, x, len);        \
+        }                                          \
+        else {                                     \
+            return;                                \
+        }                                          \
+    } while(0)
+
 /* RM registered transport mapping structure */
 typedef struct trans_map_entry_s {
     /* Registered RM transport handle */
@@ -80,22 +103,67 @@ typedef struct trans_map_entry_s {
 /**********************************************************************
  ********************** Global Variables ******************************
  **********************************************************************/
+
 /* RM Server instance name (must match with RM Global Resource List (GRL) and policies */
-char   server_name[RM_NAME_MAX_CHARS] = "RM_Server";
+char           server_name[RM_NAME_MAX_CHARS] = "RM_Server";
+
+Rm_Handle      server_h;
+
+sock_h         server_sock = NULL;
+
+rmserver_cfg_t rmsrv_cfg;
+
+char           rmsrv_log_buf[MAX_LOG_LEN];
+
+/**********************************************************************
+ ********************** External Variables ****************************
+ **********************************************************************/
 
-sock_h server_sock = NULL;
+extern int   optind;
+extern char *optarg;
 
 /**********************************************************************
  ************************** Server Functions **************************
  **********************************************************************/
+
+/* RM Server logging utility (need to move it to another file) */
+void rmsrv_log(const int loglevel, const char* functionName, const char* fileName, const int lineNo, const char* format, ...)
+{
+    int len;
+    char lineno_a[32];
+    va_list args;
+
+    sprintf(lineno_a, "%d", lineNo);
+
+    rmsrv_log_buf[0] = 0;
+
+    LOG_APPEND(fileName);
+    LOG_APPEND(":");
+    LOG_APPEND(lineno_a);
+    LOG_APPEND(":");
+    LOG_APPEND(functionName);
+    LOG_APPEND(":");
+
+    len = MAX_LOG_LEN - strlen(rmsrv_log_buf);
+    if (len <= 0) {
+        return;
+    }
+
+    va_start(args, format);
+    vsnprintf(&rmsrv_log_buf[strlen(rmsrv_log_buf)], len, format, args);
+    va_end(args);
+
+    fprintf(rmsrv_cfg.logfile_p, "%s", rmsrv_log_buf);
+    fflush(rmsrv_cfg.logfile_p);
+}
+
 Rm_Packet *transportAlloc(Rm_AppTransportHandle appTransport, uint32_t pktSize, Rm_PacketHandle *pktHandle)
 {
     Rm_Packet *rm_pkt = NULL;
 
     rm_pkt = calloc(1, sizeof(*rm_pkt));
     if (!rm_pkt) {
-        error_msg("can't malloc for RM send message (err: %s)\n",
+        error_msg("Failed to malloc RM packet (err: %s)\n",
                   strerror(errno));
         return (NULL);
     }
@@ -107,8 +175,7 @@ Rm_Packet *transportAlloc(Rm_AppTransportHandle appTransport, uint32_t pktSize,
 
 void transportFree (Rm_Packet *rm_pkt)
 {
-    uint32_t pkt_size = rm_pkt->pktLenBytes;
-    int32_t  status;
+    int32_t status;
 
     if (rm_pkt) {
         free (rm_pkt);
@@ -121,21 +188,19 @@ int32_t transportSend (Rm_AppTransportHandle appTransport, Rm_PacketHandle pktHa
     Rm_Packet   *rm_pkt = (Rm_Packet *)pktHandle;
     
     if (sock_send(server_sock, (char *)rm_pkt, (int) rm_pkt->pktLenBytes, client_sock_name)) {
-        error_msg("send data failed\n");
+        error_msg("Failed to send RM packet\n");
+    }
+    else {
+        /* Print resources after sending response */
+        Rm_resourceStatus(server_h, 1);
     }
+
+    transportFree(rm_pkt);
     return (0);
 }
 
-int main(int argc, char *argv[])
+int rm_server_run(void *grl, void *policy, void *lin_dtb, int is_daemon)
 {
-    int                 fd;
-    time_t              old_time;
-    struct stat         file_stat;
-    char               *grl_addr;
-    char               *linux_dtb_addr;
-    char               *policy_addr;
-    Rm_Handle           server_h;
     Rm_InitCfg          rm_init_cfg;
     Rm_TransportCfg     rm_trans_cfg;
     int32_t             rm_result;
@@ -147,102 +212,48 @@ int main(int argc, char *argv[])
     sock_name_t         serv_sock_name;
     sock_name_t         client_sock_addr;
     Rm_Packet          *rm_pkt = NULL;
-    struct sockaddr_un  client_addr;
-    struct timeval      tv = {0, SERVER_SOCK_TIMEOUT_USEC};    
+    char                pkt_src[RM_NAME_MAX_CHARS];
+    struct sockaddr_un  client_addr; 
+    int                 signal_fd = -1;
     char                rm_socket_name[] = RM_SERVER_SOCKET_NAME;
 
-    if ((argc < 3) || (argc > 4))
-    {
-        error_msg("Invalid number of input arguments\n");
-        exit(EXIT_FAILURE);        
-    }
-
-    /* mmap the GRL */
-    fd = open(argv[1], O_RDONLY);
-    if (fd == -1) {
-        error_msg("Error opening GRL\n");
-        exit(EXIT_FAILURE);
-    }
-    /* Obtain file size */
-    if (fstat(fd, &file_stat) == -1) {
-        error_msg("Error getting GRL size\n");
-        exit(EXIT_FAILURE);
-    }
-    grl_addr = mmap(NULL, file_stat.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
-    if (grl_addr == MAP_FAILED) {
-        error_msg("mmap of GRL failed\n");
-        exit(EXIT_FAILURE);
-    }
-
-    /* mmap the Global Policy */
-    fd = open(argv[2], O_RDONLY);
-    if (fd == -1) {
-        error_msg("Error opening Global Policy\n");
-        exit(EXIT_FAILURE);
-    }
-    /* Obtain file size */
-    if (fstat(fd, &file_stat) == -1) {
-        error_msg("Error getting Global Policy size\n");
-        exit(EXIT_FAILURE);
-    }
-    policy_addr = mmap(NULL, file_stat.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
-    if (policy_addr == MAP_FAILED) {
-        error_msg("mmap of Global Policy failed\n");
-        exit(EXIT_FAILURE);
-    }
-
-    if (argc == 4){
-        /* mmap (Example) Linux DTB */
-        fd = open(argv[3], O_RDONLY);
-        if (fd == -1) {
-            error_msg("Error opening Linux DTB\n");
-            exit(EXIT_FAILURE);
-        }
-        /* Obtain file size */
-        if (fstat(fd, &file_stat) == -1) {
-            error_msg("Error getting Linux DTB size\n");
-            exit(EXIT_FAILURE);
-        }
-        linux_dtb_addr = mmap(NULL, file_stat.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
-        if (linux_dtb_addr == MAP_FAILED) {
-            error_msg("mmap of Linux DTB failed\n");
-            exit(EXIT_FAILURE);
-        }
+    rmsrv_cfg.logfile_p = fopen(RMSERVER_DAEMON_LOG_FILE_NAME, "w+");
+    if (!rmsrv_cfg.logfile_p) {
+        printf("Error in opening log file %s (%s)", RMSERVER_DAEMON_LOG_FILE_NAME, strerror(errno));
     }
 
+    debug_msg("Starting RM server");
+    
     /* Create the Server instance */
     memset(&rm_init_cfg, 0, sizeof(rm_init_cfg));
     rm_init_cfg.instName = server_name;
     rm_init_cfg.instType = Rm_instType_SERVER;
-    rm_init_cfg.instCfg.serverCfg.globalResourceList = (void *)grl_addr;
-    rm_init_cfg.instCfg.serverCfg.linuxDtb = (void *)linux_dtb_addr;
-    rm_init_cfg.instCfg.serverCfg.globalPolicy = (void *)policy_addr;
+    rm_init_cfg.instCfg.serverCfg.globalResourceList = grl;
+    rm_init_cfg.instCfg.serverCfg.linuxDtb = lin_dtb;
+    rm_init_cfg.instCfg.serverCfg.globalPolicy = policy;
     server_h = Rm_init(&rm_init_cfg, &rm_result);
     ERROR_CHECK(RM_OK, rm_result, server_name, "Initialization failed\n");
 
-    printf("\n\nInitialized %s\n\n", server_name);
+    debug_msg("RM Server initialized with name: %s", server_name);
 
     Rm_resourceStatus(server_h, 1);
     
     serv_sock_name.type = sock_name_e;
     serv_sock_name.s.name = rm_socket_name;
     server_sock = sock_open (&serv_sock_name);
+    if (!server_sock) {
+        error_msg("Error when opening socket %s", rm_socket_name);
+        return -1;
+    }
 
-    old_time = time(NULL);
-    info_msg("Begin waiting for messages from Clients\n");
+    if (is_daemon){
+        signal_fd = daemon_signal_fd();
+    }
 
     while(1) {
-
-        if ((time(NULL) - old_time) > SECONDS_SINCE_LAST_REQUEST) {
-            Rm_resourceStatus(server_h, 1);
-            old_time = time(NULL);
-        }
-
-        retval = sock_wait(server_sock, &length, &tv, -1);
-        if (retval == -2) {
-            goto loop_continue;
-        }
-        else if (retval < 0) {
+        info_msg("Waiting for messages from Clients\n");
+        retval = sock_wait(server_sock, &length, NULL, signal_fd);
+        if (retval < 0) {
             error_msg("Error in reading from socket\n");
             goto loop_continue;
         }
@@ -267,7 +278,13 @@ int main(int argc, char *argv[])
             goto loop_continue;
         }
 
-        info_msg("received RM pkt of size %d bytes from %s\n", length, client_sock_addr.s.addr->sun_path);
+        info_msg("Received RM pkt of size %d bytes from socket %s\n", length, client_sock_addr.s.addr->sun_path);
+        if (Rm_receiveGetPktSrcName(rm_pkt, &pkt_src[0], RM_NAME_MAX_CHARS) == RM_OK) {
+            info_msg("    RM pkt originated from %s instance\n", &pkt_src[0]);
+        }
+        if (Rm_receiveGetPktServiceSrcName(rm_pkt, &pkt_src[0], RM_NAME_MAX_CHARS) == RM_OK) {
+            info_msg("    Service request within RM pkt originated from %s instance\n", &pkt_src[0]);
+        }
 
         map_index = trans_map;
         while(map_index != NULL) {
@@ -313,15 +330,256 @@ int main(int argc, char *argv[])
 
         /* Provide packet to RM Server for processing */       
         if (rm_result = Rm_receivePacket(map_index->trans_handle, rm_pkt)) {
-            printf("RM failed to process received packet: %d\n", rm_result);
+            error_msg("RM failed to process received packet: %d\n", rm_result);
         }
-        transportFree(rm_pkt);
-        old_time = time(NULL);
+        
 loop_continue:
         /* Cleanups */
-        length = 0;    
+        length = 0;
+        transportFree(rm_pkt);
         memset(&client_sock_addr, 0, sizeof(sock_name_t));
         memset(&client_addr, 0, sizeof(struct sockaddr_un));
+    }   
+}
+
+char *get_pid_file_name(void) {
+       static char pid_file_name[] = RMSERVER_DAEMON_PID_FILE_NAME;
+
+       return pid_file_name;
+}
+
+static void print_usage(char *appname)
+{
+    printf ("Usage: %s [OPTION]... [GRL] [POLICY]\n", appname);
+    printf ("Run a resource manager server with the specified [GRL] and [POLICY]\n"
+            "[GRL] and [POLICY] must be device tree blob (DTB) files\n"
+            "Example: rmserver grl.dtb policy.dtb\n\n"
+            "Optional Input:\n"
+            "  -l, --lindtb [LINUX_DTB]  Optionally, provide a Linux DTB file\n"
+            "                            that RM will use to reserve resources\n"
+            "                            for Linux.  The GRL must have the\n"
+            "                            proper Linux DTB resource mappings\n"
+            "                            for this feature to work\n"
+            "Miscellaneous:\n"
+            "  -n, --nodaemon            do not daemonize, run in foreground\n"
+            "  -k, --kill                kill the existing daemon\n"
+            "  -h, --help                print this message\n"
+            "\n"
+            "rmserver will run as a daemon by default.\n\n");
+}
+
+int main(int argc, char *argv[])
+{
+    int          opt;
+    int          daemonize = 1, kill = 0;
+    int          fd;
+    struct stat  file_stat;
+    pid_t        pid;
+    char        *grl_file;
+    char        *policy_file;
+    char        *lin_dtb_file = NULL;
+    void        *grl;
+    void        *policy;
+    void        *lin_dtb = NULL;
+    
+
+    const struct option longopts[] =
+    {
+        {"nodaemon", no_argument,       0, 'n'},
+        {"kill",        no_argument,       0, 'k'},
+        {"help",     no_argument,       0, 'h'},
+        {"lindtb",   required_argument, 0, 'l'},
+        {0,          0,                 0,   0},
+    };
+
+    while((opt = getopt_long(argc, argv, "nkhl:", longopts, NULL)) != -1) {
+        switch (opt) {
+            case 'n':
+                daemonize = 0;
+                break;
+            case 'k':
+                kill = 1;
+                break;
+            case 'l':
+                lin_dtb_file = optarg;
+                break;
+            case 'h':
+            default:
+                print_usage(argv[0]);
+                exit(EXIT_SUCCESS);
+        }
+    }
+
+    if (!kill) {
+        /* GRL and Policy must always be provided */
+        if (optind == (argc - 2)) {
+            /* First must be GRL */
+            grl_file = argv[optind++];
+            /* Second must be policy */
+            policy_file = argv[optind++];  
+        }
+        else {
+            printf("GRL or policy not provided\n\n");
+            print_usage(argv[0]);
+            exit(EXIT_FAILURE);
+        }
+
+        /* mmap the GRL */
+        fd = open(grl_file, O_RDONLY);
+        if (fd == -1) {
+            printf("Error opening GRL: %s\n", strerror(errno));
+            exit(EXIT_FAILURE);
+        }
+        /* Obtain file size */
+        if (fstat(fd, &file_stat) == -1) {
+            printf("Error getting GRL size\n");
+            exit(EXIT_FAILURE);
+        }
+        grl = mmap(NULL, file_stat.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
+        if (grl == MAP_FAILED) {
+            printf("mmap of GRL failed\n");
+            exit(EXIT_FAILURE);
+        }
+
+        /* mmap the Global Policy */
+        fd = open(policy_file, O_RDONLY);
+        if (fd == -1) {
+            printf("Error opening Global Policy: %s\n", strerror(errno));
+            exit(EXIT_FAILURE);
+        }
+        /* Obtain file size */
+        if (fstat(fd, &file_stat) == -1) {
+            printf("Error getting Global Policy size\n");
+            exit(EXIT_FAILURE);
+        }
+        policy = mmap(NULL, file_stat.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
+        if (policy == MAP_FAILED) {
+            printf("mmap of Global Policy failed\n");
+            exit(EXIT_FAILURE);
+        }
+
+        if (lin_dtb_file) {
+            /* mmap the Linux DTB if it was provided */
+            fd = open(lin_dtb_file, O_RDONLY);
+            if (fd == -1) {
+                printf("Error opening Linux DTB: %s\n", strerror(errno));
+                exit(EXIT_FAILURE);
+            }
+            /* Obtain file size */
+            if (fstat(fd, &file_stat) == -1) {
+                printf("Error getting Linux DTB size\n");
+                exit(EXIT_FAILURE);
+            }
+            lin_dtb = mmap(NULL, file_stat.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
+            if (lin_dtb == MAP_FAILED) {
+                printf("mmap of Linux DTB failed\n");
+                exit(EXIT_FAILURE);
+            }
+        }        
+    }
+
+    if (daemonize) {
+        if (kill) {
+            printf("Killing %s\n", argv[0]);
+        }
+        else {
+            printf("Starting %s\n", argv[0]);
+        }
+
+        /* Reset signal handlers */
+        if (daemon_reset_sigs(-1) < 0) {
+            printf("Failed to reset all signal handlers: %s\n", strerror(errno));
+            exit(EXIT_FAILURE);
+        }
+
+        /* Unblock signals */
+        if (daemon_unblock_sigs(-1) < 0) {
+            printf("Failed to unblock all signals: %s\n", strerror(errno));
+            exit(EXIT_FAILURE);
+        }
+
+        if (check_and_create_path (get_pid_file_name()) < 0) {
+            printf("Failed to create pid file path: %s\n", get_pid_file_name());
+            exit(EXIT_FAILURE);
+        }
+
+        /* set daemon id string */
+        daemon_log_ident = daemon_ident_from_argv0(argv[0]);
+        daemon_pid_file_proc = (daemon_pid_file_proc_t) get_pid_file_name;
+
+        if (kill) {
+            if (daemon_pid_file_kill_wait(SIGTERM, 5) < 0) {
+                printf("Failed to kill daemon: %s\n", strerror(errno));
+                exit(EXIT_FAILURE);
+            }
+            exit(EXIT_SUCCESS);
+        }
+
+        /* Single instance */
+        if ((pid = daemon_pid_file_is_running()) >= 0) {
+            printf("Daemon already running on PID file %u\n", pid);
+            exit(EXIT_FAILURE);
+        }
+
+        if (daemon_retval_init() < 0) {
+            printf("Failed to create pipe.\n");
+            exit(EXIT_FAILURE);
+        }
+
+        /* Do the fork */
+        if ((pid = daemon_fork()) < 0) {
+            daemon_retval_done();
+            printf("Error in daemon fork %s\n", strerror(errno));
+            exit(EXIT_FAILURE);
+        } 
+        else if (pid) { /* The parent */
+            int ret;
+
+            /* Wait for 20 seconds for the return value passed from the daemon process */
+            if ((ret = daemon_retval_wait(20)) < 0) {
+                printf("Could not receive return value from daemon process: %s\n", strerror(errno));
+                return -1;
+            }
+
+            printf("Daemon returned %i as return value.\n", ret);
+            return ret;
+        }
+
+        /* Close FDs */
+        if (daemon_close_all(-1) < 0) {
+            printf("Failed to close all file descriptors: %s\n", strerror(errno));
+
+            /* Send the error condition to the parent process */
+            daemon_retval_send(1);
+            goto close_n_exit;
+        }
+
+        /* Create the PID file */
+        if (daemon_pid_file_create() < 0) {
+            printf("Could not create PID file (%s).\n", strerror(errno));
+            daemon_retval_send(2);
+            goto close_n_exit;
+        }
+
+        /* Initialize signal handling */
+        if (daemon_signal_init(SIGINT, SIGTERM, SIGQUIT, SIGHUP, 0) < 0) {
+            printf("Could not register signal handlers (%s).\n", strerror(errno));
+            daemon_retval_send(3);
+            goto close_n_exit;
+        }
+
+        /* Send OK to parent process */
+        daemon_retval_send(0);
     }
+
+    rm_server_run(grl, policy, lin_dtb, daemonize);
+
+close_n_exit:
+    printf("Exiting %s daemon\n", argv[0]);
+    if (daemonize) {
+        daemon_retval_send(255);
+        daemon_signal_done();
+        daemon_pid_file_remove();
+    }    
 }