index 1b7a31c448dfa1f7e7491b7cbd336e1ea26980d3..450cdf44d9c79e08d23c035ca67058dda2e985b7 100644 (file)
/*
- * 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 */
/**********************************************************************
********************** 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);
}
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;
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;
}
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) {
/* 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();
+ }
}