mirror of
https://gitlab.winehq.org/wine/wine-staging.git
synced 2024-11-21 16:46:54 -08:00
276 lines
11 KiB
Diff
276 lines
11 KiB
Diff
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
|
|
|