wine-staging/patches/kernel32-ThreadGroupAffinity/0002-kernel32-Implement-Set-GetThreadGroupAffinity.patch

276 lines
11 KiB
Diff
Raw Normal View History

From 0e15d46d97e226c2a566d7f30c9f67afaabbb6b1 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Michael=20M=C3=BCller?= <michael@fds-team.de>
Date: Sun, 6 Sep 2015 06:19:40 +0200
Subject: kernel32: Implement Set/GetThreadGroupAffinity.
---
dlls/kernel32/kernel32.spec | 4 +-
dlls/kernel32/tests/thread.c | 142 ++++++++++++++++++++++++++++++++-----------
dlls/kernel32/thread.c | 46 ++++++++++++++
3 files changed, 156 insertions(+), 36 deletions(-)
diff --git a/dlls/kernel32/kernel32.spec b/dlls/kernel32/kernel32.spec
index 77e55e1..bda7c9d 100644
--- a/dlls/kernel32/kernel32.spec
+++ b/dlls/kernel32/kernel32.spec
@@ -844,7 +844,7 @@
@ stdcall GetTempPathW(long ptr)
@ stdcall GetThreadContext(long ptr)
@ stdcall GetThreadErrorMode()
-# @ stub GetThreadGroupAffinity
+@ stdcall GetThreadGroupAffinity(long ptr)
@ stdcall GetThreadId(ptr)
# @ stub GetThreadIdealProcessorEx
@ stdcall GetThreadIOPendingFlag(long ptr)
@@ -1443,7 +1443,7 @@
@ stdcall SetThreadContext(long ptr)
@ stdcall SetThreadErrorMode(long ptr)
@ stdcall SetThreadExecutionState(long)
-# @ stub SetThreadGroupAffinity
+@ stdcall SetThreadGroupAffinity(long ptr ptr)
@ stdcall SetThreadIdealProcessor(long long)
# @ stub SetThreadIdealProcessorEx
@ stdcall SetThreadLocale(long)
diff --git a/dlls/kernel32/tests/thread.c b/dlls/kernel32/tests/thread.c
index d0fbfa4..fc5ff94 100644
--- a/dlls/kernel32/tests/thread.c
+++ b/dlls/kernel32/tests/thread.c
@@ -99,6 +99,9 @@ static void (WINAPI *pSubmitThreadpoolWork)(PTP_WORK);
static void (WINAPI *pWaitForThreadpoolWorkCallbacks)(PTP_WORK,BOOL);
static void (WINAPI *pCloseThreadpoolWork)(PTP_WORK);
static NTSTATUS (WINAPI *pNtQueryInformationThread)(HANDLE,THREADINFOCLASS,PVOID,ULONG,PULONG);
+static BOOL (WINAPI *pGetThreadGroupAffinity)(HANDLE,GROUP_AFFINITY*);
+static BOOL (WINAPI *pSetThreadGroupAffinity)(HANDLE,const GROUP_AFFINITY*,GROUP_AFFINITY*);
+static NTSTATUS (WINAPI *pNtSetInformationThread)(HANDLE,THREADINFOCLASS,LPCVOID,ULONG);
static HANDLE create_target_process(const char *arg)
{
@@ -877,6 +880,15 @@ static VOID test_thread_processor(void)
retMask = SetThreadAffinityMask(curthread,~0);
ok(broken(retMask==0) || retMask==processMask,
"SetThreadAffinityMask(thread,-1) failed to request all processors.\n");
+
+ if (retMask == processMask)
+ {
+ /* Show that the "all processors" flag is handled in ntdll/kernel */
+ DWORD_PTR mask = ~0;
+ NTSTATUS status = pNtSetInformationThread(curthread, ThreadAffinityMask, &mask, sizeof(mask));
+ ok(status == STATUS_SUCCESS, "Expected STATUS_SUCCESS in NtSetInformationThread, got %x\n", status);
+ }
+
if (retMask == processMask && sizeof(ULONG_PTR) > sizeof(ULONG))
{
/* only the low 32-bits matter */
@@ -886,41 +898,99 @@ static VOID test_thread_processor(void)
ok(retMask == processMask, "SetThreadAffinityMask failed\n");
}
/* NOTE: This only works on WinNT/2000/XP) */
- if (pSetThreadIdealProcessor) {
- SetLastError(0xdeadbeef);
- error=pSetThreadIdealProcessor(curthread,0);
- if (GetLastError()==ERROR_CALL_NOT_IMPLEMENTED)
- {
- win_skip("SetThreadIdealProcessor is not implemented\n");
- return;
- }
- ok(error!=-1, "SetThreadIdealProcessor failed\n");
-
- if (is_wow64)
- {
- SetLastError(0xdeadbeef);
- error=pSetThreadIdealProcessor(curthread,MAXIMUM_PROCESSORS+1);
- todo_wine
- ok(error!=-1, "SetThreadIdealProcessor failed for %u on Wow64\n", MAXIMUM_PROCESSORS+1);
-
- SetLastError(0xdeadbeef);
- error=pSetThreadIdealProcessor(curthread,65);
- ok(error==-1, "SetThreadIdealProcessor succeeded with an illegal processor #\n");
- ok(GetLastError()==ERROR_INVALID_PARAMETER,
- "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
- }
- else
- {
- SetLastError(0xdeadbeef);
- error=pSetThreadIdealProcessor(curthread,MAXIMUM_PROCESSORS+1);
- ok(error==-1, "SetThreadIdealProcessor succeeded with an illegal processor #\n");
- ok(GetLastError()==ERROR_INVALID_PARAMETER,
- "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
- }
+ if (pSetThreadIdealProcessor)
+ {
+ SetLastError(0xdeadbeef);
+ error=pSetThreadIdealProcessor(curthread,0);
+ if (GetLastError()!=ERROR_CALL_NOT_IMPLEMENTED)
+ {
+ ok(error!=-1, "SetThreadIdealProcessor failed\n");
+
+ if (is_wow64)
+ {
+ SetLastError(0xdeadbeef);
+ error=pSetThreadIdealProcessor(curthread,MAXIMUM_PROCESSORS+1);
+ todo_wine
+ ok(error!=-1, "SetThreadIdealProcessor failed for %u on Wow64\n", MAXIMUM_PROCESSORS+1);
+
+ SetLastError(0xdeadbeef);
+ error=pSetThreadIdealProcessor(curthread,65);
+ ok(error==-1, "SetThreadIdealProcessor succeeded with an illegal processor #\n");
+ ok(GetLastError()==ERROR_INVALID_PARAMETER,
+ "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
+ }
+ else
+ {
+ SetLastError(0xdeadbeef);
+ error=pSetThreadIdealProcessor(curthread,MAXIMUM_PROCESSORS+1);
+ ok(error==-1, "SetThreadIdealProcessor succeeded with an illegal processor #\n");
+ ok(GetLastError()==ERROR_INVALID_PARAMETER,
+ "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
+ }
+
+ error=pSetThreadIdealProcessor(curthread,MAXIMUM_PROCESSORS);
+ ok(error!=-1, "SetThreadIdealProcessor failed\n");
+ }
+ else
+ win_skip("SetThreadIdealProcessor is not implemented\n");
+ }
- error=pSetThreadIdealProcessor(curthread,MAXIMUM_PROCESSORS);
- ok(error!=-1, "SetThreadIdealProcessor failed\n");
- }
+ if (pGetThreadGroupAffinity && pSetThreadGroupAffinity)
+ {
+ GROUP_AFFINITY affinity, affinity_new;
+ NTSTATUS status;
+
+ memset(&affinity, 0, sizeof(affinity));
+ ok(pGetThreadGroupAffinity(curthread, &affinity), "GetThreadGroupAffinity failed\n");
+
+ SetLastError(0xdeadbeef);
+ ok(!pGetThreadGroupAffinity(curthread, NULL), "GetThreadGroupAffinity succeeded\n");
+ ok(GetLastError() == ERROR_INVALID_PARAMETER || broken(GetLastError() == ERROR_NOACCESS), /* Win 7 and 8 */
+ "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
+ ok(affinity.Group == 0, "Expected group 0 got %u\n", affinity.Group);
+
+ memset(&affinity_new, 0, sizeof(affinity_new));
+ affinity_new.Group = 0;
+ affinity_new.Mask = affinity.Mask;
+ ok(pSetThreadGroupAffinity(curthread, &affinity_new, &affinity), "SetThreadGroupAffinity failed\n");
+ ok(affinity_new.Mask == affinity.Mask, "Expected old affinity mask %lx, got %lx\n",
+ affinity_new.Mask, affinity.Mask);
+
+ /* show that the "all processors" flag is not supported for SetThreadGroupAffinity */
+ affinity_new.Group = 0;
+ affinity_new.Mask = ~0;
+ SetLastError(0xdeadbeef);
+ ok(!pSetThreadGroupAffinity(curthread, &affinity_new, NULL), "SetThreadGroupAffinity succeeded\n");
+ ok(GetLastError() == ERROR_INVALID_PARAMETER,
+ "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
+
+ affinity_new.Group = 1; /* assumes that you have less than 64 logical processors */
+ affinity_new.Mask = 0x1;
+ SetLastError(0xdeadbeef);
+ ok(!pSetThreadGroupAffinity(curthread, &affinity_new, NULL), "SetThreadGroupAffinity succeeded\n");
+ ok(GetLastError() == ERROR_INVALID_PARAMETER,
+ "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
+
+ SetLastError(0xdeadbeef);
+ ok(!pSetThreadGroupAffinity(curthread, NULL, NULL), "SetThreadGroupAffinity succeeded\n");
+ ok(GetLastError() == ERROR_NOACCESS,
+ "Expected ERROR_NOACCESS, got %d\n", GetLastError());
+
+ /* show that the ERROR_NOACCESS was set in ntdll */
+ status = pNtSetInformationThread(curthread, ThreadGroupInformation, NULL, sizeof(affinity_new));
+ ok(status == STATUS_ACCESS_VIOLATION,
+ "Expected STATUS_ACCESS_VIOLATION, got %08x\n", status);
+
+ /* restore original mask */
+ affinity_new.Group = 0;
+ affinity_new.Mask = affinity.Mask;
+ SetLastError(0xdeadbeef);
+ ok(pSetThreadGroupAffinity(curthread, &affinity_new, &affinity), "SetThreadGroupAffinity failed\n");
+ ok(affinity_new.Mask == affinity.Mask, "Expected old affinity mask %lx, got %lx\n",
+ affinity_new.Mask, affinity.Mask);
+ }
+ else
+ win_skip("Get/SetThreadGroupAffinity not available\n");
}
static VOID test_GetThreadExitCode(void)
@@ -1833,6 +1903,9 @@ static void init_funcs(void)
X(SubmitThreadpoolWork);
X(WaitForThreadpoolWorkCallbacks);
X(CloseThreadpoolWork);
+
+ X(GetThreadGroupAffinity);
+ X(SetThreadGroupAffinity);
#undef X
#define X(f) p##f = (void*)GetProcAddress(ntdll, #f)
@@ -1840,6 +1913,7 @@ static void init_funcs(void)
{
X(NtQueryInformationThread);
X(RtlGetThreadErrorMode);
+ X(NtSetInformationThread);
}
#undef X
}
diff --git a/dlls/kernel32/thread.c b/dlls/kernel32/thread.c
index c992e0d..0e9de82 100644
--- a/dlls/kernel32/thread.c
+++ b/dlls/kernel32/thread.c
@@ -378,6 +378,52 @@ BOOL WINAPI SetThreadStackGuarantee(PULONG stacksize)
return TRUE;
}
+/***********************************************************************
+ * GetThreadGroupAffinity (KERNEL32.@)
+ */
+BOOL WINAPI GetThreadGroupAffinity( HANDLE thread, GROUP_AFFINITY *affinity )
+{
+ NTSTATUS status;
+
+ if (!affinity)
+ {
+ SetLastError( ERROR_INVALID_PARAMETER );
+ return FALSE;
+ }
+
+ status = NtQueryInformationThread( thread, ThreadGroupInformation,
+ affinity, sizeof(*affinity), NULL );
+ if (status)
+ {
+ SetLastError( RtlNtStatusToDosError(status) );
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/***********************************************************************
+ * SetThreadGroupAffinity (KERNEL32.@)
+ */
+BOOL WINAPI SetThreadGroupAffinity( HANDLE thread, const GROUP_AFFINITY *affinity_new,
+ GROUP_AFFINITY *affinity_old )
+{
+ NTSTATUS status;
+
+ if (affinity_old && !GetThreadGroupAffinity( thread, affinity_old ))
+ return FALSE;
+
+ status = NtSetInformationThread( thread, ThreadGroupInformation,
+ affinity_new, sizeof(*affinity_new) );
+ if (status)
+ {
+ SetLastError( RtlNtStatusToDosError(status) );
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
/**********************************************************************
* SetThreadAffinityMask (KERNEL32.@)
*/
--
2.5.1