From e6eb1b2542caec9481f9ec0ad87d17dd568a3106 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Michael=20M=C3=BCller?= <michael@fds-team.de>
Date: Sat, 4 Feb 2017 16:20:37 +0100
Subject: [PATCH] kernel32: Implement some processor group functions.

---
 .../api-ms-win-core-kernel32-legacy-l1-1-0.spec    |  2 +-
 .../api-ms-win-core-kernel32-legacy-l1-1-1.spec    |  2 +-
 dlls/kernel32/cpu.c                                | 28 ++++++++++++++++------
 dlls/kernel32/kernel32.spec                        |  2 +-
 dlls/kernel32/tests/process.c                      | 23 ++++++++++++++++++
 include/winnt.h                                    |  2 ++
 6 files changed, 49 insertions(+), 10 deletions(-)

diff --git a/dlls/api-ms-win-core-kernel32-legacy-l1-1-0/api-ms-win-core-kernel32-legacy-l1-1-0.spec b/dlls/api-ms-win-core-kernel32-legacy-l1-1-0/api-ms-win-core-kernel32-legacy-l1-1-0.spec
index e653ac6..b6af37a 100644
--- a/dlls/api-ms-win-core-kernel32-legacy-l1-1-0/api-ms-win-core-kernel32-legacy-l1-1-0.spec
+++ b/dlls/api-ms-win-core-kernel32-legacy-l1-1-0/api-ms-win-core-kernel32-legacy-l1-1-0.spec
@@ -21,7 +21,7 @@
 @ stdcall GetComputerNameW(ptr ptr) kernel32.GetComputerNameW
 @ stdcall GetConsoleWindow() kernel32.GetConsoleWindow
 @ stub GetDurationFormatEx
-@ stub GetMaximumProcessorGroupCount
+@ stdcall GetMaximumProcessorGroupCount() kernel32.GetMaximumProcessorGroupCount
 @ stdcall GetNamedPipeClientProcessId(long ptr) kernel32.GetNamedPipeClientProcessId
 @ stdcall GetNamedPipeServerProcessId(long ptr) kernel32.GetNamedPipeServerProcessId
 @ stdcall GetShortPathNameA(str ptr long) kernel32.GetShortPathNameA
diff --git a/dlls/api-ms-win-core-kernel32-legacy-l1-1-1/api-ms-win-core-kernel32-legacy-l1-1-1.spec b/dlls/api-ms-win-core-kernel32-legacy-l1-1-1/api-ms-win-core-kernel32-legacy-l1-1-1.spec
index 946e3de..fca40f1 100644
--- a/dlls/api-ms-win-core-kernel32-legacy-l1-1-1/api-ms-win-core-kernel32-legacy-l1-1-1.spec
+++ b/dlls/api-ms-win-core-kernel32-legacy-l1-1-1/api-ms-win-core-kernel32-legacy-l1-1-1.spec
@@ -26,7 +26,7 @@
 @ stub GetDurationFormatEx
 @ stub GetFileAttributesTransactedW
 @ stub GetFirmwareType
-@ stub GetMaximumProcessorGroupCount
+@ stdcall GetMaximumProcessorGroupCount() kernel32.GetMaximumProcessorGroupCount
 @ stdcall GetNamedPipeClientProcessId(long ptr) kernel32.GetNamedPipeClientProcessId
 @ stdcall GetNamedPipeServerProcessId(long ptr) kernel32.GetNamedPipeServerProcessId
 @ stdcall GetNumaAvailableMemoryNodeEx(long ptr)
diff --git a/dlls/kernel32/cpu.c b/dlls/kernel32/cpu.c
index 6e198ba..8d0afde 100644
--- a/dlls/kernel32/cpu.c
+++ b/dlls/kernel32/cpu.c
@@ -284,7 +284,9 @@ SIZE_T WINAPI GetLargePageMinimum(void)
  */
 WORD WINAPI GetActiveProcessorGroupCount(void)
 {
-    FIXME("semi-stub, always returning 1\n");
+    TRACE("()\n");
+
+    /* systems with less than 64 logical processors only have group 0 */
     return 1;
 }
 
@@ -293,14 +295,26 @@ WORD WINAPI GetActiveProcessorGroupCount(void)
  */
 DWORD WINAPI GetActiveProcessorCount(WORD group)
 {
-    SYSTEM_INFO si;
-    DWORD cpus;
+    TRACE("(%u)\n", group);
 
-    GetSystemInfo( &si );
-    cpus = si.dwNumberOfProcessors;
+    if (group && group != ALL_PROCESSOR_GROUPS)
+    {
+        SetLastError(ERROR_INVALID_PARAMETER);
+        return 0;
+    }
 
-    FIXME("semi-stub, returning %u\n", cpus);
-    return cpus;
+    return system_info.NumberOfProcessors;
+}
+
+/***********************************************************************
+ *           GetMaximumProcessorGroupCount (KERNEL32.@)
+ */
+WORD WINAPI GetMaximumProcessorGroupCount(void)
+{
+    TRACE("()\n");
+
+    /* systems with less than 64 logical processors only have group 0 */
+    return 1;
 }
 
 /***********************************************************************
diff --git a/dlls/kernel32/kernel32.spec b/dlls/kernel32/kernel32.spec
index 8346575..1928382 100644
--- a/dlls/kernel32/kernel32.spec
+++ b/dlls/kernel32/kernel32.spec
@@ -717,7 +717,7 @@
 @ stdcall GetLongPathNameW (wstr long long)
 @ stdcall GetMailslotInfo(long ptr ptr ptr ptr)
 @ stdcall GetMaximumProcessorCount(long)
-# @ stub GetMaximumProcessorGroupCount
+@ stdcall GetMaximumProcessorGroupCount()
 @ stdcall GetModuleFileNameA(long ptr long)
 @ stdcall GetModuleFileNameW(long ptr long)
 @ stdcall GetModuleHandleA(str)
diff --git a/dlls/kernel32/tests/process.c b/dlls/kernel32/tests/process.c
index 0892d84..71d141d 100644
--- a/dlls/kernel32/tests/process.c
+++ b/dlls/kernel32/tests/process.c
@@ -91,6 +91,7 @@ static SIZE_T (WINAPI *pGetLargePageMinimum)(void);
 static BOOL   (WINAPI *pInitializeProcThreadAttributeList)(struct _PROC_THREAD_ATTRIBUTE_LIST*, DWORD, DWORD, SIZE_T*);
 static BOOL   (WINAPI *pUpdateProcThreadAttribute)(struct _PROC_THREAD_ATTRIBUTE_LIST*, DWORD, DWORD_PTR, void *,SIZE_T,void*,SIZE_T*);
 static void   (WINAPI *pDeleteProcThreadAttributeList)(struct _PROC_THREAD_ATTRIBUTE_LIST*);
+static DWORD  (WINAPI *pGetActiveProcessorCount)(WORD);
 
 /* ############################### */
 static char     base[MAX_PATH];
@@ -258,6 +259,7 @@ static BOOL init(void)
     pInitializeProcThreadAttributeList = (void *)GetProcAddress(hkernel32, "InitializeProcThreadAttributeList");
     pUpdateProcThreadAttribute = (void *)GetProcAddress(hkernel32, "UpdateProcThreadAttribute");
     pDeleteProcThreadAttributeList = (void *)GetProcAddress(hkernel32, "DeleteProcThreadAttributeList");
+    pGetActiveProcessorCount = (void *)GetProcAddress(hkernel32, "GetActiveProcessorCount");
 
     return TRUE;
 }
@@ -3880,6 +3882,26 @@ static void test_ProcThreadAttributeList(void)
     pDeleteProcThreadAttributeList(&list);
 }
 
+static void test_GetActiveProcessorCount(void)
+{
+    DWORD count;
+
+    if (!pGetActiveProcessorCount)
+    {
+        win_skip("GetActiveProcessorCount not available, skipping test\n");
+        return;
+    }
+
+    count = pGetActiveProcessorCount(0);
+    ok(count, "GetActiveProcessorCount failed, error %u\n", GetLastError());
+
+    /* Test would fail on systems with more than 6400 processors */
+    SetLastError(0xdeadbeef);
+    count = pGetActiveProcessorCount(101);
+    ok(count == 0, "Expeced GetActiveProcessorCount to fail\n");
+    ok(GetLastError() == ERROR_INVALID_PARAMETER, "Expected ERROR_INVALID_PARAMETER, got %u\n", GetLastError());
+}
+
 START_TEST(process)
 {
     HANDLE job;
@@ -3964,6 +3986,7 @@ START_TEST(process)
     test_GetNumaProcessorNode();
     test_session_info();
     test_GetLogicalProcessorInformationEx();
+    test_GetActiveProcessorCount();
     test_largepages();
     test_ProcThreadAttributeList();
     test_SuspendProcessState();
diff --git a/include/winnt.h b/include/winnt.h
index 6f651c8..e0ac7d5 100644
--- a/include/winnt.h
+++ b/include/winnt.h
@@ -6355,6 +6355,8 @@ typedef struct _GROUP_AFFINITY
     WORD Reserved[3];
 } GROUP_AFFINITY, *PGROUP_AFFINITY;
 
+#define ALL_PROCESSOR_GROUPS 0xffff
+
 typedef struct _PROCESSOR_NUMBER
 {
     WORD Group;
-- 
1.9.1

