Skip to content
Permalink
Browse files

windows: implement runtime detection for Windows 7+

Signed-off-by: kleuter <support@crystalidea.com>
Signed-off-by: Steven Noonan <steven@uplinklabs.net>
  • Loading branch information...
kleuter authored and tycho committed Oct 5, 2018
1 parent dded771 commit 0ce2b1c2095e6473be018fe738ce52263a886df4
Showing with 105 additions and 29 deletions.
  1. +3 −0 main.c
  2. +4 −4 msvc/CPUID.vcxproj
  3. +1 −1 prefix.h
  4. +2 −0 state.h
  5. +64 −24 threads.c
  6. +3 −0 threads.h
  7. +25 −0 util.c
  8. +3 −0 util.h
3 main.c
@@ -304,6 +304,7 @@ int main(int argc, char **argv)
if (file) {
cpuid_load_from_file(file, &state);
state.cpuid_call = cpuid_stub;
state.thread_init = thread_init_stub;
state.thread_bind = thread_bind_stub;
state.thread_count = thread_count_stub;
#ifdef __linux__
@@ -312,6 +313,8 @@ int main(int argc, char **argv)
#endif
}

state.thread_init();

if (cpu_start == -1) {
cpu_start = 0;
cpu_end = state.thread_count(&state) - 1;
@@ -26,24 +26,24 @@
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<PlatformToolset>v120</PlatformToolset>
<PlatformToolset>v120_xp</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
<WholeProgramOptimization>true</WholeProgramOptimization>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<PlatformToolset>v120</PlatformToolset>
<PlatformToolset>v120_xp</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<PlatformToolset>v120</PlatformToolset>
<PlatformToolset>v120_xp</PlatformToolset>
<CharacterSet>NotSet</CharacterSet>
<WholeProgramOptimization>false</WholeProgramOptimization>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<PlatformToolset>v120</PlatformToolset>
<PlatformToolset>v120_xp</PlatformToolset>
<CharacterSet>NotSet</CharacterSet>
<WholeProgramOptimization>false</WholeProgramOptimization>
</PropertyGroup>
@@ -31,7 +31,7 @@
#endif

#ifdef TARGET_OS_WINDOWS
#define _WIN32_WINNT 0x0601
#define _WIN32_WINNT _WIN32_WINNT_WIN7
#endif

#include <assert.h>
@@ -44,6 +44,7 @@ struct cpuid_leaf_t {

struct cpuid_state_t
{
thread_init_handler_t thread_init;
thread_bind_handler_t thread_bind;
thread_count_handler_t thread_count;
cpuid_call_handler_t cpuid_call;
@@ -65,6 +66,7 @@ struct cpuid_state_t
memset((x), 0, sizeof(struct cpuid_state_t)); \
(x)->cpuid_print = cpuid_dump_normal; \
(x)->cpuid_call = cpuid_native; \
(x)->thread_init = thread_init_native; \
(x)->thread_bind = thread_bind_native; \
(x)->thread_count = thread_count_native; \
}
@@ -67,6 +67,39 @@ extern int utilUnbindThreadFromCPU(void);
#endif

#include "state.h"
#include "util.h"

#ifdef TARGET_OS_WINDOWS
#if _WIN32_WINNT < 0x0601
typedef WORD(WINAPI *fnGetActiveProcessorGroupCount)(void);
typedef DWORD(WINAPI *fnGetActiveProcessorCount)(WORD);
typedef BOOL(WINAPI *fnSetThreadGroupAffinity)(HANDLE, const GROUP_AFFINITY *, PGROUP_AFFINITY);

static fnGetActiveProcessorGroupCount GetActiveProcessorGroupCount;
static fnGetActiveProcessorCount GetActiveProcessorCount;
static fnSetThreadGroupAffinity SetThreadGroupAffinity;
#endif
#endif

void thread_init_native(void)
{
#ifdef TARGET_OS_WINDOWS
#if _WIN32_WINNT < 0x0601
HMODULE hKernel32 = GetModuleHandleW(L"kernel32.dll");

#if defined(__GNUC__)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wcast-function-type"
#endif
GetActiveProcessorGroupCount = (fnGetActiveProcessorGroupCount)GetProcAddress(hKernel32, "GetActiveProcessorGroupCount");
GetActiveProcessorCount = (fnGetActiveProcessorCount)GetProcAddress(hKernel32, "GetActiveProcessorCount");
SetThreadGroupAffinity = (fnSetThreadGroupAffinity)GetProcAddress(hKernel32, "SetThreadGroupAffinity");
#if defined(__GNUC__)
#pragma GCC diagnostic pop
#endif
#endif
#endif
}

uint32_t thread_count_native(struct cpuid_state_t *state)
{
@@ -99,6 +132,10 @@ uint32_t thread_count_native(struct cpuid_state_t *state)
#endif
}

void thread_init_stub(void)
{
}

uint32_t thread_count_stub(struct cpuid_state_t *state)
{
assert(state);
@@ -111,38 +148,41 @@ int thread_bind_native(__unused_variable struct cpuid_state_t *state, uint32_t i

BOOL ret = FALSE;
HANDLE hThread = GetCurrentThread();
#if _WIN32_WINNT >= 0x0601
DWORD threadsInGroup = 0;
WORD groupId, groupCount;
GROUP_AFFINITY affinity;

ZeroMemory(&affinity, sizeof(GROUP_AFFINITY));
#if _WIN32_WINNT < 0x0601
if (is_windows7_or_greater()) {
#endif
DWORD threadsInGroup = 0;
WORD groupId, groupCount;
GROUP_AFFINITY affinity;
ZeroMemory(&affinity, sizeof(GROUP_AFFINITY));

groupCount = GetActiveProcessorGroupCount();
groupCount = GetActiveProcessorGroupCount();

for (groupId = 0; groupId < groupCount; groupId++)
{
threadsInGroup = GetActiveProcessorCount(groupId);
if (id < threadsInGroup)
break;
id -= threadsInGroup;
}
for (groupId = 0; groupId < groupCount; groupId++) {
threadsInGroup = GetActiveProcessorCount(groupId);
if (id < threadsInGroup)
break;
id -= threadsInGroup;
}

if (groupId < groupCount && id < threadsInGroup) {
affinity.Group = groupId;
affinity.Mask = 1ULL << id;
if (groupId < groupCount && id < threadsInGroup) {
affinity.Group = groupId;
affinity.Mask = 1ULL << id;

ret = SetThreadGroupAffinity(hThread, &affinity, NULL);
}
#else
DWORD mask;
ret = SetThreadGroupAffinity(hThread, &affinity, NULL);
}
#if _WIN32_WINNT < 0x0601
} else {
DWORD mask;

if (id > 32)
return 1;
if (id > 32)
return 1;

mask = (1 << id);
mask = (1 << id);

ret = SetThreadAffinityMask(hThread, mask);
ret = SetThreadAffinityMask(hThread, mask);
}
#endif

if (state && ret != FALSE)
@@ -24,14 +24,17 @@

struct cpuid_state_t;

typedef void (*thread_init_handler_t)(void);
typedef int (*thread_bind_handler_t)(struct cpuid_state_t *, uint32_t);
typedef uint32_t (*thread_count_handler_t)(struct cpuid_state_t *);

/* These do real thread binding. */
void thread_init_native(void);
int thread_bind_native(struct cpuid_state_t *state, uint32_t id);
uint32_t thread_count_native(struct cpuid_state_t *state);

/* These are used to change the logical selector in the state structure. */
void thread_init_stub(void);
int thread_bind_stub(struct cpuid_state_t *state, uint32_t id);
uint32_t thread_count_stub(struct cpuid_state_t *state);

25 util.c
@@ -118,4 +118,29 @@ double time_sec(void)
#endif
}

#ifdef TARGET_OS_WINDOWS
int is_windows7_or_greater(void)
{
static int cached = -1;
if (cached < 0) {
OSVERSIONINFOEXW osvi;
DWORDLONG const dwlConditionMask = VerSetConditionMask(
VerSetConditionMask(
VerSetConditionMask(
0, VER_MAJORVERSION, VER_GREATER_EQUAL),
VER_MINORVERSION, VER_GREATER_EQUAL),
VER_SERVICEPACKMAJOR, VER_GREATER_EQUAL);

memset(&osvi, 0, sizeof(osvi));
osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEXW);
osvi.dwMajorVersion = HIBYTE(_WIN32_WINNT_WIN7);
osvi.dwMinorVersion = LOBYTE(_WIN32_WINNT_WIN7);
osvi.wServicePackMajor = 0;

cached = (VerifyVersionInfoW(&osvi, VER_MAJORVERSION | VER_MINORVERSION | VER_SERVICEPACKMAJOR, dwlConditionMask) != FALSE) ? 1 : 0;
}
return cached;
}
#endif

/* vim: set ts=4 sts=4 sw=4 noet: */
3 util.h
@@ -27,6 +27,9 @@ uint32_t popcnt(uint32_t v);
uint32_t count_trailing_zero_bits(uint32_t v);
void squeeze(char *str);
double time_sec(void);
#ifdef TARGET_OS_WINDOWS
int is_windows7_or_greater(void);
#endif

#define NELEM(x) (sizeof(x) / sizeof((x)[0]))

0 comments on commit 0ce2b1c

Please sign in to comment.
You can’t perform that action at this time.