get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

GET /api/patches/24410/?format=api
HTTP 200 OK
Allow: GET, PUT, PATCH, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "id": 24410,
    "url": "https://patches.dpdk.org/api/patches/24410/?format=api",
    "web_url": "https://patches.dpdk.org/project/dpdk/patch/1495211986-15177-3-git-send-email-anatoly.burakov@intel.com/",
    "project": {
        "id": 1,
        "url": "https://patches.dpdk.org/api/projects/1/?format=api",
        "name": "DPDK",
        "link_name": "dpdk",
        "list_id": "dev.dpdk.org",
        "list_email": "dev@dpdk.org",
        "web_url": "http://core.dpdk.org",
        "scm_url": "git://dpdk.org/dpdk",
        "webscm_url": "http://git.dpdk.org/dpdk",
        "list_archive_url": "https://inbox.dpdk.org/dev",
        "list_archive_url_format": "https://inbox.dpdk.org/dev/{}",
        "commit_url_format": ""
    },
    "msgid": "<1495211986-15177-3-git-send-email-anatoly.burakov@intel.com>",
    "list_archive_url": "https://inbox.dpdk.org/dev/1495211986-15177-3-git-send-email-anatoly.burakov@intel.com",
    "date": "2017-05-19T16:39:44",
    "name": "[dpdk-dev,RFC,2/4] eal: enable experimental dlopen()-based secondary process support",
    "commit_ref": null,
    "pull_url": null,
    "state": "rejected",
    "archived": true,
    "hash": "9998c5a60176febf34395e2172ad8f30a17edc69",
    "submitter": {
        "id": 4,
        "url": "https://patches.dpdk.org/api/people/4/?format=api",
        "name": "Burakov, Anatoly",
        "email": "anatoly.burakov@intel.com"
    },
    "delegate": {
        "id": 1,
        "url": "https://patches.dpdk.org/api/users/1/?format=api",
        "username": "tmonjalo",
        "first_name": "Thomas",
        "last_name": "Monjalon",
        "email": "thomas@monjalon.net"
    },
    "mbox": "https://patches.dpdk.org/project/dpdk/patch/1495211986-15177-3-git-send-email-anatoly.burakov@intel.com/mbox/",
    "series": [],
    "comments": "https://patches.dpdk.org/api/patches/24410/comments/",
    "check": "fail",
    "checks": "https://patches.dpdk.org/api/patches/24410/checks/",
    "tags": {},
    "related": [],
    "headers": {
        "Return-Path": "<dev-bounces@dpdk.org>",
        "X-Original-To": "patchwork@dpdk.org",
        "Delivered-To": "patchwork@dpdk.org",
        "Received": [
            "from [92.243.14.124] (localhost [IPv6:::1])\n\tby dpdk.org (Postfix) with ESMTP id E924C3253;\n\tFri, 19 May 2017 18:40:05 +0200 (CEST)",
            "from mga01.intel.com (mga01.intel.com [192.55.52.88])\n\tby dpdk.org (Postfix) with ESMTP id 335522C6D\n\tfor <dev@dpdk.org>; Fri, 19 May 2017 18:40:03 +0200 (CEST)",
            "from orsmga003.jf.intel.com ([10.7.209.27])\n\tby fmsmga101.fm.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384;\n\t19 May 2017 09:39:48 -0700",
            "from irvmail001.ir.intel.com ([163.33.26.43])\n\tby orsmga003.jf.intel.com with ESMTP; 19 May 2017 09:39:47 -0700",
            "from sivswdev02.ir.intel.com (sivswdev02.ir.intel.com\n\t[10.237.217.46])\n\tby irvmail001.ir.intel.com (8.14.3/8.13.6/MailSET/Hub) with ESMTP id\n\tv4JGdkvU024645 for <dev@dpdk.org>; Fri, 19 May 2017 17:39:46 +0100",
            "from sivswdev02.ir.intel.com (localhost [127.0.0.1])\n\tby sivswdev02.ir.intel.com with ESMTP id v4JGdk8f015325\n\tfor <dev@dpdk.org>; Fri, 19 May 2017 17:39:46 +0100",
            "(from aburakov@localhost)\n\tby sivswdev02.ir.intel.com with ? id v4JGdkmW015321\n\tfor dev@dpdk.org; Fri, 19 May 2017 17:39:46 +0100"
        ],
        "X-ExtLoop1": "1",
        "X-IronPort-AV": "E=Sophos;i=\"5.38,364,1491289200\"; d=\"scan'208\";a=\"970796961\"",
        "From": "Anatoly Burakov <anatoly.burakov@intel.com>",
        "To": "dev@dpdk.org",
        "Date": "Fri, 19 May 2017 17:39:44 +0100",
        "Message-Id": "<1495211986-15177-3-git-send-email-anatoly.burakov@intel.com>",
        "X-Mailer": "git-send-email 1.7.0.7",
        "In-Reply-To": "<1495211986-15177-1-git-send-email-anatoly.burakov@intel.com>",
        "References": "<1495211986-15177-1-git-send-email-anatoly.burakov@intel.com>",
        "Subject": "[dpdk-dev] [RFC 2/4] eal: enable experimental dlopen()-based\n\tsecondary process support",
        "X-BeenThere": "dev@dpdk.org",
        "X-Mailman-Version": "2.1.15",
        "Precedence": "list",
        "List-Id": "DPDK patches and discussions <dev.dpdk.org>",
        "List-Unsubscribe": "<http://dpdk.org/ml/options/dev>,\n\t<mailto:dev-request@dpdk.org?subject=unsubscribe>",
        "List-Archive": "<http://dpdk.org/ml/archives/dev/>",
        "List-Post": "<mailto:dev@dpdk.org>",
        "List-Help": "<mailto:dev-request@dpdk.org?subject=help>",
        "List-Subscribe": "<http://dpdk.org/ml/listinfo/dev>,\n\t<mailto:dev-request@dpdk.org?subject=subscribe>",
        "Errors-To": "dev-bounces@dpdk.org",
        "Sender": "\"dev\" <dev-bounces@dpdk.org>"
    },
    "content": "Primary process forks itself into a new process that will be used as\nbasis for forking secondary processes. Secondary process then connects\nto this forked process over a socket, and triggers a fork.\n\nThis new forked secondary dlopen()'s the original secondary process\nbinary and runs main() again. In the meantime, the original secondary\nprocess waits until this new forked secondary dies, and exits.\n\n\"Waiting until secondary dies\" is achieved through a blocking flock()\ncall - once it succeeds, secondary is dead as all locks are released at\nprocess exit.\n\nSigned-off-by: Anatoly Burakov <anatoly.burakov@intel.com>\n---\n lib/librte_eal/linuxapp/eal/Makefile           |   2 +\n lib/librte_eal/linuxapp/eal/eal.c              | 105 +++++-\n lib/librte_eal/linuxapp/eal/eal_mp.h           |  54 +++\n lib/librte_eal/linuxapp/eal/eal_mp_primary.c   | 477 +++++++++++++++++++++++++\n lib/librte_eal/linuxapp/eal/eal_mp_secondary.c | 301 ++++++++++++++++\n 5 files changed, 933 insertions(+), 6 deletions(-)\n create mode 100755 lib/librte_eal/linuxapp/eal/eal_mp.h\n create mode 100755 lib/librte_eal/linuxapp/eal/eal_mp_primary.c\n create mode 100755 lib/librte_eal/linuxapp/eal/eal_mp_secondary.c",
    "diff": "diff --git a/lib/librte_eal/linuxapp/eal/Makefile b/lib/librte_eal/linuxapp/eal/Makefile\nindex 24aab8d..f0ec382 100644\n--- a/lib/librte_eal/linuxapp/eal/Makefile\n+++ b/lib/librte_eal/linuxapp/eal/Makefile\n@@ -63,6 +63,8 @@ SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += eal_log.c\n SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += eal_mp_socket.c\n SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += eal_vfio.c\n SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += eal_vfio_mp_sync.c\n+SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += eal_mp_secondary.c\n+SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += eal_mp_primary.c\n SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += eal_pci.c\n SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += eal_pci_uio.c\n SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += eal_pci_vfio.c\ndiff --git a/lib/librte_eal/linuxapp/eal/eal.c b/lib/librte_eal/linuxapp/eal/eal.c\nindex 7c78f2d..3d646b9 100644\n--- a/lib/librte_eal/linuxapp/eal/eal.c\n+++ b/lib/librte_eal/linuxapp/eal/eal.c\n@@ -80,6 +80,7 @@\n #include <malloc_heap.h>\n \n #include \"eal_private.h\"\n+#include \"eal_mp.h\"\n #include \"eal_thread.h\"\n #include \"eal_internal_cfg.h\"\n #include \"eal_filesystem.h\"\n@@ -480,7 +481,7 @@ eal_parse_vfio_intr(const char *mode)\n \n /* Parse the arguments for --log-level only */\n static void\n-eal_log_level_parse(int argc, char **argv)\n+eal_early_parse(int argc, char **argv)\n {\n \tint opt;\n \tchar **argvopt;\n@@ -504,6 +505,9 @@ eal_log_level_parse(int argc, char **argv)\n \t\tret = (opt == OPT_LOG_LEVEL_NUM) ?\n \t\t\teal_parse_common_option(opt, optarg, &internal_config) : 0;\n \n+\t\tret = (opt == OPT_PROC_TYPE_NUM) ?\n+\t\t    eal_parse_common_option(opt, optarg, &internal_config) : 0;\n+\n \t\t/* common parser is not happy */\n \t\tif (ret < 0)\n \t\t\tbreak;\n@@ -745,6 +749,68 @@ static void rte_eal_init_alert(const char *msg)\n \tRTE_LOG(ERR, EAL, \"%s\\n\", msg);\n }\n \n+/* secondary needs to pass parameters to the app */\n+static int\n+secondary_first_run(int argc, char **argv) {\n+\trte_srand(rte_rdtsc());\n+\n+\tif (eal_secondary_init(argc, argv) < 0)\n+\t\trte_panic(\"Cannot init secondary\\n\");\n+\n+\tRTE_LOG(ERR, EAL, \"Secondary preliminary init\\n\");\n+\n+\treturn 0;\n+}\n+\n+static int\n+secondary_second_run(void) {\n+\tunsigned i;\n+\tint ret;\n+\tchar thread_name[RTE_MAX_THREAD_NAME_LEN];\n+\n+\teal_thread_init_master(rte_config.master_lcore);\n+\n+\tRTE_LCORE_FOREACH_SLAVE(i) {\n+\n+\t\t/*\n+\t\t * create communication pipes between master thread\n+\t\t * and children\n+\t\t */\n+\t\tif (pipe(lcore_config[i].pipe_master2slave) < 0)\n+\t\t\trte_panic(\"Cannot create pipe\\n\");\n+\t\tif (pipe(lcore_config[i].pipe_slave2master) < 0)\n+\t\t\trte_panic(\"Cannot create pipe\\n\");\n+\n+\t\tlcore_config[i].state = WAIT;\n+\n+\t\t/* create a thread for each lcore */\n+\t\tret = pthread_create(&lcore_config[i].thread_id, NULL,\n+\t\t             eal_thread_loop, NULL);\n+\t\tif (ret != 0)\n+\t\t\trte_panic(\"Cannot create thread\\n\");\n+\n+\t\t/* Set thread_name for aid in debugging. */\n+\t\tsnprintf(thread_name, RTE_MAX_THREAD_NAME_LEN,\n+\t\t    \"lcore-slave-%d\", i);\n+\t\tret = rte_thread_setname(lcore_config[i].thread_id,\n+\t\t                thread_name);\n+\t\tif (ret != 0)\n+\t\t\tRTE_LOG(DEBUG, EAL,\n+\t\t\t    \"Cannot set name for lcore thread\\n\");\n+\t}\n+\n+\t/*\n+\t * Launch a dummy function on all slave lcores, so that master lcore\n+\t * knows they are all ready when this function returns.\n+\t */\n+\trte_eal_mp_remote_launch(sync_func, NULL, SKIP_MASTER);\n+\trte_eal_mp_wait_lcore();\n+\n+\tRTE_LOG(ERR, EAL, \"Secondary finished init\\n\");\n+\n+\treturn 0;\n+}\n+\n /* Launch threads, called at application init(). */\n int\n rte_eal_init(int argc, char **argv)\n@@ -752,6 +818,7 @@ rte_eal_init(int argc, char **argv)\n \tint i, fctret, ret;\n \tpthread_t thread_id;\n \tstatic rte_atomic32_t run_once = RTE_ATOMIC32_INIT(0);\n+\tstatic rte_atomic32_t run_once_secondary = RTE_ATOMIC32_INIT(0);\n \tconst char *logid;\n \tchar cpuset[RTE_CPU_AFFINITY_STR_LEN];\n \tchar thread_name[RTE_MAX_THREAD_NAME_LEN];\n@@ -763,10 +830,28 @@ rte_eal_init(int argc, char **argv)\n \t\treturn -1;\n \t}\n \n+\t/* short-circuit running secondary processes */\n \tif (!rte_atomic32_test_and_set(&run_once)) {\n-\t\trte_eal_init_alert(\"already called initialization.\");\n-\t\trte_errno = EALREADY;\n-\t\treturn -1;\n+\t\tif (internal_config.process_type == RTE_PROC_SECONDARY) {\n+\t\t\tif (!rte_atomic32_test_and_set(&run_once_secondary)) {\n+\t\t\t\tRTE_LOG(ERR, EAL, \"Can't run secondary init twice!\\n\");\n+\t\t\t\trte_errno = EALREADY;\n+\t\t\t\treturn -1;\n+\t\t\t} else {\n+\n+\t\t\t\t/* parse EAL arguments before running secondary process */\n+\t\t\t\tfctret = eal_parse_args(argc, argv);\n+\t\t\t\tif (fctret < 0)\n+\t\t\t\t\texit(1);\n+\n+\t\t\t\tsecondary_second_run();\n+\t\t\t\treturn fctret;\n+\t\t\t}\n+\t\t} else {\n+\t\t\trte_eal_init_alert(\"already called initialization.\");\n+\t\t\trte_errno = EALREADY;\n+\t\t\treturn -1;\n+\t\t}\n \t}\n \n \tlogid = strrchr(argv[0], '/');\n@@ -776,8 +861,8 @@ rte_eal_init(int argc, char **argv)\n \n \teal_reset_internal_config(&internal_config);\n \n-\t/* set log level as early as possible */\n-\teal_log_level_parse(argc, argv);\n+\t/* set log level and process type as early as possible */\n+\teal_early_parse(argc, argv);\n \n \tif (rte_eal_cpu_init() < 0) {\n \t\trte_eal_init_alert(\"Cannot detect lcores.\");\n@@ -785,6 +870,11 @@ rte_eal_init(int argc, char **argv)\n \t\treturn -1;\n \t}\n \n+\tif (internal_config.process_type == RTE_PROC_SECONDARY) {\n+\t\tsecondary_first_run(argc, argv);\n+\t\trte_exit(EXIT_SUCCESS, \"Done\");\n+\t}\n+\n \tfctret = eal_parse_args(argc, argv);\n \tif (fctret < 0) {\n \t\trte_eal_init_alert(\"Invalid 'command line' arguments.\");\n@@ -939,6 +1029,9 @@ rte_eal_init(int argc, char **argv)\n \t\treturn -1;\n \t}\n \n+\tif (eal_secondary_mp_sync_setup() < 0)\n+\t\tRTE_LOG(WARNING, EAL, \"Couldn't start multiprocess socket!\\n\");\n+\n \trte_eal_mcfg_complete();\n \n \treturn fctret;\ndiff --git a/lib/librte_eal/linuxapp/eal/eal_mp.h b/lib/librte_eal/linuxapp/eal/eal_mp.h\nnew file mode 100755\nindex 0000000..43ff9df\n--- /dev/null\n+++ b/lib/librte_eal/linuxapp/eal/eal_mp.h\n@@ -0,0 +1,54 @@\n+/*-\n+ *   BSD LICENSE\n+ *\n+ *   Copyright(c) 2010-2017 Intel Corporation. All rights reserved.\n+ *   All rights reserved.\n+ *\n+ *   Redistribution and use in source and binary forms, with or without\n+ *   modification, are permitted provided that the following conditions\n+ *   are met:\n+ *\n+ *     * Redistributions of source code must retain the above copyright\n+ *       notice, this list of conditions and the following disclaimer.\n+ *     * Redistributions in binary form must reproduce the above copyright\n+ *       notice, this list of conditions and the following disclaimer in\n+ *       the documentation and/or other materials provided with the\n+ *       distribution.\n+ *     * Neither the name of Intel Corporation nor the names of its\n+ *       contributors may be used to endorse or promote products derived\n+ *       from this software without specific prior written permission.\n+ *\n+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n+ *   \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n+ */\n+\n+#ifndef EAL_MP_H\n+#define EAL_MP_H\n+\n+#include \"eal_mp_socket.h\"\n+\n+#define SOCKET_REQ_FORK SOCKET_REQ_USER + 0\n+#define SOCKET_REQ_STDIN SOCKET_REQ_USER + 1\n+#define SOCKET_REQ_STDOUT SOCKET_REQ_USER + 2\n+#define SOCKET_REQ_STDERR SOCKET_REQ_USER + 3\n+#define SOCKET_REQ_LOGFILE SOCKET_REQ_USER + 4\n+#define SOCKET_REQ_PATH SOCKET_REQ_USER + 5\n+#define SOCKET_REQ_ARGC SOCKET_REQ_USER + 6\n+#define SOCKET_REQ_ARGV SOCKET_REQ_USER + 7\n+\n+int eal_secondary_mp_sync_setup(void);\n+int eal_secondary_mp_sync_connect_to_primary(void);\n+void eal_secondary_mp_sync_get_socket_path(char *buffer, int bufsz);\n+\n+int eal_secondary_init(int argc, char **argv);\n+\n+#endif // EAL_MP_H\ndiff --git a/lib/librte_eal/linuxapp/eal/eal_mp_primary.c b/lib/librte_eal/linuxapp/eal/eal_mp_primary.c\nnew file mode 100755\nindex 0000000..32fce69\n--- /dev/null\n+++ b/lib/librte_eal/linuxapp/eal/eal_mp_primary.c\n@@ -0,0 +1,477 @@\n+/*-\n+ *   BSD LICENSE\n+ *\n+ *   Copyright(c) 2010-2017 Intel Corporation. All rights reserved.\n+ *   All rights reserved.\n+ *\n+ *   Redistribution and use in source and binary forms, with or without\n+ *   modification, are permitted provided that the following conditions\n+ *   are met:\n+ *\n+ *     * Redistributions of source code must retain the above copyright\n+ *       notice, this list of conditions and the following disclaimer.\n+ *     * Redistributions in binary form must reproduce the above copyright\n+ *       notice, this list of conditions and the following disclaimer in\n+ *       the documentation and/or other materials provided with the\n+ *       distribution.\n+ *     * Neither the name of Intel Corporation nor the names of its\n+ *       contributors may be used to endorse or promote products derived\n+ *       from this software without specific prior written permission.\n+ *\n+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n+ *   \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n+ */\n+\n+#include <string.h>\n+#include <fcntl.h>\n+#include <sys/socket.h>\n+#include <sys/types.h>\n+#include <sys/wait.h>\n+#include <limits.h>\n+#include <pthread.h>\n+#include <stdlib.h>\n+#include <signal.h>\n+#include <dlfcn.h>\n+#include <unistd.h>\n+#include <stdbool.h>\n+#include <time.h>\n+#include <sys/file.h>\n+#include <linux/version.h>\n+#include <signal.h>\n+#include <sys/prctl.h>\n+\n+/* sys/un.h with __USE_MISC uses strlen, which is unsafe */\n+#ifdef __USE_MISC\n+#define REMOVED_USE_MISC\n+#undef __USE_MISC\n+#endif\n+#include <sys/un.h>\n+/* make sure we redefine __USE_MISC only if it was previously undefined */\n+#ifdef REMOVED_USE_MISC\n+#define __USE_MISC\n+#undef REMOVED_USE_MISC\n+#endif\n+\n+#include <rte_log.h>\n+#include <rte_pci.h>\n+#include <rte_eal_memconfig.h>\n+#include <rte_malloc.h>\n+#include <rte_cycles.h>\n+\n+#include \"eal_filesystem.h\"\n+#include \"eal_pci_init.h\"\n+#include \"eal_thread.h\"\n+#include \"eal_mp.h\"\n+\n+#define SOCKET_PATH_FMT \"%s/.%s_mp_secondary_socket\"\n+#define LOCKFILE_PATH_FMT \"%s/.%s_secondary_lock_%s\"\n+\n+static\n+const char *get_run_dir(void) {\n+\tconst char *dir = \"/var/run\";\n+\tconst char *home_dir = getenv(\"HOME\");\n+\n+\tif (getuid() != 0 && home_dir != NULL)\n+\t\tdir = home_dir;\n+\treturn dir;\n+}\n+\n+static\n+void get_rand_str(char *str, int sz) {\n+\tchar charset[] = \"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789\";\n+\tfor (int i = 0; i < sz - 1; i++) {\n+\t\t// this does not give us *true* randomness but it's good enough\n+\t\tint idx = rand() % sizeof(charset);\n+\t\tstr[i] = charset[idx];\n+\t}\n+\tstr[sz - 1] = '\\0';\n+}\n+\n+/* we need to know its length */\n+static\n+int get_lock_file_path(char *str, int sz) {\n+\tchar rand_str[16];\n+\n+\tget_rand_str(rand_str, 16);\n+\n+\treturn snprintf(str, sz, LOCKFILE_PATH_FMT, get_run_dir(),\n+\t                internal_config.hugefile_prefix, rand_str);\n+}\n+\n+static int secondary_mp_socket_fd;\n+\n+/* get socket path (/var/run if root, $HOME otherwise) */\n+void\n+eal_secondary_mp_sync_get_socket_path(char *buffer, int bufsz)\n+{\n+\t/* use current prefix as file path */\n+\tsnprintf(buffer, bufsz, SOCKET_PATH_FMT, get_run_dir(),\n+\t        internal_config.hugefile_prefix);\n+}\n+\n+static void *\n+secondary_wait_thread(void * arg)\n+{\n+\tint status;\n+\tpid_t pid = *(pid_t*) arg;\n+\n+\tRTE_LOG(INFO, EAL, \"Secondary process %i started\\n\", pid);\n+\n+\twaitpid(pid, &status, 0);\n+\n+\tRTE_LOG(INFO, EAL, \"Secondary process %i died\\n\", pid);\n+\n+\t/* TODO: notify others this one has died? */\n+\n+\tpthread_exit(0);\n+\treturn 0;\n+}\n+\n+/* handle parent exit */\n+static void\n+parent_exit(int __rte_unused sig)\n+{\n+\texit(0);\n+}\n+\n+/*\n+ * data flow for socket comm protocol:\n+ *\n+ * in case of any error, socket is closed.\n+ */\n+\n+static int\n+secondary_mp_sync_socket_setup(void)\n+{\n+\tint socket_fd;\n+\tchar path[PATH_MAX];\n+\n+\t/* generate random socket name */\n+\teal_secondary_mp_sync_get_socket_path(path, sizeof(path));\n+\n+\tsocket_fd = eal_mp_sync_socket_setup(path);\n+\tif (socket_fd < 0) {\n+\t\tRTE_LOG(ERR, EAL, \"Failed to create socket!\\n\");\n+\t\treturn -1;\n+\t}\n+\n+\t/* save the socket in local configuration */\n+\tsecondary_mp_socket_fd = socket_fd;\n+\n+\treturn 0;\n+}\n+\n+/* connect socket_fd in secondary process to the primary process's socket */\n+int\n+eal_secondary_mp_sync_connect_to_primary(void)\n+{\n+\tchar path[PATH_MAX];\n+\n+\teal_secondary_mp_sync_get_socket_path(path, sizeof(path));\n+\n+\treturn eal_mp_sync_connect_to_primary(path);\n+}\n+\n+/*\n+ * listen for sockets\n+ */\n+static void\n+secondary_mp_sync_listener(void)\n+{\n+\tint cur_argv = 0, argc = 0;\n+\tchar *argv[4096] = {0};\n+\tchar *str;\n+\tint ret;\n+\n+\t/* get seed from tsc */\n+\tsrand((unsigned) rte_rdtsc());\n+\n+\tif (secondary_mp_sync_socket_setup() < 0) {\n+\t\tRTE_LOG(ERR, EAL, \"Failed to set up local socket!\\n\");\n+\t\treturn;\n+\t}\n+\n+\t/* wait for requests on the socket and the IPC */\n+\tfor (;;) {\n+\t\tint conn_sock;\n+\t\tstruct sockaddr_un addr;\n+\t\tsocklen_t sockaddr_len = sizeof(addr);\n+\n+\t\t/* this is a blocking call */\n+\t\tconn_sock = accept(secondary_mp_socket_fd, (struct sockaddr *) &addr,\n+\t\t        &sockaddr_len);\n+\n+\t\t/* just restart on error */\n+\t\tif (conn_sock == -1)\n+\t\t\tcontinue;\n+\n+\t\t/* set socket to linger after close */\n+\t\tstruct linger l;\n+\t\tl.l_onoff = 1;\n+\t\tl.l_linger = 60;\n+\n+\t\tif (setsockopt(conn_sock, SOL_SOCKET, SO_LINGER, &l, sizeof(l)) < 0)\n+\t\t\tRTE_LOG(WARNING, EAL, \"Cannot set SO_LINGER option \"\n+\t\t\t        \"on listen socket (%s)\\n\", strerror(errno));\n+\n+\t\tbool done = false;\n+\t\tbool is_fork = false;\n+\n+\t\t/* forked process data */\n+\t\tchar path[PATH_MAX] = \"\";\n+\t\tchar lockfile[PATH_MAX] = \"\";\n+\t\tint sp_stdin = STDIN_FILENO;\n+\t\tint sp_stdout = STDOUT_FILENO;\n+\t\tint sp_stderr = STDERR_FILENO;\n+\t\tint sp_log = rte_logs.file == NULL ? sp_stderr : fileno(rte_logs.file);\n+\n+\t\twhile (!done) {\n+\t\t\tret = eal_mp_sync_receive_request(conn_sock);\n+\n+\t\t\tswitch (ret) {\n+\t\t\tcase SOCKET_REQ_STDIN:\n+\t\t\t\teal_mp_sync_send_request(conn_sock, SOCKET_OK);\n+\n+\t\t\t\tret = eal_mp_sync_receive_fd(conn_sock);\n+\t\t\t\tif (ret < 0) {\n+\t\t\t\t\teal_mp_sync_send_request(conn_sock, SOCKET_ERR);\n+\t\t\t\t\tdone = true;\n+\t\t\t\t\tbreak;\n+\t\t\t\t}\n+\t\t\t\teal_mp_sync_send_request(conn_sock, SOCKET_OK);\n+\t\t\t\tsp_stdin = ret;\n+\t\t\t\tbreak;\n+\t\t\tcase SOCKET_REQ_STDOUT:\n+\t\t\t\teal_mp_sync_send_request(conn_sock, SOCKET_OK);\n+\n+\t\t\t\tret = eal_mp_sync_receive_fd(conn_sock);\n+\t\t\t\tif (ret < 0) {\n+\t\t\t\t\teal_mp_sync_send_request(conn_sock, SOCKET_ERR);\n+\t\t\t\t\tdone = true;\n+\t\t\t\t\tbreak;\n+\t\t\t\t}\n+\t\t\t\teal_mp_sync_send_request(conn_sock, SOCKET_OK);\n+\t\t\t\tsp_stdout = ret;\n+\t\t\t\tbreak;\n+\t\t\tcase SOCKET_REQ_STDERR:\n+\t\t\t\teal_mp_sync_send_request(conn_sock, SOCKET_OK);\n+\n+\t\t\t\tret = eal_mp_sync_receive_fd(conn_sock);\n+\t\t\t\tif (ret < 0) {\n+\t\t\t\t\teal_mp_sync_send_request(conn_sock, SOCKET_ERR);\n+\t\t\t\t\tdone = true;\n+\t\t\t\t\tbreak;\n+\t\t\t\t}\n+\t\t\t\teal_mp_sync_send_request(conn_sock, SOCKET_OK);\n+\t\t\t\tsp_stderr = ret;\n+\t\t\t\tbreak;\n+\t\t\tcase SOCKET_REQ_LOGFILE:\n+\t\t\t\teal_mp_sync_send_request(conn_sock, SOCKET_OK);\n+\n+\t\t\t\tret = eal_mp_sync_receive_fd(conn_sock);\n+\t\t\t\tif (ret < 0) {\n+\t\t\t\t\teal_mp_sync_send_request(conn_sock, SOCKET_ERR);\n+\t\t\t\t\tdone = true;\n+\t\t\t\t\tbreak;\n+\t\t\t\t}\n+\t\t\t\teal_mp_sync_send_request(conn_sock, SOCKET_OK);\n+\t\t\t\tsp_log = ret;\n+\t\t\t\tbreak;\n+\t\t\tcase SOCKET_REQ_PATH:\n+\t\t\t\teal_mp_sync_send_request(conn_sock, SOCKET_OK);\n+\n+\t\t\t\t/* receive path */\n+\t\t\t\tif (eal_mp_sync_receive_data(conn_sock, path, PATH_MAX)) {\n+\t\t\t\t\teal_mp_sync_send_request(conn_sock, SOCKET_ERR);\n+\t\t\t\t\tdone = true;\n+\t\t\t\t\tbreak;\n+\t\t\t\t}\n+\t\t\t\teal_mp_sync_send_request(conn_sock, SOCKET_OK);\n+\t\t\t\tbreak;\n+\t\t\tcase SOCKET_REQ_ARGC:\n+\t\t\t\teal_mp_sync_send_request(conn_sock, SOCKET_OK);\n+\n+\t\t\t\t/* receive argc */\n+\t\t\t\tif (eal_mp_sync_receive_data(conn_sock, &argc, sizeof(argc))) {\n+\t\t\t\t\teal_mp_sync_send_request(conn_sock, SOCKET_ERR);\n+\t\t\t\t\tdone = true;\n+\t\t\t\t\tbreak;\n+\t\t\t\t}\n+\t\t\t\teal_mp_sync_send_request(conn_sock, SOCKET_OK);\n+\t\t\t\tbreak;\n+\t\t\tcase SOCKET_REQ_ARGV:\n+\t\t\t\teal_mp_sync_send_request(conn_sock, SOCKET_OK);\n+\n+\t\t\t\t/* 4K should be enough for everyone */\n+\t\t\t\tstr = (char*) calloc(1024, 4);\n+\n+\t\t\t\t/* receive argv */\n+\t\t\t\tif (eal_mp_sync_receive_data(conn_sock, str, 4096)) {\n+\t\t\t\t\teal_mp_sync_send_request(conn_sock, SOCKET_ERR);\n+\t\t\t\t\tdone = true;\n+\t\t\t\t\tbreak;\n+\t\t\t\t}\n+\t\t\t\targv[cur_argv++] = str;\n+\n+\t\t\t\teal_mp_sync_send_request(conn_sock, SOCKET_OK);\n+\t\t\t\tbreak;\n+\t\t\tcase SOCKET_REQ_FORK:\n+\t\t\t\t/*\n+\t\t\t\t * before we can fork, we need to make sure that argc matches\n+\t\t\t\t * cur_argv\n+\t\t\t\t */\n+\t\t\t\tif (argc != cur_argv) {\n+\t\t\t\t\tRTE_LOG(ERR, EAL, \"Argument number mismatch\\n\");\n+\t\t\t\t\teal_mp_sync_send_request(conn_sock, SOCKET_ERR);\n+\t\t\t\t\tdone = true;\n+\t\t\t\t\tbreak;\n+\t\t\t\t}\n+\t\t\t\teal_mp_sync_send_request(conn_sock, SOCKET_OK);\n+\n+\t\t\t\t// get_lock_file_path returns length, not total bytes\n+\t\t\t\tint len = get_lock_file_path(lockfile, sizeof(lockfile)) + 1;\n+\n+\t\t\t\tpid_t id = fork();\n+\n+\t\t\t\tif (id < 0) {\n+\t\t\t\t\tRTE_LOG(ERR, EAL, \"Failed to fork\\n\");\n+\t\t\t\t\teal_mp_sync_send_request(conn_sock, SOCKET_ERR);\n+\t\t\t\t\tdone = true;\n+\t\t\t\t\tbreak;\n+\t\t\t\t}\n+\n+\t\t\t\t/* we're going to be forked, so stop the loop */\n+\t\t\t\tdone = true;\n+\t\t\t\tif (id == 0) {\n+\t\t\t\t\t/* pointer to exported function */\n+\t\t\t\t\tvoid (*exported)(int argc, char** argv);\n+\t\t\t\t\tis_fork = true;\n+\n+\t\t\t\t\t/* touch the file */\n+\t\t\t\t\tint fd = creat(lockfile, O_EXCL);\n+\t\t\t\t\tflock(fd, LOCK_EX);\n+\n+\t\t\t\t\t/* set up file descriptors */\n+\t\t\t\t\tdup2(sp_stdin, STDIN_FILENO);\n+\t\t\t\t\tdup2(sp_stdout, STDOUT_FILENO);\n+\t\t\t\t\tdup2(sp_stderr, STDERR_FILENO);\n+\t\t\t\t\trte_openlog_stream(fdopen(sp_log, \"w+\"));\n+\n+\t\t\t\t\t/* send lockfile path */\n+\t\t\t\t\teal_mp_sync_send_data(conn_sock, lockfile, len);\n+\n+\t\t\t\t\t/* close the sockets */\n+\t\t\t\t\tclose(secondary_mp_socket_fd);\n+\t\t\t\t\tclose(conn_sock);\n+\n+\t\t\t\t\t/* let the magic happen! */\n+\t\t\t\t\tvoid *h = dlopen(path, RTLD_NOW | RTLD_GLOBAL);\n+\t\t\t\t\tif (!h) {\n+\t\t\t\t\t\tRTE_LOG(ERR, EAL, \"Couldn't dlopen: %s\\n\", dlerror());\n+\t\t\t\t\t\texit(1);\n+\t\t\t\t\t}\n+\t\t\t\t\tdlerror();\n+\t\t\t\t\t*(void **) (&exported) = dlsym(h, \"main\");\n+\n+\t\t\t\t\tchar *err = dlerror();\n+\t\t\t\t\tif (err) {\n+\t\t\t\t\t\tRTE_LOG(ERR, EAL, \"Couldn't dlsym: %s\\n\", err);\n+\t\t\t\t\t\texit(1);\n+\t\t\t\t\t}\n+\t\t\t\t\t/* prepare to run EAL second time */\n+\t\t\t\t\tinternal_config.process_type = RTE_PROC_SECONDARY;\n+\t\t\t\t\trte_eal_get_configuration()->process_type = RTE_PROC_SECONDARY;\n+\n+\t\t\t\t\t(*exported)(argc, argv);\n+\n+\t\t\t\t\tdlclose(h);\n+\t\t\t\t} else {\n+\t\t\t\t\tchar thread_name[RTE_MAX_THREAD_NAME_LEN];\n+\n+\t\t\t\t\t/* clean up after ourselves */\n+\t\t\t\t\tclose(sp_stdin);\n+\t\t\t\t\tclose(sp_stdout);\n+\t\t\t\t\tclose(sp_stderr);\n+\t\t\t\t\tclose(sp_log);\n+\t\t\t\t\tfor (int i = 0; i < argc; i++) {\n+\t\t\t\t\t\tfree(argv[i]);\n+\t\t\t\t\t}\n+\n+\t\t\t\t\tpthread_t thread;\n+\t\t\t\t\t/* run a new thread waiting for child's termination */\n+\n+\t\t\t\t\t/* TODO: store id somewhere, as this is dangerous */\n+\t\t\t\t\tret = pthread_create(&thread, NULL,\n+\t\t\t\t\t        secondary_wait_thread, &id);\n+\t\t\t\t\tif (ret) {\n+\t\t\t\t\t\tRTE_LOG(ERR, EAL,\n+\t\t\t\t\t\t    \"Failed to create thread for communication with secondary processes!\\n\");\n+\t\t\t\t\t}\n+\n+\t\t\t\t\t/* Set thread_name for aid in debugging. */\n+\t\t\t\t\tsnprintf(thread_name, RTE_MAX_THREAD_NAME_LEN, \"secondary_%u\", id);\n+\t\t\t\t\tRTE_LOG(DEBUG, EAL, \"Attempting to create thread %s\\n\", thread_name);\n+\t\t\t\t\tret = rte_thread_setname(thread, thread_name);\n+\t\t\t\t\tif (ret)\n+\t\t\t\t\t\tRTE_LOG(DEBUG, EAL,\n+\t\t\t\t\t\t    \"Failed to set thread name for secondary processes!\\n\");\n+\n+\t\t\t\t}\n+\t\t\t\tbreak;\n+\t\t\tdefault:\n+\t\t\t\teal_mp_sync_send_request(conn_sock, SOCKET_ERR);\n+\t\t\t\tdone = true;\n+\t\t\t\tbreak;\n+\t\t\t}\n+\t\t}\n+\t\t/* forked process probably closed this already but we don't care */\n+\t\tclose(conn_sock);\n+\t\tif (is_fork) {\n+\t\t\t/* fork executable doesn't need to listen on socket */\n+\t\t\treturn;\n+\t\t}\n+\t}\n+}\n+\n+/*\n+ * set up a local socket and tell it to listen for incoming connections\n+ */\n+int\n+eal_secondary_mp_sync_setup(void)\n+{\n+\t/* pre-fork instead of creating a listening thread */\n+\tpid_t id = fork();\n+\tif (id < 0) {\n+\t\tRTE_LOG(ERR, EAL, \"Failed to fork!\\n\");\n+\t\treturn -1;\n+\t} else if (id == 0) {\n+\t\t/* child process */\n+\n+\t\tif (prctl(PR_SET_PDEATHSIG, SIGUSR1, 0, 0, 0, 0) != 0)\n+\t\t\tRTE_LOG(ERR, EAL, \"Can't register parent exit handler\\n\");\n+\t\telse {\n+\t\t\tstruct sigaction act;\n+\t\t\tmemset(&act, 0 , sizeof(act));\n+\t\t\tact.sa_handler = parent_exit;\n+\t\t\tif (sigaction(SIGUSR1, &act, NULL) != 0)\n+\t\t\t\tRTE_LOG(ERR, EAL, \"Can't register parent exit signal callback\\n\");\n+\t\t}\n+\n+\t\tsecondary_mp_sync_listener();\n+\t\trte_exit(EXIT_SUCCESS, \"Secondary process finished\\n\");\n+\t} else {\n+\t\t/* what if socket setup fails? do we care? */\n+\t\tRTE_LOG(INFO, EAL, \"Fork successful\\n\");\n+\t}\n+\n+\treturn 0;\n+}\ndiff --git a/lib/librte_eal/linuxapp/eal/eal_mp_secondary.c b/lib/librte_eal/linuxapp/eal/eal_mp_secondary.c\nnew file mode 100755\nindex 0000000..5ebfbc9\n--- /dev/null\n+++ b/lib/librte_eal/linuxapp/eal/eal_mp_secondary.c\n@@ -0,0 +1,301 @@\n+/*-\n+ *   BSD LICENSE\n+ *\n+ *   Copyright(c) 2010-2017 Intel Corporation. All rights reserved.\n+ *   All rights reserved.\n+ *\n+ *   Redistribution and use in source and binary forms, with or without\n+ *   modification, are permitted provided that the following conditions\n+ *   are met:\n+ *\n+ *     * Redistributions of source code must retain the above copyright\n+ *       notice, this list of conditions and the following disclaimer.\n+ *     * Redistributions in binary form must reproduce the above copyright\n+ *       notice, this list of conditions and the following disclaimer in\n+ *       the documentation and/or other materials provided with the\n+ *       distribution.\n+ *     * Neither the name of Intel Corporation nor the names of its\n+ *       contributors may be used to endorse or promote products derived\n+ *       from this software without specific prior written permission.\n+ *\n+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n+ *   \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n+ */\n+\n+#include <string.h>\n+#include <fcntl.h>\n+#include <sys/socket.h>\n+#include <pthread.h>\n+#include <stdlib.h>\n+#include <signal.h>\n+#include <dlfcn.h>\n+#include <unistd.h>\n+#include <stdbool.h>\n+#include <time.h>\n+#include <sys/file.h>\n+#include <linux/version.h>\n+\n+/* sys/un.h with __USE_MISC uses strlen, which is unsafe */\n+#ifdef __USE_MISC\n+#define REMOVED_USE_MISC\n+#undef __USE_MISC\n+#endif\n+#include <sys/un.h>\n+/* make sure we redefine __USE_MISC only if it was previously undefined */\n+#ifdef REMOVED_USE_MISC\n+#define __USE_MISC\n+#undef REMOVED_USE_MISC\n+#endif\n+\n+#include <rte_log.h>\n+#include <rte_pci.h>\n+#include <rte_eal_memconfig.h>\n+#include <rte_malloc.h>\n+#include <rte_common.h>\n+\n+#include \"eal_filesystem.h\"\n+#include \"eal_pci_init.h\"\n+#include \"eal_thread.h\"\n+#include \"eal_mp.h\"\n+\n+#define EXPORT __attribute__((visibility(\"default\")))\n+\n+#define SELF_PATH \"/proc/self/exe\"\n+\n+enum fd_type {\n+\tSTDIN,\n+\tSTDOUT,\n+\tSTDERR,\n+\tLOGFILE\n+};\n+\n+/* connect socket_fd in secondary process to the primary process's socket */\n+static\n+int connect_to_primary(void)\n+{\n+\tstruct sockaddr_un addr;\n+\tsocklen_t sockaddr_len;\n+\tint socket_fd;\n+\n+\t/* set up a socket */\n+\tsocket_fd = socket(AF_UNIX, SOCK_SEQPACKET, 0);\n+\tif (socket_fd < 0) {\n+\t\tRTE_LOG(INFO, EAL, \"Failed to create socket!\\n\");\n+\t\treturn -1;\n+\t}\n+\n+\teal_secondary_mp_sync_get_socket_path(addr.sun_path, sizeof(addr.sun_path));\n+\taddr.sun_family = AF_UNIX;\n+\n+\tsockaddr_len = sizeof(struct sockaddr_un);\n+\n+\tif (connect(socket_fd, (struct sockaddr *) &addr, sockaddr_len) == 0)\n+\t\treturn socket_fd;\n+\n+\t/* if connect failed */\n+\tclose(socket_fd);\n+\treturn -1;\n+}\n+\n+static int\n+sendpath(int socket) {\n+\tchar path[PATH_MAX] = \"\";\n+\tint len = readlink(SELF_PATH, path, PATH_MAX - 1) + 1;\n+\tif (len < 0) {\n+\t\tRTE_LOG(INFO, EAL, \"Failed to get current path\\n\");\n+\t\treturn -1;\n+\t}\n+\tif (eal_mp_sync_send_request(socket, SOCKET_REQ_PATH)) {\n+\t\tRTE_LOG(INFO, EAL, \"Couldn't send path request\\n\");\n+\t\treturn -1;\n+\t}\n+\tif (eal_mp_sync_receive_request(socket) != SOCKET_OK) {\n+\t\tRTE_LOG(INFO, EAL, \"Didn't get path ack\\n\");\n+\t\treturn -1;\n+\t}\n+\tif (eal_mp_sync_send_data(socket, path, len)) {\n+\t\tRTE_LOG(INFO, EAL, \"Couldn't send path\\n\");\n+\t\treturn -1;\n+\t}\n+\tif (eal_mp_sync_receive_request(socket) != SOCKET_OK) {\n+\t\tRTE_LOG(INFO, EAL, \"Didn't get path ack\\n\");\n+\t\treturn -1;\n+\t}\n+\treturn 0;\n+}\n+\n+static int\n+sendargs(int socket, int argc, char **argv) {\n+\tif (argc == 0) {\n+\t\t/* no arguments to be sent */\n+\t\treturn 0;\n+\t}\n+\tif (eal_mp_sync_send_request(socket, SOCKET_REQ_ARGC)) {\n+\t\tRTE_LOG(INFO, EAL, \"Couldn't send argc request\\n\");\n+\t\treturn -1;\n+\t}\n+\tif (eal_mp_sync_receive_request(socket) != SOCKET_OK) {\n+\t\tRTE_LOG(INFO, EAL, \"Didn't get argc ack\\n\");\n+\t\treturn -1;\n+\t}\n+\tif (eal_mp_sync_send_data(socket, &argc, sizeof(argc))) {\n+\t\tRTE_LOG(INFO, EAL, \"Couldn't send argc\\n\");\n+\t\treturn -1;\n+\t}\n+\tif (eal_mp_sync_receive_request(socket) != SOCKET_OK) {\n+\t\tRTE_LOG(INFO, EAL, \"Didn't get argc ack\\n\");\n+\t\treturn -1;\n+\t}\n+\n+\tfor (int i = 0; i < argc; i++) {\n+\t\tchar *str = argv[i];\n+\t\tint len = strlen(str) + 1;\n+\n+\t\tif (eal_mp_sync_send_request(socket, SOCKET_REQ_ARGV)) {\n+\t\t\tRTE_LOG(INFO, EAL, \"Couldn't send argv request\\n\");\n+\t\t\treturn -1;\n+\t\t}\n+\t\tif (eal_mp_sync_receive_request(socket) != SOCKET_OK) {\n+\t\t\tRTE_LOG(INFO, EAL, \"Didn't get argc ack\\n\");\n+\t\t\treturn -1;\n+\t\t}\n+\t\tif (eal_mp_sync_send_data(socket, str, len)) {\n+\t\t\tRTE_LOG(INFO, EAL, \"Couldn't send argv\\n\");\n+\t\t\treturn -1;\n+\t\t}\n+\t\tif (eal_mp_sync_receive_request(socket) != SOCKET_OK) {\n+\t\t\tRTE_LOG(INFO, EAL, \"Didn't get argv ack\\n\");\n+\t\t\treturn -1;\n+\t\t}\n+\t}\n+\n+\treturn 0;\n+}\n+\n+static int\n+sendfd(int socket, enum fd_type t) {\n+\tint fd, req;\n+\tswitch (t) {\n+\t\tcase STDIN:\n+\t\t\tfd = STDIN_FILENO;\n+\t\t\treq = SOCKET_REQ_STDIN;\n+\t\t\tbreak;\n+\t\tcase STDOUT:\n+\t\t\tfd = STDOUT_FILENO;\n+\t\t\treq = SOCKET_REQ_STDOUT;\n+\t\t\tbreak;\n+\t\tcase STDERR:\n+\t\t\tfd = STDERR_FILENO;\n+\t\t\treq = SOCKET_REQ_STDERR;\n+\t\t\tbreak;\n+\t\tcase LOGFILE:\n+\t\t\tfd = rte_logs.file == NULL ? STDERR_FILENO : fileno(rte_logs.file);\n+\t\t\treq = SOCKET_REQ_LOGFILE;\n+\t\t\tbreak;\n+\t}\n+\tif (eal_mp_sync_send_request(socket, req)) {\n+\t\tRTE_LOG(INFO, EAL, \"Couldn't send fd request\\n\");\n+\t\treturn -1;\n+\t}\n+\tif (eal_mp_sync_receive_request(socket) != SOCKET_OK) {\n+\t\tRTE_LOG(INFO, EAL, \"Didn't get fd request ack\\n\");\n+\t\treturn -1;\n+\t}\n+\tif (eal_mp_sync_send_fd(socket, fd)) {\n+\t\tRTE_LOG(INFO, EAL, \"Couldn't send fd\\n\");\n+\t\treturn -1;\n+\t}\n+\tif (eal_mp_sync_receive_request(socket) != SOCKET_OK) {\n+\t\tRTE_LOG(INFO, EAL, \"Didn't get fd ack\\n\");\n+\t\treturn -1;\n+\t}\n+\treturn 0;\n+}\n+\n+static int\n+reqfork(int socket, char *str, int sz) {\n+\tif (eal_mp_sync_send_request(socket, SOCKET_REQ_FORK)) {\n+\t\tRTE_LOG(INFO, EAL, \"Couldn't send fork request\\n\");\n+\t\treturn -1;\n+\t}\n+\tif (eal_mp_sync_receive_request(socket) != SOCKET_OK) {\n+\t\tRTE_LOG(INFO, EAL, \"Didn't get fork request ack\\n\");\n+\t\treturn -1;\n+\t}\n+\tif (eal_mp_sync_receive_data(socket, str, sz)) {\n+\t\tRTE_LOG(INFO, EAL, \"Couldn't receive lockfile path\\n\");\n+\t\treturn -1;\n+\t}\n+\treturn 0;\n+}\n+\n+int eal_secondary_init(int argc, char **argv) {\n+\tRTE_LOG(INFO, EAL, \"Secondary process initializing\\n\");\n+\n+\tchar path[4096];\n+\n+\tint sock = connect_to_primary();\n+\n+\tif (sock < 0) {\n+\t\tRTE_LOG(INFO, EAL, \"Couldn't connect to primary\\n\");\n+\t\treturn -1;\n+\t}\n+\tif (sendpath(sock)) {\n+\t\tRTE_LOG(INFO, EAL, \"Sending path failed\\n\");\n+\t\treturn -1;\n+\t}\n+\tif (sendfd(sock, STDIN)) {\n+\t\tRTE_LOG(INFO, EAL, \"Sending stdin failed\\n\");\n+\t\treturn -1;\n+\t}\n+\tif (sendfd(sock, STDOUT)) {\n+\t\tRTE_LOG(INFO, EAL, \"Sending stdout failed\\n\");\n+\t\treturn -1;\n+\t}\n+\tif (sendfd(sock, STDERR)) {\n+\t\tRTE_LOG(INFO, EAL, \"Sending stderr failed\\n\");\n+\t\treturn -1;\n+\t}\n+\tif (sendfd(sock, LOGFILE)) {\n+\t\tRTE_LOG(INFO, EAL, \"Sending logfile failed\\n\");\n+\t\treturn -1;\n+\t}\n+\tif (sendargs(sock, argc, argv)) {\n+\t\tRTE_LOG(INFO, EAL, \"Sending args failed\\n\");\n+\t\treturn -1;\n+\t}\n+\tif (reqfork(sock, path, sizeof(path))) {\n+\t\tRTE_LOG(INFO, EAL, \"Fork failed\\n\");\n+\t\treturn -1;\n+\t}\n+\tclose(sock);\n+\n+\t/* at this point, the file is locked by the primary */\n+\n+\tint fd = open(path, O_RDONLY);\n+\tif (fd < 0) {\n+\t\tRTE_LOG(INFO, EAL, \"open failed for %s: %s\\n\", path, strerror(errno));\n+\t\treturn -1;\n+\t}\n+\n+\t// blocking call - if succeeded, that means secondary is dead\n+\tif (flock(fd, LOCK_EX) < 0) {\n+\t\tRTE_LOG(INFO, EAL, \"Lock failed: %s\\n\", strerror(errno));\n+\t\treturn -1;\n+\t} else {\n+\t\tRTE_LOG(INFO, EAL, \"Secondary process exited\\n\");\n+\t\tclose(fd);\n+\t\tunlink(path);\n+\t}\n+\n+\treturn 0;\n+}\n",
    "prefixes": [
        "dpdk-dev",
        "RFC",
        "2/4"
    ]
}