@@ -33,3 +33,9 @@ build-*
# ignore other build directory patterns
*-gcc*
*-clang*
+
+# ignore sub-directories of the subprojects directory excluding wrap files and the packagefiles directory
+subprojects/**/*
+!subprojects/*.wrap
+!subprojects/packagefiles/
+!subprojects/packagefiles/**
@@ -318,10 +318,13 @@ M: Dmitry Kozlyuk <dmitry.kozliuk@gmail.com>
M: Narcisa Ana Maria Vasile <navasile@linux.microsoft.com>
M: Dmitry Malloy <dmitrym@microsoft.com>
M: Pallavi Kadam <pallavi.kadam@intel.com>
+M: John Alexander <john.alexander@datapath.co.uk>
F: lib/librte_eal/windows/
+F: lib/librte_eal/windows/windows_eal_impl.c
F: lib/librte_eal/rte_eal_exports.def
F: buildtools/map_to_win.py
F: doc/guides/windows_gsg/
+F: subprojects/
Windows memory allocation
M: Dmitry Kozlyuk <dmitry.kozliuk@gmail.com>
@@ -260,7 +260,7 @@ rte_eal_cleanup(void)
int
rte_eal_init(int argc, char **argv)
{
- int i, fctret, bscan;
+ int i, fctret, bscan, ret;
const struct rte_config *config = rte_eal_get_configuration();
struct internal_config *internal_conf =
eal_get_internal_configuration();
@@ -360,6 +360,15 @@ rte_eal_init(int argc, char **argv)
return -1;
}
+ /*
+ * We require real-time priority threads. To achieve this on Windows we must
+ * set the current process class to real-time. Setting the process class to
+ * real-time requires elevated privileges (admin user) otherwise the maximum
+ * achievable thread priority will still only be 15 (out of 31) even with
+ * real-time thread priority and real-time process class set.
+ */
+ SetPriorityClass(GetCurrentProcess(), REALTIME_PRIORITY_CLASS);
+
RTE_LCORE_FOREACH_SLAVE(i) {
/*
@@ -376,8 +385,16 @@ rte_eal_init(int argc, char **argv)
lcore_config[i].state = WAIT;
/* create a thread for each lcore */
- if (eal_thread_create(&lcore_config[i].thread_id) != 0)
+ /* create a thread for each lcore */
+ ret = pthread_create(&lcore_config[i].thread_id, NULL,
+ eal_thread_loop, NULL);
+ if (ret != 0)
rte_panic("Cannot create thread\n");
+
+ ret = pthread_setaffinity_np(lcore_config[i].thread_id,
+ sizeof(rte_cpuset_t), &lcore_config[i].cpuset);
+ if (ret != 0)
+ rte_panic("Cannot set affinity\n");
}
/* Initialize services so drivers can register services during probe. */
@@ -3,6 +3,7 @@
*/
#include <io.h>
+#include <pthread.h>
#include <rte_atomic.h>
#include <rte_debug.h>
@@ -66,9 +67,11 @@ eal_thread_loop(void *arg __rte_unused)
thread_id = pthread_self();
+ SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL);
+
/* retrieve our lcore_id from the configuration structure */
RTE_LCORE_FOREACH_SLAVE(lcore_id) {
- if (thread_id == lcore_config[lcore_id].thread_id)
+ if (pthread_equal(thread_id, lcore_config[lcore_id].thread_id))
break;
}
if (lcore_id == RTE_MAX_LCORE)
@@ -79,8 +82,8 @@ eal_thread_loop(void *arg __rte_unused)
__rte_thread_init(lcore_id, &lcore_config[lcore_id].cpuset);
- RTE_LOG(DEBUG, EAL, "lcore %u is ready (tid=%zx;cpuset=[%s])\n",
- lcore_id, (uintptr_t)thread_id, cpuset);
+ RTE_LOG(DEBUG, EAL, "lcore %u is ready (tid=%p;cpuset=[%s])\n",
+ lcore_id, thread_id, cpuset);
/* read on our pipe to get commands */
while (1) {
@@ -122,24 +125,6 @@ eal_thread_loop(void *arg __rte_unused)
}
}
-/* function to create threads */
-int
-eal_thread_create(pthread_t *thread)
-{
- HANDLE th;
-
- th = CreateThread(NULL, 0,
- (LPTHREAD_START_ROUTINE)(ULONG_PTR)eal_thread_loop,
- NULL, 0, (LPDWORD)thread);
- if (!th)
- return -1;
-
- SetPriorityClass(GetCurrentProcess(), REALTIME_PRIORITY_CLASS);
- SetThreadPriority(th, THREAD_PRIORITY_TIME_CRITICAL);
-
- return 0;
-}
-
/* get current thread ID */
int
rte_sys_gettid(void)
@@ -35,16 +35,6 @@
*/
int eal_create_cpu_map(void);
-/**
- * Create a thread.
- *
- * @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);
-
/**
* Get system NUMA node number for a socket ID.
*
deleted file mode 100644
@@ -1,146 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2019 Intel Corporation
- */
-
-#ifndef _PTHREAD_H_
-#define _PTHREAD_H_
-
-#include <stdint.h>
-#include <sched.h>
-
-/**
- * This file is required to support the common code in eal_common_proc.c,
- * eal_common_thread.c and common\include\rte_per_lcore.h as Microsoft libc
- * does not contain pthread.h. This may be removed in future releases.
- */
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#include <rte_common.h>
-#include <rte_windows.h>
-
-#define PTHREAD_BARRIER_SERIAL_THREAD TRUE
-
-/* defining pthread_t type on Windows since there is no in Microsoft libc*/
-typedef uintptr_t pthread_t;
-
-/* defining pthread_attr_t type on Windows since there is no in Microsoft libc*/
-typedef void *pthread_attr_t;
-
-typedef SYNCHRONIZATION_BARRIER pthread_barrier_t;
-
-#define pthread_barrier_init(barrier, attr, count) \
- InitializeSynchronizationBarrier(barrier, count, -1)
-#define pthread_barrier_wait(barrier) EnterSynchronizationBarrier(barrier, \
- SYNCHRONIZATION_BARRIER_FLAGS_BLOCK_ONLY)
-#define pthread_barrier_destroy(barrier) \
- DeleteSynchronizationBarrier(barrier)
-#define pthread_cancel(thread) TerminateThread((HANDLE) thread, 0)
-
-/* pthread function overrides */
-#define pthread_self() \
- ((pthread_t)GetCurrentThreadId())
-
-static inline int
-pthread_setaffinity_np(pthread_t threadid, size_t cpuset_size,
- rte_cpuset_t *cpuset)
-{
- DWORD_PTR ret = 0;
- HANDLE thread_handle;
-
- if (cpuset == NULL || cpuset_size == 0)
- return -1;
-
- thread_handle = OpenThread(THREAD_ALL_ACCESS, FALSE, threadid);
- if (thread_handle == NULL) {
- RTE_LOG_WIN32_ERR("OpenThread()");
- return -1;
- }
-
- ret = SetThreadAffinityMask(thread_handle, *cpuset->_bits);
- if (ret == 0) {
- RTE_LOG_WIN32_ERR("SetThreadAffinityMask()");
- goto close_handle;
- }
-
-close_handle:
- if (CloseHandle(thread_handle) == 0) {
- RTE_LOG_WIN32_ERR("CloseHandle()");
- return -1;
- }
- return (ret == 0) ? -1 : 0;
-}
-
-static inline int
-pthread_getaffinity_np(pthread_t threadid, size_t cpuset_size,
- rte_cpuset_t *cpuset)
-{
- /* Workaround for the lack of a GetThreadAffinityMask()
- *API in Windows
- */
- DWORD_PTR prev_affinity_mask;
- HANDLE thread_handle;
- DWORD_PTR ret = 0;
-
- if (cpuset == NULL || cpuset_size == 0)
- return -1;
-
- thread_handle = OpenThread(THREAD_ALL_ACCESS, FALSE, threadid);
- if (thread_handle == NULL) {
- RTE_LOG_WIN32_ERR("OpenThread()");
- return -1;
- }
-
- /* obtain previous mask by setting dummy mask */
- prev_affinity_mask = SetThreadAffinityMask(thread_handle, 0x1);
- if (prev_affinity_mask == 0) {
- RTE_LOG_WIN32_ERR("SetThreadAffinityMask()");
- goto close_handle;
- }
-
- /* set it back! */
- ret = SetThreadAffinityMask(thread_handle, prev_affinity_mask);
- if (ret == 0) {
- RTE_LOG_WIN32_ERR("SetThreadAffinityMask()");
- goto close_handle;
- }
-
- memset(cpuset, 0, cpuset_size);
- *cpuset->_bits = prev_affinity_mask;
-
-close_handle:
- if (CloseHandle(thread_handle) == 0) {
- RTE_LOG_WIN32_ERR("SetThreadAffinityMask()");
- return -1;
- }
- return (ret == 0) ? -1 : 0;
-}
-
-static inline int
-pthread_create(void *threadid, const void *threadattr, void *threadfunc,
- void *args)
-{
- RTE_SET_USED(threadattr);
- HANDLE hThread;
- hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)threadfunc,
- args, 0, (LPDWORD)threadid);
- if (hThread) {
- SetPriorityClass(GetCurrentProcess(), REALTIME_PRIORITY_CLASS);
- SetThreadPriority(hThread, THREAD_PRIORITY_TIME_CRITICAL);
- }
- return ((hThread != NULL) ? 0 : E_FAIL);
-}
-
-static inline int
-pthread_join(__rte_unused pthread_t thread,
- __rte_unused void **value_ptr)
-{
- return 0;
-}
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* _PTHREAD_H_ */
@@ -15,6 +15,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <sched.h>
#ifdef __cplusplus
extern "C" {
@@ -43,10 +44,22 @@ extern "C" {
#define unlink _unlink
/* cpu_set macros implementation */
+typedef cpu_set_t rte_cpuset_t;
#define RTE_CPU_AND(dst, src1, src2) CPU_AND(dst, src1, src2)
#define RTE_CPU_OR(dst, src1, src2) CPU_OR(dst, src1, src2)
#define RTE_CPU_FILL(set) CPU_FILL(set)
-#define RTE_CPU_NOT(dst, src) CPU_NOT(dst, src)
+void RTE_CPU_ANDNOT(cpu_set_t *dst, cpu_set_t *src);
+void RTE_CPU_COPY(cpu_set_t *from, cpu_set_t *to);
+void RTE_CPU_FILL(cpu_set_t *pdestset);
+#define RTE_CPU_NOT(dst, src) do \
+{ \
+ cpu_set_t tmp; \
+ RTE_CPU_FILL(&tmp); \
+ RTE_CPU_ANDNOT(&tmp, src); \
+ RTE_CPU_COPY(&tmp, dst); \
+} while (0)
+
+
/* as in <windows.h> */
typedef long long ssize_t;
deleted file mode 100644
@@ -1,92 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2019 Intel Corporation
- */
-
-#ifndef _SCHED_H_
-#define _SCHED_H_
-
-/**
- * This file is added to support the common code in eal_common_thread.c
- * as Microsoft libc does not contain sched.h. This may be removed
- * in future releases.
- */
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#ifndef CPU_SETSIZE
-#define CPU_SETSIZE RTE_MAX_LCORE
-#endif
-
-#define _BITS_PER_SET (sizeof(long long) * 8)
-#define _BIT_SET_MASK (_BITS_PER_SET - 1)
-
-#define _NUM_SETS(b) (((b) + _BIT_SET_MASK) / _BITS_PER_SET)
-#define _WHICH_SET(b) ((b) / _BITS_PER_SET)
-#define _WHICH_BIT(b) ((b) & (_BITS_PER_SET - 1))
-
-typedef struct _rte_cpuset_s {
- long long _bits[_NUM_SETS(CPU_SETSIZE)];
-} rte_cpuset_t;
-
-#define CPU_SET(b, s) ((s)->_bits[_WHICH_SET(b)] |= (1LL << _WHICH_BIT(b)))
-
-#define CPU_ZERO(s) \
- do { \
- unsigned int _i; \
- \
- for (_i = 0; _i < _NUM_SETS(CPU_SETSIZE); _i++) \
- (s)->_bits[_i] = 0LL; \
- } while (0)
-
-#define CPU_ISSET(b, s) (((s)->_bits[_WHICH_SET(b)] & \
- (1LL << _WHICH_BIT(b))) != 0LL)
-
-static inline int
-count_cpu(rte_cpuset_t *s)
-{
- unsigned int _i;
- int count = 0;
-
- for (_i = 0; _i < _NUM_SETS(CPU_SETSIZE); _i++)
- if (CPU_ISSET(_i, s) != 0LL)
- count++;
- return count;
-}
-#define CPU_COUNT(s) count_cpu(s)
-
-#define CPU_AND(dst, src1, src2) \
-do { \
- unsigned int _i; \
- \
- for (_i = 0; _i < _NUM_SETS(CPU_SETSIZE); _i++) \
- (dst)->_bits[_i] = (src1)->_bits[_i] & (src2)->_bits[_i]; \
-} while (0)
-
-#define CPU_OR(dst, src1, src2) \
-do { \
- unsigned int _i; \
- \
- for (_i = 0; _i < _NUM_SETS(CPU_SETSIZE); _i++) \
- (dst)->_bits[_i] = (src1)->_bits[_i] | (src2)->_bits[_i]; \
-} while (0)
-
-#define CPU_FILL(s) \
-do { \
- unsigned int _i; \
- for (_i = 0; _i < _NUM_SETS(CPU_SETSIZE); _i++) \
- (s)->_bits[_i] = -1LL; \
-} while (0)
-
-#define CPU_NOT(dst, src) \
-do { \
- unsigned int _i; \
- for (_i = 0; _i < _NUM_SETS(CPU_SETSIZE); _i++) \
- (dst)->_bits[_i] = (src)->_bits[_i] ^ -1LL; \
-} while (0)
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* _SCHED_H_ */
@@ -18,6 +18,7 @@ sources += files(
'eal_timer.c',
'fnmatch.c',
'getopt.c',
+ 'windows_eal_impl.c'
)
dpdk_conf.set10('RTE_EAL_NUMA_AWARE_HUGEPAGES', true)
new file mode 100644
@@ -0,0 +1,53 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright 2020 Datapath Limited
+ */
+
+#include "eal_windows.h"
+
+pid_t
+getpid()
+{
+ return GetCurrentProcessId();
+}
+
+void
+RTE_CPU_FILL(cpu_set_t *pdestset)
+{
+ SYSTEM_INFO system_info;
+ memset(&system_info, 0, sizeof(system_info));
+
+ GetSystemInfo(&system_info);
+
+ int masked_so_far = 0;
+ int index = 0;
+ do{
+ unsigned char mask = 0xFF;
+
+ if ((masked_so_far + 8) > system_info.dwNumberOfProcessors){
+ int mask_shift = (masked_so_far + 8) - system_info.dwNumberOfProcessors;
+ mask = mask >> mask_shift;
+ }
+
+ pdestset->cpuset[index] = mask;
+
+ masked_so_far += 8;
+ index++;
+ } while (masked_so_far < system_info.dwNumberOfProcessors);
+}
+
+void
+RTE_CPU_ANDNOT(cpu_set_t *dst, cpu_set_t *src)
+{
+ int set_index;
+ for (set_index = 0;
+ set_index < _countof(dst->cpuset);
+ set_index++){
+ dst->cpuset[set_index] = ~(dst->cpuset[set_index] & src->cpuset[set_index]);
+ }
+}
+
+void
+RTE_CPU_COPY(cpu_set_t *from, cpu_set_t *to)
+{
+ memcpy(to, from, sizeof(cpu_set_t));
+}
@@ -43,6 +43,11 @@ if is_windows
'ring',
'mempool', 'mbuf', 'net', 'meter', 'ethdev', 'pci',
] # only supported libraries for windows
+
+ # Windows doesn't natively support pthreads so we pull down an external project
+ # using the meson subproject feature.
+ pthreads4w_proj = subproject('pthreads4w-code')
+ pthreads4w_shared_dep = pthreads4w_proj.get_variable('pthreads4w_shared_dep')
endif
default_cflags = machine_args
@@ -82,6 +87,12 @@ foreach l:libraries
if build
shared_deps = ext_deps
static_deps = ext_deps
+ if is_windows
+ # Initialisation issues with the external pthreads library when linked with
+ # DPDK require us to always use the shared build of the pthreads4w library.
+ shared_deps += pthreads4w_shared_dep
+ static_deps += pthreads4w_shared_dep
+ endif
foreach d:deps
if not is_variable('shared_rte_' + d)
error('Missing internal dependency "@0@" for @1@ [@2@]'
@@ -153,8 +164,7 @@ foreach l:libraries
output: '@0@_mingw.map'.format(libname))
if is_ms_linker
- lk_args = ['-Wl,/def:' + def_file.full_path(),
- '-Wl,/implib:lib\\' + implib]
+ lk_args = ['-Wl,/def:' + def_file.full_path()]
else
if is_windows
lk_args = ['-Wl,--version-script=' + mingw_map.full_path()]
@@ -8,7 +8,7 @@ project('DPDK', 'C',
files('VERSION')).stdout().strip(),
license: 'BSD',
default_options: ['buildtype=release', 'default_library=static'],
- meson_version: '>= 0.47.1'
+ meson_version: '>= 0.55.0'
)
# set up some global vars for compiler, platform, configuration, etc.
@@ -44,6 +44,11 @@ global_inc = include_directories('.', 'config',
subdir('buildtools')
subdir('config')
+if is_windows
+ # Windows builds do not define this but it is required so we define it globally here.
+ add_global_arguments('-D_POSIX_C_SOURCE=200809L', language: 'c')
+endif
+
# build libs and drivers
subdir('buildtools/pmdinfogen')
subdir('lib')
new file mode 100644
@@ -0,0 +1 @@
+3.0.0
new file mode 100644
@@ -0,0 +1,49 @@
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright 2020 Datapath Limited
+
+project('pthreads4w', 'C',
+ # Fallback to "more" for Windows compatibility.
+ version: run_command(find_program('cat', 'more'),
+ files('VERSION')).stdout().strip(),
+ license: 'APACHE2.0',
+ default_options: ['buildtype=release', 'default_library=static'],
+ meson_version: '>= 0.55.0'
+)
+
+sources = files(
+ 'pthread.c'
+)
+
+objs = []
+cflags = ['-DHAVE_CONFIG_H']
+
+# The static library is built differently to ensure the process attach/detach and thread attach/detach operate correctly.
+cflags_static = cflags
+cflags_static += '-D__PTW32_STATIC_LIB'
+pthreads4w_static_lib = static_library('pthreads4w',
+ sources,
+ objects: objs,
+ c_args: cflags_static,
+ install: true)
+
+pthreads4w_shared_lib = shared_library('pthreads4w',
+ sources,
+ objects: objs,
+ c_args: cflags,
+ implib: true,
+ install: true)
+
+pthreads4w_static_dep = declare_dependency(
+ include_directories: '',
+ link_with : pthreads4w_static_lib)
+
+pthreads4w_shared_dep = declare_dependency(
+ include_directories: '',
+ link_with : pthreads4w_shared_lib)
+
+install_headers(
+ 'pthread.h',
+ '_ptw32.h',
+ 'sched.h',
+ 'semaphore.h')
+
new file mode 100644
@@ -0,0 +1,8 @@
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright 2020 Datapath Limited
+
+[wrap-git]
+directory=pthreads4w
+url=git://git.code.sf.net/p/pthreads4w/code
+revision=Version-3-0-0-release
+patch_directory=pthreads4w-meson