@@ -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
The Windows EAL build now pulls in the pthreads4w project as an external subproject. The pthreads4w subproject does not currently provide a meson build so the project has been patched with one. Removed the placeholder librte_eal\windows\include\pthread.h and sched.h header files as these are superseded by the pthreads4w implementation. rte_eal_init() in the Windows EAL has been modified to use pthread_create() and pthread_setaffinity_np() to setup the secondary lcores. eal_thread_create() has been removed as it is no longer required. rte_eal_init() in the Windows EAL now calls SetPriorityClass() to set the process class to real-time in a singular location. eal_thread_loop() in the Windows EAL now calls SetThreadPriority() to set the thread priority to real-time when the thread commences execution. This function now uses pthreads functions to test and compare pthread_t handles. Added the source file librte_eal\windows\windows_eal_impl.c. This source file serves as a location for the implementation of auxiliary functionality provided by the Windows EAL that would otherwise be provided by the UNIX runtime. Added the pthreads4w shared library as a dependency to EAL library builds for Windows builds only. The meson install step will install the pthreads4w.dll that is built by the meson external subproject build step. The shared library has been selected for both static and shared library builds to avoid constructior initialisation issues observed when using pthreads4w and static linkage within the DPDK project. Added the subprojects folder to the .gitignore file such that authored content is not ignored and downloaded content is ignored (as that's where meson stores the subprojects when they are cloned). Incremented the minimum meson version number to 0.55.0. This is required to use the subproject folder patch feature. Updated MAINTAINERS to reflect new additions. Signed-off-by: John Alexander <john.alexander@datapath.co.uk> --- .gitignore | 6 + MAINTAINERS | 3 + lib/librte_eal/windows/eal.c | 21 ++- lib/librte_eal/windows/eal_thread.c | 27 +--- lib/librte_eal/windows/eal_windows.h | 10 -- lib/librte_eal/windows/include/pthread.h | 146 ------------------ lib/librte_eal/windows/include/rte_os.h | 15 +- lib/librte_eal/windows/include/sched.h | 92 ----------- lib/librte_eal/windows/meson.build | 1 + lib/librte_eal/windows/windows_eal_impl.c | 53 +++++++ lib/meson.build | 14 +- meson.build | 7 +- .../packagefiles/pthreads4w-meson/VERSION | 1 + .../packagefiles/pthreads4w-meson/meson.build | 49 ++++++ subprojects/pthreads4w-code.wrap | 8 + 15 files changed, 178 insertions(+), 275 deletions(-) delete mode 100644 lib/librte_eal/windows/include/pthread.h delete mode 100644 lib/librte_eal/windows/include/sched.h create mode 100644 lib/librte_eal/windows/windows_eal_impl.c create mode 100644 subprojects/packagefiles/pthreads4w-meson/VERSION create mode 100644 subprojects/packagefiles/pthreads4w-meson/meson.build create mode 100644 subprojects/pthreads4w-code.wrap