{"action":"created","comment":{"url":"https://api.github.com/repos/collectd/collectd/pulls/comments/78740712","id":78740712,"diff_hunk":"@@ -0,0 +1,775 @@\n+/*-\n+ * collectd - src/dpdkstat.c\n+ * MIT License\n+ *\n+ * Copyright(c) 2016 Intel Corporation. All rights reserved.\n+ *\n+ * Permission is hereby granted, free of charge, to any person obtaining a copy of\n+ * this software and associated documentation files (the \"Software\"), to deal in\n+ * the Software without restriction, including without limitation the rights to\n+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies\n+ * of the Software, and to permit persons to whom the Software is furnished to do\n+ * so, subject to the following conditions:\n+ *\n+ * The above copyright notice and this permission notice shall be included in all\n+ * copies or substantial portions of the Software.\n+ *\n+ * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n+ * SOFTWARE.\n+ *\n+ * Authors:\n+ *   Maryam Tahhan <maryam.tahhan@intel.com>\n+ *   Harry van Haaren <harry.van.haaren@intel.com>\n+ */\n+\n+#include \"collectd.h\"\n+#include \"common.h\" /* auxiliary functions */\n+#include \"plugin.h\" /* plugin_register_*, plugin_dispatch_values */\n+#include \"utils_time.h\"\n+\n+#include <getopt.h>\n+#include <semaphore.h>\n+#include <sys/mman.h>\n+#include <sys/queue.h>\n+#include <poll.h>\n+\n+#include <rte_config.h>\n+#include <rte_eal.h>\n+#include <rte_ethdev.h>\n+#include <rte_common.h>\n+#include <rte_debug.h>\n+#include <rte_malloc.h>\n+#include <rte_memory.h>\n+#include <rte_memzone.h>\n+#include <rte_launch.h>\n+#include <rte_tailq.h>\n+#include <rte_lcore.h>\n+#include <rte_per_lcore.h>\n+#include <rte_debug.h>\n+#include <rte_log.h>\n+#include <rte_atomic.h>\n+#include <rte_branch_prediction.h>\n+#include <rte_string_fns.h>\n+\n+#define DPDKSTAT_MAX_BUFFER_SIZE (4096*4)\n+#define DPDK_SHM_NAME \"dpdk_collectd_stats_shm\"\n+#define REINIT_SHM 1\n+#define RESET 1\n+#define NO_RESET 0\n+\n+enum DPDK_HELPER_ACTION {\n+  DPDK_HELPER_ACTION_COUNT_STATS,\n+  DPDK_HELPER_ACTION_SEND_STATS,\n+};\n+\n+enum DPDK_HELPER_STATUS {\n+  DPDK_HELPER_NOT_INITIALIZED = 0,\n+  DPDK_HELPER_WAITING_ON_PRIMARY,\n+  DPDK_HELPER_INITIALIZING_EAL,\n+  DPDK_HELPER_ALIVE_SENDING_STATS,\n+  DPDK_HELPER_GRACEFUL_QUIT,\n+};\n+\n+struct dpdk_config_s {\n+  /* General DPDK params */\n+  char coremask[DATA_MAX_NAME_LEN];\n+  char memory_channels[DATA_MAX_NAME_LEN];\n+  char socket_memory[DATA_MAX_NAME_LEN];\n+  char process_type[DATA_MAX_NAME_LEN];\n+  char file_prefix[DATA_MAX_NAME_LEN];\n+  cdtime_t interval;\n+  uint32_t eal_initialized;\n+  uint32_t enabled_port_mask;\n+  char port_name[RTE_MAX_ETHPORTS][DATA_MAX_NAME_LEN];\n+  uint32_t eal_argc;\n+  /* Helper info */\n+  int   collectd_reinit_shm;\n+  pid_t helper_pid;\n+  sem_t sema_helper_get_stats;\n+  sem_t sema_stats_in_shm;\n+  int   helper_pipes[2];\n+  enum DPDK_HELPER_STATUS helper_status;\n+  enum DPDK_HELPER_ACTION helper_action;\n+  /* xstats info */\n+  uint32_t num_ports;\n+  uint32_t num_xstats;\n+  cdtime_t port_read_time[RTE_MAX_ETHPORTS];\n+  uint32_t num_stats_in_port[RTE_MAX_ETHPORTS];\n+  struct rte_eth_link link_status[RTE_MAX_ETHPORTS];\n+  struct rte_eth_xstats xstats;\n+  /* rte_eth_xstats from here on until the end of the SHM */\n+};\n+typedef struct dpdk_config_s dpdk_config_t;\n+\n+static int g_configured;\n+static dpdk_config_t *g_configuration;\n+\n+static void dpdk_config_init_default(void);\n+static int dpdk_config(oconfig_item_t *ci);\n+static int dpdk_helper_init_eal(void);\n+static int dpdk_helper_run(void);\n+static int dpdk_helper_spawn(enum DPDK_HELPER_ACTION action);\n+static int dpdk_init(void);\n+static int dpdk_read(user_data_t *ud);\n+static int dpdk_shm_cleanup(void);\n+static int dpdk_shm_init(size_t size);\n+\n+/* Write the default configuration to the g_configuration instances */\n+static void dpdk_config_init_default(void)\n+{\n+    g_configuration->interval = plugin_get_interval();\n+    WARNING(\"dpdkstat: No time interval was configured, default value %lu ms is set\\n\",\n+             CDTIME_T_TO_MS(g_configuration->interval));\n+    /* Default is all ports enabled */\n+    g_configuration->enabled_port_mask = ~0;\n+    g_configuration->eal_argc = 2;\n+    g_configuration->eal_initialized = 0;\n+    ssnprintf(g_configuration->coremask, DATA_MAX_NAME_LEN, \"%s\", \"0xf\");\n+    ssnprintf(g_configuration->memory_channels, DATA_MAX_NAME_LEN, \"%s\", \"1\");\n+    ssnprintf(g_configuration->process_type, DATA_MAX_NAME_LEN, \"%s\", \"secondary\");\n+    ssnprintf(g_configuration->file_prefix, DATA_MAX_NAME_LEN, \"%s\",\n+             \"/var/run/.rte_config\");\n+\n+    for (int i = 0; i < RTE_MAX_ETHPORTS; i++)\n+      g_configuration->port_name[i][0] = 0;\n+}\n+\n+static int dpdk_config(oconfig_item_t *ci)\n+{\n+  int port_counter = 0;\n+\n+  /* Initialize a POSIX SHared Memory (SHM) object. */\n+  int err = dpdk_shm_init(sizeof(dpdk_config_t));\n+  if (err) {\n+    DEBUG(\"dpdkstat: error in shm_init, %s\", strerror(errno));\n+    return -1;\n+  }\n+\n+  /* Set defaults for config, overwritten by loop if config item exists */\n+  dpdk_config_init_default();\n+\n+  for (int i = 0; i < ci->children_num; i++) {\n+    oconfig_item_t *child = ci->children + i;\n+\n+    if (strcasecmp(\"Interval\", child->key) == 0) {\n+      g_configuration->interval =\n+            DOUBLE_TO_CDTIME_T (child->values[0].value.number);\n+      DEBUG(\"dpdkstat: Plugin Read Interval %lu milliseconds\\n\",\n+            CDTIME_T_TO_MS(g_configuration->interval));\n+    } else if (strcasecmp(\"Coremask\", child->key) == 0) {\n+      ssnprintf(g_configuration->coremask, DATA_MAX_NAME_LEN, \"%s\",\n+               child->values[0].value.string);\n+      DEBUG(\"dpdkstat:COREMASK %s \\n\", g_configuration->coremask);\n+      g_configuration->eal_argc+=1;\n+    } else if (strcasecmp(\"MemoryChannels\", child->key) == 0) {\n+      ssnprintf(g_configuration->memory_channels, DATA_MAX_NAME_LEN, \"%s\",\n+               child->values[0].value.string);\n+      DEBUG(\"dpdkstat:Memory Channels %s \\n\", g_configuration->memory_channels);\n+      g_configuration->eal_argc+=1;\n+    } else if (strcasecmp(\"SocketMemory\", child->key) == 0) {\n+      ssnprintf(g_configuration->socket_memory, DATA_MAX_NAME_LEN, \"%s\",\n+               child->values[0].value.string);\n+      DEBUG(\"dpdkstat: socket mem %s \\n\", g_configuration->socket_memory);\n+      g_configuration->eal_argc+=1;\n+    } else if (strcasecmp(\"ProcessType\", child->key) == 0) {\n+      ssnprintf(g_configuration->process_type, DATA_MAX_NAME_LEN, \"%s\",\n+               child->values[0].value.string);\n+      DEBUG(\"dpdkstat: proc type %s \\n\", g_configuration->process_type);\n+      g_configuration->eal_argc+=1;\n+    } else if (strcasecmp(\"FilePrefix\", child->key) == 0) {\n+      ssnprintf(g_configuration->file_prefix, DATA_MAX_NAME_LEN, \"/var/run/.%s_config\",\n+               child->values[0].value.string);\n+      DEBUG(\"dpdkstat: file prefix %s \\n\", g_configuration->file_prefix);\n+      if (strcasecmp(g_configuration->file_prefix, \"/var/run/.rte_config\") != 0) {\n+        g_configuration->eal_argc+=1;\n+      }\n+    } else if (strcasecmp(\"EnabledPortMask\", child->key) == 0) {\n+      g_configuration->enabled_port_mask = (uint32_t)child->values[0].value.number;\n+      DEBUG(\"dpdkstat: Enabled Port Mask %u\\n\", g_configuration->enabled_port_mask);\n+    } else if (strcasecmp(\"PortName\", child->key) == 0) {\n+      ssnprintf(g_configuration->port_name[port_counter], DATA_MAX_NAME_LEN, \"%s\",\n+               child->values[0].value.string);\n+      DEBUG(\"dpdkstat: Port %d Name: %s \\n\", port_counter,\n+               g_configuration->port_name[port_counter]);\n+      port_counter++;\n+    } else {\n+      WARNING (\"dpdkstat: The config option \\\"%s\\\" is unknown.\",\n+               child->key);\n+    }\n+  } /* End for (int i = 0; i < ci->children_num; i++)*/\n+  g_configured = 1; /* Bypass configuration in dpdk_shm_init(). */\n+\n+  return 0;\n+}\n+\n+/* Initialize SHared Memory (SHM) for config and helper process */\n+static int dpdk_shm_init(size_t size)\n+{\n+  /*\n+   * Check if SHM is already configured: when config items are provided, the\n+   * config function initializes SHM. If there is no config, then init() will\n+   * just return.\n+   */\n+  if(g_configuration)\n+    return 0;\n+\n+  /* Create and open a new object, or open an existing object. */\n+  int fd = shm_open(DPDK_SHM_NAME, O_CREAT | O_TRUNC | O_RDWR, 0666);\n+  if (fd < 0) {\n+    WARNING(\"dpdkstat:Failed to open %s as SHM:%s\\n\", DPDK_SHM_NAME,\n+            strerror(errno));\n+    goto fail;\n+  }\n+  /* Set the size of the shared memory object. */\n+  int ret = ftruncate(fd, size);\n+  if (ret != 0) {\n+    WARNING(\"dpdkstat:Failed to resize SHM:%s\\n\", strerror(errno));\n+    goto fail_close;\n+  }\n+  /* Map the shared memory object into this process' virtual address space. */\n+  g_configuration = mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);\n+  if (g_configuration == MAP_FAILED) {\n+    WARNING(\"dpdkstat:Failed to mmap SHM:%s\\n\", strerror(errno));\n+    goto fail_close;\n+  }\n+  /*\n+   * Close the file descriptor, the shared memory object still exists\n+   * and can only be removed by calling shm_unlink().\n+   */\n+  close(fd);\n+\n+  /* Initialize g_configuration. */\n+  memset(g_configuration, 0, size);\n+\n+  /* Initialize the semaphores for SHM use */\n+  int err = sem_init(&g_configuration->sema_helper_get_stats, 1, 0);\n+  if(err) {\n+    ERROR(\"dpdkstat semaphore init failed: %s\\n\", strerror(errno));\n+    goto fail_close;\n+  }\n+  err = sem_init(&g_configuration->sema_stats_in_shm, 1, 0);\n+  if(err) {\n+    ERROR(\"dpdkstat semaphore init failed: %s\\n\", strerror(errno));\n+    goto fail_close;\n+  }\n+\n+  return 0;\n+\n+fail_close:\n+  close(fd);\n+fail:\n+  /* Reset to zero, as it was set to MAP_FAILED aka: (void *)-1. Avoid\n+   * an issue if collectd attempts to run this plugin failure.\n+   */\n+  g_configuration = 0;\n+  return -1;\n+}\n+\n+static int dpdk_re_init_shm()\n+{\n+  dpdk_config_t temp_config;\n+  memcpy(&temp_config, g_configuration, sizeof(dpdk_config_t));\n+  DEBUG(\"dpdkstat: %s: ports %d, xstats %d\\n\", __func__, temp_config.num_ports,\n+        temp_config.num_xstats);\n+\n+  int shm_xstats_size = sizeof(dpdk_config_t) + (sizeof(struct rte_eth_xstats) *\n+                        g_configuration->num_xstats);\n+  DEBUG(\"=== SHM new size for %d xstats\\n\", g_configuration->num_xstats);\n+\n+  int err = dpdk_shm_cleanup();\n+  if (err)\n+    ERROR(\"dpdkstat: Error in shm_cleanup in %s\\n\", __func__);\n+\n+  err = dpdk_shm_init(shm_xstats_size);\n+  if (err)\n+    ERROR(\"dpdkstat: Error in shm_init in %s\\n\", __func__);\n+\n+  /* If the XML config() function has been run, dont re-initialize defaults */\n+  if(!g_configured)\n+    dpdk_config_init_default();\n+\n+  memcpy(g_configuration, &temp_config, sizeof(dpdk_config_t));\n+  g_configuration->collectd_reinit_shm = 0;\n+\n+  return 0;\n+}\n+\n+static int dpdk_init (void)\n+{\n+  int err = dpdk_shm_init(sizeof(dpdk_config_t));\n+  if (err)\n+    ERROR(\"dpdkstat: %s : error %d in shm_init()\", __func__, err);\n+\n+  /* If the XML config() function has been run, dont re-initialize defaults */\n+  if(!g_configured) {\n+    dpdk_config_init_default();\n+  }\n+\n+  plugin_register_complex_read (NULL, \"dpdkstat\", dpdk_read,\n+                                g_configuration->interval, NULL);\n+  return 0;\n+}\n+\n+static int dpdk_helper_exit(int reset)\n+{\n+  g_configuration->helper_status = DPDK_HELPER_GRACEFUL_QUIT;\n+  if (reset) {\n+    g_configuration->eal_initialized = 0;\n+    g_configuration->num_ports = 0;\n+    memset(&g_configuration->xstats, 0, g_configuration->num_xstats* sizeof(struct rte_eth_xstats));\n+    g_configuration->num_xstats = 0;\n+    for (int i = 0; i < RTE_MAX_ETHPORTS; i++)\n+      g_configuration->num_stats_in_port[i] = 0;\n+  }\n+  close(g_configuration->helper_pipes[1]);\n+  int err = kill(g_configuration->helper_pid, SIGKILL);\n+  if (err) {\n+    ERROR(\"dpdkstat: error sending kill to helper: %s\\n\", strerror(errno));\n+  }\n+\n+  return 0;\n+}\n+\n+static int dpdk_helper_spawn(enum DPDK_HELPER_ACTION action)\n+{\n+  g_configuration->eal_initialized = 0;\n+  g_configuration->helper_action = action;\n+  /*\n+   * Create a pipe for helper stdout back to collectd. This is necessary for\n+   * logging EAL failures, as rte_eal_init() calls rte_panic().\n+   */\n+  if (g_configuration->helper_pipes[1]) {\n+    DEBUG(\"dpdkstat: collectd closing helper pipe %d\\n\",\n+          g_configuration->helper_pipes[1]);\n+  } else {\n+    DEBUG(\"dpdkstat: collectd helper pipe %d, not closing\\n\",\n+          g_configuration->helper_pipes[1]);\n+  }\n+  if(pipe(g_configuration->helper_pipes) != 0) {\n+    DEBUG(\"dpdkstat: Could not create helper pipe: %s\\n\", strerror(errno));\n+    return -1;\n+  }\n+\n+  int pipe0_flags = fcntl(g_configuration->helper_pipes[0], F_GETFL, 0);\n+  int pipe1_flags = fcntl(g_configuration->helper_pipes[1], F_GETFL, 0);\n+  if (pipe0_flags == -1 || pipe1_flags == -1) {\n+    ERROR(\"dpdkstat: error setting up pipe flags: %s\\n\", strerror(errno));\n+  }\n+  int  pipe0_err = fcntl(g_configuration->helper_pipes[0], F_SETFL, pipe1_flags\n+                         | O_NONBLOCK);\n+  int  pipe1_err = fcntl(g_configuration->helper_pipes[1], F_SETFL, pipe0_flags\n+                         | O_NONBLOCK);\n+  if (pipe0_err == -1 || pipe1_err == -1) {\n+    ERROR(\"dpdkstat: error setting up pipes: %s\\n\", strerror(errno));\n+  }\n+\n+  pid_t pid = fork();\n+  if (pid > 0) {\n+    close(g_configuration->helper_pipes[1]);\n+    g_configuration->helper_pid = pid;\n+    DEBUG(\"dpdkstat: helper pid %u\\n\", g_configuration->helper_pid);\n+    /* Kick helper once its alive to have it start processing */\n+    sem_post(&g_configuration->sema_helper_get_stats);\n+  } else if (pid == 0) {\n+    /* Replace stdout with a pipe to collectd. */\n+    close(g_configuration->helper_pipes[0]);\n+    close(STDOUT_FILENO);\n+    dup2(g_configuration->helper_pipes[1], STDOUT_FILENO);\n+    dpdk_helper_run();\n+  } else {\n+    ERROR(\"dpdkstat: Failed to fork helper process: %s\\n\", strerror(errno));\n+    return -1;\n+  }\n+  return 0;\n+}\n+\n+/*\n+ * Initialize the DPDK EAL, if this returns, EAL is successfully initialized.\n+ * On failure, the EAL prints an error message, and the helper process exits.\n+ */\n+static int dpdk_helper_init_eal(void)\n+{\n+  g_configuration->helper_status = DPDK_HELPER_INITIALIZING_EAL;\n+  char *argp[(g_configuration->eal_argc) + 1];\n+  int i = 0;\n+\n+  argp[i++] = \"collectd-dpdk\";\n+  if (strcasecmp(g_configuration->coremask, \"\") != 0) {\n+    argp[i++] = \"-c\";\n+    argp[i++] = g_configuration->coremask;\n+  }\n+  if (strcasecmp(g_configuration->memory_channels, \"\") != 0) {\n+    argp[i++] = \"-n\";\n+    argp[i++] = g_configuration->memory_channels;\n+  }\n+  if (strcasecmp(g_configuration->socket_memory, \"\") != 0) {\n+    argp[i++] = \"--socket-mem\";\n+    argp[i++] = g_configuration->socket_memory;\n+  }\n+  if (strcasecmp(g_configuration->file_prefix, \"\") != 0 &&\n+     strcasecmp(g_configuration->file_prefix, \"/var/run/.rte_config\") != 0) {\n+    argp[i++] = \"--file-prefix\";\n+    argp[i++] = g_configuration->file_prefix;\n+  }\n+  if (strcasecmp(g_configuration->process_type, \"\") != 0) {\n+    argp[i++] = \"--proc-type\";\n+    argp[i++] = g_configuration->process_type;\n+  }\n+  g_configuration->eal_argc = i;\n+\n+  g_configuration->eal_initialized = 1;\n+  int ret = rte_eal_init(g_configuration->eal_argc, argp);\n+  if (ret < 0) {\n+    g_configuration->eal_initialized = 0;\n+    printf(\"dpdkstat: ERROR initializing EAL ret = %d\\n\", ret);\n+    printf(\"dpdkstat: EAL arguments: \");","path":"src/dpdkstat.c","position":430,"original_position":430,"commit_id":"acbf4e5d5b848540c6fc0d9bfb235f6441564384","original_commit_id":"acbf4e5d5b848540c6fc0d9bfb235f6441564384","user":{"login":"octo","id":116087,"avatar_url":"https://avatars.githubusercontent.com/u/116087?v=3","gravatar_id":"","url":"https://api.github.com/users/octo","html_url":"https://github.com/octo","followers_url":"https://api.github.com/users/octo/followers","following_url":"https://api.github.com/users/octo/following{/other_user}","gists_url":"https://api.github.com/users/octo/gists{/gist_id}","starred_url":"https://api.github.com/users/octo/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/octo/subscriptions","organizations_url":"https://api.github.com/users/octo/orgs","repos_url":"https://api.github.com/users/octo/repos","events_url":"https://api.github.com/users/octo/events{/privacy}","received_events_url":"https://api.github.com/users/octo/received_events","type":"User","site_admin":false},"body":"These should probably be `ERROR()`s or be removed before merging.","created_at":"2016-09-14T12:45:52Z","updated_at":"2016-09-14T12:45:52Z","html_url":"https://github.com/collectd/collectd/pull/1649#discussion_r78740712","pull_request_url":"https://api.github.com/repos/collectd/collectd/pulls/1649","_links":{"self":{"href":"https://api.github.com/repos/collectd/collectd/pulls/comments/78740712"},"html":{"href":"https://github.com/collectd/collectd/pull/1649#discussion_r78740712"},"pull_request":{"href":"https://api.github.com/repos/collectd/collectd/pulls/1649"}}},"pull_request":{"url":"https://api.github.com/repos/collectd/collectd/pulls/1649","id":65036798,"html_url":"https://github.com/collectd/collectd/pull/1649","diff_url":"https://github.com/collectd/collectd/pull/1649.diff","patch_url":"https://github.com/collectd/collectd/pull/1649.patch","issue_url":"https://api.github.com/repos/collectd/collectd/issues/1649","number":1649,"state":"open","locked":false,"title":"dpdkstat: enable a plugin for DPDK stats","user":{"login":"maryamtahhan","id":5012288,"avatar_url":"https://avatars.githubusercontent.com/u/5012288?v=3","gravatar_id":"","url":"https://api.github.com/users/maryamtahhan","html_url":"https://github.com/maryamtahhan","followers_url":"https://api.github.com/users/maryamtahhan/followers","following_url":"https://api.github.com/users/maryamtahhan/following{/other_user}","gists_url":"https://api.github.com/users/maryamtahhan/gists{/gist_id}","starred_url":"https://api.github.com/users/maryamtahhan/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/maryamtahhan/subscriptions","organizations_url":"https://api.github.com/users/maryamtahhan/orgs","repos_url":"https://api.github.com/users/maryamtahhan/repos","events_url":"https://api.github.com/users/maryamtahhan/events{/privacy}","received_events_url":"https://api.github.com/users/maryamtahhan/received_events","type":"User","site_admin":false},"body":"This patch enables support to retrieve statistics for DPDK interfaces. An overview of the threading is as follows:\r\n\r\n1.  collectd `init()` or `read()` calls `dpdk_helper_spawn()` to retrieve the required size of xstats to allocate.\r\n    1.  DPDK counts ports, stats and length, writing them to shared-memory (SHM).\r\n    2.  DPDK helper (secondary) process quits, allowing cleanup of the shared memory.\r\n2.  collectd resizes shared-memory to size of stats as provided by DPDK.\r\n3.  collectd respawns the DPDK helper.\r\n    1. Helper blocks on a semaphore until told to read the stats from DPDK and write them to SHM.\r\n4.  collectd dispatches statistics\r\n    1.  Thread blocks on semaphore until stats are available.\r\n\r\nThis threading model is required to allow the plugin to detect when the DPDK primary process/application has been killed/reset, and to avoid the plugin from stopping another DPDK primary process from starting. Some extra housekeeping is in place to ensure collectd is never stalled by using `sem_timedwait()` with a timeout. If collectd dies, the helper process will automatically quit after a timeout, as it detects its ppid has changed.\r\n\r\nSigned-off-by: Harry van Haaren <harry.van.haaren@intel.com>\r\nSigned-off-by: Maryam Tahhan <maryam.tahhan@intel.com>","created_at":"2016-04-02T12:31:42Z","updated_at":"2016-09-14T12:45:52Z","closed_at":null,"merged_at":null,"merge_commit_sha":"bdd48a97db9d7fec1c0bb2883bd981f92d99e8f1","assignee":null,"assignees":[],"milestone":null,"commits_url":"https://api.github.com/repos/collectd/collectd/pulls/1649/commits","review_comments_url":"https://api.github.com/repos/collectd/collectd/pulls/1649/comments","review_comment_url":"https://api.github.com/repos/collectd/collectd/pulls/comments{/number}","comments_url":"https://api.github.com/repos/collectd/collectd/issues/1649/comments","statuses_url":"https://api.github.com/repos/collectd/collectd/statuses/acbf4e5d5b848540c6fc0d9bfb235f6441564384","head":{"label":"maryamtahhan:dpdkstat","ref":"dpdkstat","sha":"acbf4e5d5b848540c6fc0d9bfb235f6441564384","user":{"login":"maryamtahhan","id":5012288,"avatar_url":"https://avatars.githubusercontent.com/u/5012288?v=3","gravatar_id":"","url":"https://api.github.com/users/maryamtahhan","html_url":"https://github.com/maryamtahhan","followers_url":"https://api.github.com/users/maryamtahhan/followers","following_url":"https://api.github.com/users/maryamtahhan/following{/other_user}","gists_url":"https://api.github.com/users/maryamtahhan/gists{/gist_id}","starred_url":"https://api.github.com/users/maryamtahhan/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/maryamtahhan/subscriptions","organizations_url":"https://api.github.com/users/maryamtahhan/orgs","repos_url":"https://api.github.com/users/maryamtahhan/repos","events_url":"https://api.github.com/users/maryamtahhan/events{/privacy}","received_events_url":"https://api.github.com/users/maryamtahhan/received_events","type":"User","site_admin":false},"repo":{"id":55240614,"name":"collectd","full_name":"maryamtahhan/collectd","owner":{"login":"maryamtahhan","id":5012288,"avatar_url":"https://avatars.githubusercontent.com/u/5012288?v=3","gravatar_id":"","url":"https://api.github.com/users/maryamtahhan","html_url":"https://github.com/maryamtahhan","followers_url":"https://api.github.com/users/maryamtahhan/followers","following_url":"https://api.github.com/users/maryamtahhan/following{/other_user}","gists_url":"https://api.github.com/users/maryamtahhan/gists{/gist_id}","starred_url":"https://api.github.com/users/maryamtahhan/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/maryamtahhan/subscriptions","organizations_url":"https://api.github.com/users/maryamtahhan/orgs","repos_url":"https://api.github.com/users/maryamtahhan/repos","events_url":"https://api.github.com/users/maryamtahhan/events{/privacy}","received_events_url":"https://api.github.com/users/maryamtahhan/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/maryamtahhan/collectd","description":"The system statistics collection daemon - repo for new features to be merged into mainline collectd. Mirror of the canonical repository (updated automatically). Please send Pull Requests here!","fork":true,"url":"https://api.github.com/repos/maryamtahhan/collectd","forks_url":"https://api.github.com/repos/maryamtahhan/collectd/forks","keys_url":"https://api.github.com/repos/maryamtahhan/collectd/keys{/key_id}","collaborators_url":"https://api.github.com/repos/maryamtahhan/collectd/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/maryamtahhan/collectd/teams","hooks_url":"https://api.github.com/repos/maryamtahhan/collectd/hooks","issue_events_url":"https://api.github.com/repos/maryamtahhan/collectd/issues/events{/number}","events_url":"https://api.github.com/repos/maryamtahhan/collectd/events","assignees_url":"https://api.github.com/repos/maryamtahhan/collectd/assignees{/user}","branches_url":"https://api.github.com/repos/maryamtahhan/collectd/branches{/branch}","tags_url":"https://api.github.com/repos/maryamtahhan/collectd/tags","blobs_url":"https://api.github.com/repos/maryamtahhan/collectd/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/maryamtahhan/collectd/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/maryamtahhan/collectd/git/refs{/sha}","trees_url":"https://api.github.com/repos/maryamtahhan/collectd/git/trees{/sha}","statuses_url":"https://api.github.com/repos/maryamtahhan/collectd/statuses/{sha}","languages_url":"https://api.github.com/repos/maryamtahhan/collectd/languages","stargazers_url":"https://api.github.com/repos/maryamtahhan/collectd/stargazers","contributors_url":"https://api.github.com/repos/maryamtahhan/collectd/contributors","subscribers_url":"https://api.github.com/repos/maryamtahhan/collectd/subscribers","subscription_url":"https://api.github.com/repos/maryamtahhan/collectd/subscription","commits_url":"https://api.github.com/repos/maryamtahhan/collectd/commits{/sha}","git_commits_url":"https://api.github.com/repos/maryamtahhan/collectd/git/commits{/sha}","comments_url":"https://api.github.com/repos/maryamtahhan/collectd/comments{/number}","issue_comment_url":"https://api.github.com/repos/maryamtahhan/collectd/issues/comments{/number}","contents_url":"https://api.github.com/repos/maryamtahhan/collectd/contents/{+path}","compare_url":"https://api.github.com/repos/maryamtahhan/collectd/compare/{base}...{head}","merges_url":"https://api.github.com/repos/maryamtahhan/collectd/merges","archive_url":"https://api.github.com/repos/maryamtahhan/collectd/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/maryamtahhan/collectd/downloads","issues_url":"https://api.github.com/repos/maryamtahhan/collectd/issues{/number}","pulls_url":"https://api.github.com/repos/maryamtahhan/collectd/pulls{/number}","milestones_url":"https://api.github.com/repos/maryamtahhan/collectd/milestones{/number}","notifications_url":"https://api.github.com/repos/maryamtahhan/collectd/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/maryamtahhan/collectd/labels{/name}","releases_url":"https://api.github.com/repos/maryamtahhan/collectd/releases{/id}","deployments_url":"https://api.github.com/repos/maryamtahhan/collectd/deployments","created_at":"2016-04-01T15:03:06Z","updated_at":"2016-08-24T09:19:46Z","pushed_at":"2016-09-12T15:23:46Z","git_url":"git://github.com/maryamtahhan/collectd.git","ssh_url":"git@github.com:maryamtahhan/collectd.git","clone_url":"https://github.com/maryamtahhan/collectd.git","svn_url":"https://github.com/maryamtahhan/collectd","homepage":"http://collectd.org/","size":14703,"stargazers_count":1,"watchers_count":1,"language":"C","has_issues":false,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":1,"default_branch":"master"}},"base":{"label":"collectd:master","ref":"master","sha":"42c129f80a181553ac08b6e8d3484a845c674a07","user":{"login":"collectd","id":1027481,"avatar_url":"https://avatars.githubusercontent.com/u/1027481?v=3","gravatar_id":"","url":"https://api.github.com/users/collectd","html_url":"https://github.com/collectd","followers_url":"https://api.github.com/users/collectd/followers","following_url":"https://api.github.com/users/collectd/following{/other_user}","gists_url":"https://api.github.com/users/collectd/gists{/gist_id}","starred_url":"https://api.github.com/users/collectd/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/collectd/subscriptions","organizations_url":"https://api.github.com/users/collectd/orgs","repos_url":"https://api.github.com/users/collectd/repos","events_url":"https://api.github.com/users/collectd/events{/privacy}","received_events_url":"https://api.github.com/users/collectd/received_events","type":"Organization","site_admin":false},"repo":{"id":3208640,"name":"collectd","full_name":"collectd/collectd","owner":{"login":"collectd","id":1027481,"avatar_url":"https://avatars.githubusercontent.com/u/1027481?v=3","gravatar_id":"","url":"https://api.github.com/users/collectd","html_url":"https://github.com/collectd","followers_url":"https://api.github.com/users/collectd/followers","following_url":"https://api.github.com/users/collectd/following{/other_user}","gists_url":"https://api.github.com/users/collectd/gists{/gist_id}","starred_url":"https://api.github.com/users/collectd/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/collectd/subscriptions","organizations_url":"https://api.github.com/users/collectd/orgs","repos_url":"https://api.github.com/users/collectd/repos","events_url":"https://api.github.com/users/collectd/events{/privacy}","received_events_url":"https://api.github.com/users/collectd/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/collectd/collectd","description":"The system statistics collection daemon. Mirror of the canonical repository (updated automatically). Please send Pull Requests here!","fork":false,"url":"https://api.github.com/repos/collectd/collectd","forks_url":"https://api.github.com/repos/collectd/collectd/forks","keys_url":"https://api.github.com/repos/collectd/collectd/keys{/key_id}","collaborators_url":"https://api.github.com/repos/collectd/collectd/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/collectd/collectd/teams","hooks_url":"https://api.github.com/repos/collectd/collectd/hooks","issue_events_url":"https://api.github.com/repos/collectd/collectd/issues/events{/number}","events_url":"https://api.github.com/repos/collectd/collectd/events","assignees_url":"https://api.github.com/repos/collectd/collectd/assignees{/user}","branches_url":"https://api.github.com/repos/collectd/collectd/branches{/branch}","tags_url":"https://api.github.com/repos/collectd/collectd/tags","blobs_url":"https://api.github.com/repos/collectd/collectd/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/collectd/collectd/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/collectd/collectd/git/refs{/sha}","trees_url":"https://api.github.com/repos/collectd/collectd/git/trees{/sha}","statuses_url":"https://api.github.com/repos/collectd/collectd/statuses/{sha}","languages_url":"https://api.github.com/repos/collectd/collectd/languages","stargazers_url":"https://api.github.com/repos/collectd/collectd/stargazers","contributors_url":"https://api.github.com/repos/collectd/collectd/contributors","subscribers_url":"https://api.github.com/repos/collectd/collectd/subscribers","subscription_url":"https://api.github.com/repos/collectd/collectd/subscription","commits_url":"https://api.github.com/repos/collectd/collectd/commits{/sha}","git_commits_url":"https://api.github.com/repos/collectd/collectd/git/commits{/sha}","comments_url":"https://api.github.com/repos/collectd/collectd/comments{/number}","issue_comment_url":"https://api.github.com/repos/collectd/collectd/issues/comments{/number}","contents_url":"https://api.github.com/repos/collectd/collectd/contents/{+path}","compare_url":"https://api.github.com/repos/collectd/collectd/compare/{base}...{head}","merges_url":"https://api.github.com/repos/collectd/collectd/merges","archive_url":"https://api.github.com/repos/collectd/collectd/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/collectd/collectd/downloads","issues_url":"https://api.github.com/repos/collectd/collectd/issues{/number}","pulls_url":"https://api.github.com/repos/collectd/collectd/pulls{/number}","milestones_url":"https://api.github.com/repos/collectd/collectd/milestones{/number}","notifications_url":"https://api.github.com/repos/collectd/collectd/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/collectd/collectd/labels{/name}","releases_url":"https://api.github.com/repos/collectd/collectd/releases{/id}","deployments_url":"https://api.github.com/repos/collectd/collectd/deployments","created_at":"2012-01-18T13:07:51Z","updated_at":"2016-09-14T03:13:15Z","pushed_at":"2016-09-14T11:59:16Z","git_url":"git://github.com/collectd/collectd.git","ssh_url":"git@github.com:collectd/collectd.git","clone_url":"https://github.com/collectd/collectd.git","svn_url":"https://github.com/collectd/collectd","homepage":"http://collectd.org/","size":34562,"stargazers_count":1260,"watchers_count":1260,"language":"C","has_issues":true,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":711,"mirror_url":null,"open_issues_count":295,"forks":711,"open_issues":295,"watchers":1260,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/collectd/collectd/pulls/1649"},"html":{"href":"https://github.com/collectd/collectd/pull/1649"},"issue":{"href":"https://api.github.com/repos/collectd/collectd/issues/1649"},"comments":{"href":"https://api.github.com/repos/collectd/collectd/issues/1649/comments"},"review_comments":{"href":"https://api.github.com/repos/collectd/collectd/pulls/1649/comments"},"review_comment":{"href":"https://api.github.com/repos/collectd/collectd/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/collectd/collectd/pulls/1649/commits"},"statuses":{"href":"https://api.github.com/repos/collectd/collectd/statuses/acbf4e5d5b848540c6fc0d9bfb235f6441564384"}}}}
{"actor":{"display_login":"octo"}}