From patchwork Tue Mar 26 06:02:36 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Anand Rawat X-Patchwork-Id: 51684 X-Patchwork-Delegate: thomas@monjalon.net Return-Path: X-Original-To: patchwork@dpdk.org Delivered-To: patchwork@dpdk.org Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id 01E964C93; Tue, 26 Mar 2019 07:02:59 +0100 (CET) Received: from mga12.intel.com (mga12.intel.com [192.55.52.136]) by dpdk.org (Postfix) with ESMTP id 6F8E35A for ; Tue, 26 Mar 2019 07:02:42 +0100 (CET) X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from orsmga007.jf.intel.com ([10.7.209.58]) by fmsmga106.fm.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 25 Mar 2019 23:02:40 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.60,271,1549958400"; d="scan'208";a="125884628" Received: from anandraw-devbx.amr.corp.intel.com ([10.19.242.57]) by orsmga007.jf.intel.com with ESMTP; 25 Mar 2019 23:02:39 -0700 From: Anand Rawat To: dev@dpdk.org Cc: anand.rawat@intel.com, pallavi.kadam@intel.com, ranjit.menon@intel.com, jeffrey.b.shaw@intel.com, bruce.richardson@intel.com, thomas@monjalon.net Date: Mon, 25 Mar 2019 23:02:36 -0700 Message-Id: <20190326060238.9884-7-anand.rawat@intel.com> X-Mailer: git-send-email 2.17.1.windows.2 In-Reply-To: <20190326060238.9884-1-anand.rawat@intel.com> References: <20190306041634.12976-1-anand.rawat@intel.com> <20190326060238.9884-1-anand.rawat@intel.com> Subject: [dpdk-dev] [PATCH v5 6/8] eal: add minimum viable code for eal on windows X-BeenThere: dev@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: DPDK patches and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dev-bounces@dpdk.org Sender: "dev" Add windows specific logic for eal.c, eal_lcore.c, eal_debug.c and eal_thread.c. Updated header files to contain suitable function declaractions. Signed-off-by: Anand Rawat Signed-off-by: Pallavi Kadam Reviewed-by: Jeff Shaw Reviewed-by: Ranjit Menon Signed-off-by: Anand Rawat Signed-off-by: Pallavi Kadam Reviewed-by: Jeff Shaw Reviewed-by: Ranjit Menon Acked-by: Harini Ramakrishnan --- lib/librte_eal/windows/eal/eal.c | 76 ++++++++- lib/librte_eal/windows/eal/eal_debug.c | 14 +- lib/librte_eal/windows/eal/eal_lcore.c | 104 ++++++++++--- lib/librte_eal/windows/eal/eal_thread.c | 147 +++++++++++++++++- lib/librte_eal/windows/eal/include/regex.h | 2 + .../windows/eal/include/rte_windows.h | 20 +++ 6 files changed, 331 insertions(+), 32 deletions(-) diff --git a/lib/librte_eal/windows/eal/eal.c b/lib/librte_eal/windows/eal/eal.c index 13e41ea30..ce460481f 100644 --- a/lib/librte_eal/windows/eal/eal.c +++ b/lib/librte_eal/windows/eal/eal.c @@ -2,13 +2,83 @@ * Copyright(c) 2019 Intel Corporation */ -#include "rte_common.h" +#include +#include +#include +#include +#include +#include +#include +#include + +/* Address of global and public configuration */ +static struct rte_config rte_config; + +/* internal configuration (per-core) */ +struct lcore_config lcore_config[RTE_MAX_LCORE]; + +/* Return a pointer to the configuration structure */ +struct rte_config * +rte_eal_get_configuration(void) +{ + return &rte_config; +} + +static int +sync_func(void *arg __rte_unused) +{ + return 0; +} + +static void +rte_eal_init_alert(const char *msg) +{ + fprintf(stderr, "EAL: FATAL: %s\n", msg); + RTE_LOG(ERR, EAL, "%s\n", msg); +} /* Launch threads, called at application init(). */ int rte_eal_init(int argc __rte_unused, char **argv __rte_unused) { - /* TODO */ - /* This is a stub, not the expected result */ + int i; + + /* create a map of all processors in the system */ + eal_create_cpu_map(); + + if (rte_eal_cpu_init() < 0) { + rte_eal_init_alert("Cannot detect lcores."); + rte_errno = ENOTSUP; + return -1; + } + + eal_thread_init_master(rte_config.master_lcore); + + RTE_LCORE_FOREACH_SLAVE(i) { + + /* + * create communication pipes between master thread + * and children + */ + if (_pipe(lcore_config[i].pipe_master2slave, + sizeof(char), _O_BINARY) < 0) + rte_panic("Cannot create pipe\n"); + if (_pipe(lcore_config[i].pipe_slave2master, + sizeof(char), _O_BINARY) < 0) + rte_panic("Cannot create pipe\n"); + + lcore_config[i].state = WAIT; + + /* create a thread for each lcore */ + if (eal_thread_create(&lcore_config[i].thread_id) != 0) + rte_panic("Cannot create thread\n"); + } + + /* + * Launch a dummy function on all slave lcores, so that master lcore + * knows they are all ready when this function returns. + */ + rte_eal_mp_remote_launch(sync_func, NULL, SKIP_MASTER); + rte_eal_mp_wait_lcore(); return 0; } diff --git a/lib/librte_eal/windows/eal/eal_debug.c b/lib/librte_eal/windows/eal/eal_debug.c index 6e07fe10c..edcf257cc 100644 --- a/lib/librte_eal/windows/eal/eal_debug.c +++ b/lib/librte_eal/windows/eal/eal_debug.c @@ -2,14 +2,18 @@ * Copyright(c) 2019 Intel Corporation */ -#include "rte_common.h" +#include +#include /* call abort(), it will generate a coredump if enabled */ void -__rte_panic(const char *funcname __rte_unused, - const char *format __rte_unused, ...) +__rte_panic(const char *funcname, const char *format, ...) { - /* TODO */ - /* This is a stub, not the expected result */ + va_list ap; + + rte_log(RTE_LOG_CRIT, RTE_LOGTYPE_EAL, "PANIC in %s():\n", funcname); + va_start(ap, format); + rte_vlog(RTE_LOG_CRIT, RTE_LOGTYPE_EAL, format, ap); + va_end(ap); abort(); } diff --git a/lib/librte_eal/windows/eal/eal_lcore.c b/lib/librte_eal/windows/eal/eal_lcore.c index 4ddf51aa8..d39f348a3 100644 --- a/lib/librte_eal/windows/eal/eal_lcore.c +++ b/lib/librte_eal/windows/eal/eal_lcore.c @@ -2,31 +2,99 @@ * Copyright(c) 2019 Intel Corporation */ -#include "rte_common.h" +#include - /* Get the cpu core id value */ -unsigned int -eal_cpu_core_id(unsigned int lcore_id) +#include + +/* global data structure that contains the CPU map */ +static struct _wcpu_map { + unsigned int total_procs; + unsigned int proc_sockets; + unsigned int proc_cores; + unsigned int reserved; + struct _win_lcore_map { + uint8_t socket_id; + uint8_t core_id; + } wlcore_map[RTE_MAX_LCORE]; +} wcpu_map = { 0 }; + +/* + * Create a map of all processors and associated cores on the system + */ +void +eal_create_cpu_map() { - /* TODO */ - /* This is a stub, not the expected result */ - return lcore_id; + wcpu_map.total_procs = + GetActiveProcessorCount(ALL_PROCESSOR_GROUPS); + + LOGICAL_PROCESSOR_RELATIONSHIP lprocRel; + DWORD lprocInfoSize = 0; + BOOL ht_enabled = FALSE; + + /* First get the processor package information */ + lprocRel = RelationProcessorPackage; + /* Determine the size of buffer we need (pass NULL) */ + GetLogicalProcessorInformationEx(lprocRel, NULL, &lprocInfoSize); + wcpu_map.proc_sockets = lprocInfoSize / 48; + + lprocInfoSize = 0; + /* Next get the processor core information */ + lprocRel = RelationProcessorCore; + GetLogicalProcessorInformationEx(lprocRel, NULL, &lprocInfoSize); + wcpu_map.proc_cores = lprocInfoSize / 48; + + if (wcpu_map.total_procs > wcpu_map.proc_cores) + ht_enabled = TRUE; + + /* Distribute the socket and core ids appropriately + * across the logical cores. For now, split the cores + * equally across the sockets. + */ + unsigned int lcore = 0; + for (unsigned int socket = 0; socket < + wcpu_map.proc_sockets; ++socket) { + for (unsigned int core = 0; + core < (wcpu_map.proc_cores / wcpu_map.proc_sockets); + ++core) { + wcpu_map.wlcore_map[lcore] + .socket_id = socket; + wcpu_map.wlcore_map[lcore] + .core_id = core; + lcore++; + if (ht_enabled) { + wcpu_map.wlcore_map[lcore] + .socket_id = socket; + wcpu_map.wlcore_map[lcore] + .core_id = core; + lcore++; + } + } + } } -/* Check if a cpu is present by the presence of the cpu information for it */ +/* + * Check if a cpu is present by the presence of the cpu information for it + */ int -eal_cpu_detected(unsigned int lcore_id __rte_unused) +eal_cpu_detected(unsigned int lcore_id) +{ + return (lcore_id < wcpu_map.total_procs); +} + +/* + * Get CPU socket id for a logical core + */ +unsigned +eal_cpu_socket_id(unsigned int lcore_id) { - /* TODO */ - /* This is a stub, not the expected result */ - return 1; + return wcpu_map.wlcore_map[lcore_id].socket_id; } -/* Get CPU socket id (NUMA node) for a logical core */ -unsigned int -eal_cpu_socket_id(unsigned int cpu_id __rte_unused) +/* + * Get CPU socket id (NUMA node) for a logical core + */ +unsigned +eal_cpu_core_id(unsigned int lcore_id) { - /* TODO */ - /* This is a stub, not the expected result */ - return 0; + return wcpu_map.wlcore_map[lcore_id].core_id; } diff --git a/lib/librte_eal/windows/eal/eal_thread.c b/lib/librte_eal/windows/eal/eal_thread.c index e74f8893b..906502f90 100644 --- a/lib/librte_eal/windows/eal/eal_thread.c +++ b/lib/librte_eal/windows/eal/eal_thread.c @@ -2,17 +2,152 @@ * Copyright(c) 2019 Intel Corporation */ -#include +#include -#include "rte_common.h" +#include +#include +#include +#include +#include +#include +#include -typedef uintptr_t eal_thread_t; + +RTE_DEFINE_PER_LCORE(unsigned int, _lcore_id) = LCORE_ID_ANY; + +/* + * Send a message to a slave lcore identified by slave_id to call a + * function f with argument arg. Once the execution is done, the + * remote lcore switch in FINISHED state. + */ +int +rte_eal_remote_launch(lcore_function_t *f, void *arg, unsigned int slave_id) +{ + int n; + char c = 0; + int m2s = lcore_config[slave_id].pipe_master2slave[1]; + int s2m = lcore_config[slave_id].pipe_slave2master[0]; + + if (lcore_config[slave_id].state != WAIT) + return -EBUSY; + + lcore_config[slave_id].f = f; + lcore_config[slave_id].arg = arg; + + /* send message */ + n = 0; + while (n == 0 || (n < 0 && errno == EINTR)) + n = _write(m2s, &c, 1); + if (n < 0) + rte_panic("cannot write on configuration pipe\n"); + + /* wait ack */ + do { + n = _read(s2m, &c, 1); + } while (n < 0 && errno == EINTR); + + if (n <= 0) + rte_panic("cannot read on configuration pipe\n"); + + return 0; +} + +void +eal_thread_init_master(unsigned int lcore_id) +{ + /* set the lcore ID in per-lcore memory area */ + RTE_PER_LCORE(_lcore_id) = lcore_id; +} + +static inline pthread_t +eal_thread_self(void) +{ + return GetCurrentThreadId(); +} + +/* main loop of threads */ +void * +eal_thread_loop(void *arg __rte_unused) +{ + char c; + int n, ret; + unsigned int lcore_id; + pthread_t thread_id; + int m2s, s2m; + char cpuset[RTE_CPU_AFFINITY_STR_LEN]; + + thread_id = eal_thread_self(); + + /* retrieve our lcore_id from the configuration structure */ + RTE_LCORE_FOREACH_SLAVE(lcore_id) { + if (thread_id == lcore_config[lcore_id].thread_id) + break; + } + if (lcore_id == RTE_MAX_LCORE) + rte_panic("cannot retrieve lcore id\n"); + + m2s = lcore_config[lcore_id].pipe_master2slave[0]; + s2m = lcore_config[lcore_id].pipe_slave2master[1]; + + /* set the lcore ID in per-lcore memory area */ + RTE_PER_LCORE(_lcore_id) = lcore_id; + + RTE_LOG(DEBUG, EAL, "lcore %u is ready (tid=%zx;cpuset=[%s])\n", + lcore_id, (uintptr_t)thread_id, cpuset); + + /* read on our pipe to get commands */ + while (1) { + void *fct_arg; + + /* wait command */ + do { + n = _read(m2s, &c, 1); + } while (n < 0 && errno == EINTR); + + if (n <= 0) + rte_panic("cannot read on configuration pipe\n"); + + lcore_config[lcore_id].state = RUNNING; + + /* send ack */ + n = 0; + while (n == 0 || (n < 0 && errno == EINTR)) + n = _write(s2m, &c, 1); + if (n < 0) + rte_panic("cannot write on configuration pipe\n"); + + if (lcore_config[lcore_id].f == NULL) + rte_panic("NULL function pointer\n"); + + /* call the function and store the return value */ + fct_arg = lcore_config[lcore_id].arg; + ret = lcore_config[lcore_id].f(fct_arg); + lcore_config[lcore_id].ret = ret; + rte_wmb(); + + /* when a service core returns, it should go directly to WAIT + * state, because the application will not lcore_wait() for it. + */ + if (lcore_config[lcore_id].core_role == ROLE_SERVICE) + lcore_config[lcore_id].state = WAIT; + else + lcore_config[lcore_id].state = FINISHED; + } +} /* function to create threads */ int -eal_thread_create(eal_thread_t *thread __rte_unused) +eal_thread_create(pthread_t *thread) { - /* TODO */ - /* This is a stub, not the expected result */ + HANDLE th; + + th = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)eal_thread_loop, + NULL, 0, (LPDWORD)thread); + if (!th) + return -1; + + SetPriorityClass(GetCurrentProcess(), REALTIME_PRIORITY_CLASS); + SetThreadPriority(th, THREAD_PRIORITY_TIME_CRITICAL); + return 0; } diff --git a/lib/librte_eal/windows/eal/include/regex.h b/lib/librte_eal/windows/eal/include/regex.h index daa102f74..412b4edc5 100644 --- a/lib/librte_eal/windows/eal/include/regex.h +++ b/lib/librte_eal/windows/eal/include/regex.h @@ -12,6 +12,8 @@ extern "C" { #define REG_NOMATCH 1 #define REG_ESPACE 12 +#include + /* defining regex_t for windows */ typedef void *regex_t; /* defining regmatch_t for windows */ diff --git a/lib/librte_eal/windows/eal/include/rte_windows.h b/lib/librte_eal/windows/eal/include/rte_windows.h index af24ef39f..46146e59b 100644 --- a/lib/librte_eal/windows/eal/include/rte_windows.h +++ b/lib/librte_eal/windows/eal/include/rte_windows.h @@ -9,7 +9,9 @@ extern "C" { #endif +#include #include +#include /* macro substitution for windows supported strerror_r */ #define strerror_r(a, b, c) strerror_s(b, c, a) @@ -23,6 +25,24 @@ typedef SSIZE_T ssize_t; /* macro substitution for windows supported strtok_r */ #define strtok_r(str, delim, saveptr) strtok_s(str, delim, saveptr) +/** + * Create a thread. + * This function is private to EAL. + * + * @param thread + * The location to store the thread id if successful. + * @return + * 0 for success, -1 if the thread is not created. + */ +int eal_thread_create(pthread_t *thread); + +/** + * Create a map of processors and cores on the system. + * This function is private to EAL. + * + */ +void eal_create_cpu_map(void); + #ifdef __cplusplus } #endif