Added patch to implement {Set,Get}ThreadGroupAffinity and related ntdll functions.

This commit is contained in:
Sebastian Lackner 2015-09-06 12:08:52 +02:00
parent 7d662cf2d7
commit dd18774526
6 changed files with 410 additions and 1 deletions

View File

@ -39,7 +39,7 @@ Wine. All those differences are also documented on the
Included bug fixes and improvements
-----------------------------------
**Bug fixes and features included in the next upcoming release [17]:**
**Bug fixes and features included in the next upcoming release [18]:**
* Add stub for dwmapi.DwmUpdateThumbnailProperties
* Add stub for winspool.SetPrinterW level 8 ([Wine Bug #24645](https://bugs.winehq.org/show_bug.cgi?id=24645))
@ -52,6 +52,7 @@ Included bug fixes and improvements
* Implement FolderImpl_Items and stubbed FolderItems interface
* Implement a Courier New replacement font ([Wine Bug #20456](https://bugs.winehq.org/show_bug.cgi?id=20456))
* Implement a Times New Roman replacement font ([Wine Bug #32342](https://bugs.winehq.org/show_bug.cgi?id=32342))
* Implement {Set,Get}ThreadGroupAffinity and related ntdll functions ([Wine Bug #36549](https://bugs.winehq.org/show_bug.cgi?id=36549))
* Map EXDEV error code to STATUS_NOT_SAME_DEVICE
* Properly close sockets when WSACleanup is called ([Wine Bug #18670](https://bugs.winehq.org/show_bug.cgi?id=18670))
* Return a dummy BIOS name in Win32_BIOS record

2
debian/changelog vendored
View File

@ -31,6 +31,8 @@ wine-staging (1.7.51) UNRELEASED; urgency=low
* Added patch to use proper glyph names in wineps driver (which fixes a bug
related to copying text from generated PDF files).
* Added patch to properly close sockets when WSACleanup is called.
* Added patch to implement {Set,Get}ThreadGroupAffinity and related ntdll
functions.
* Removed patch to fix bug in wineserver debug_children inheritance (accepted
upstream).
* Removed patch to use helper function for NtWaitForMultipleObjects and

View File

@ -0,0 +1,108 @@
From c12f95c2b6fefcbe086e1d623d2124f31b84b53e 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:17:46 +0200
Subject: ntdll: Implement ThreadGroupInformation class.
---
dlls/ntdll/thread.c | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++
include/winternl.h | 16 ++++++++++++++++
2 files changed, 66 insertions(+)
diff --git a/dlls/ntdll/thread.c b/dlls/ntdll/thread.c
index 0a8a7b9..afb347f 100644
--- a/dlls/ntdll/thread.c
+++ b/dlls/ntdll/thread.c
@@ -1103,6 +1103,29 @@ NTSTATUS WINAPI NtQueryInformationThread( HANDLE handle, THREADINFOCLASS class,
SERVER_END_REQ;
return status;
}
+ case ThreadGroupInformation:
+ {
+ const ULONG_PTR affinity_mask = get_system_affinity_mask();
+ GROUP_AFFINITY affinity;
+
+ memset(&affinity, 0, sizeof(affinity));
+ affinity.Group = 0; /* Wine only supports max 64 processors */
+
+ SERVER_START_REQ( get_thread_info )
+ {
+ req->handle = wine_server_obj_handle( handle );
+ req->tid_in = 0;
+ if (!(status = wine_server_call( req )))
+ affinity.Mask = reply->affinity & affinity_mask;
+ }
+ SERVER_END_REQ;
+ if (status == STATUS_SUCCESS)
+ {
+ if (data) memcpy( data, &affinity, min( length, sizeof(affinity) ));
+ if (ret_len) *ret_len = min( length, sizeof(affinity) );
+ }
+ }
+ return status;
case ThreadPriority:
case ThreadBasePriority:
case ThreadImpersonationToken:
@@ -1233,6 +1256,33 @@ NTSTATUS WINAPI NtSetInformationThread( HANDLE handle, THREADINFOCLASS class,
SERVER_END_REQ;
}
return status;
+ case ThreadGroupInformation:
+ {
+ const ULONG_PTR affinity_mask = get_system_affinity_mask();
+ const GROUP_AFFINITY *req_aff;
+
+ if (length != sizeof(*req_aff)) return STATUS_INVALID_PARAMETER;
+ if (!data) return STATUS_ACCESS_VIOLATION;
+ req_aff = data;
+
+ /* On windows the request fails if the reserved fields are set */
+ if (req_aff->Reserved[0] || req_aff->Reserved[1] || req_aff->Reserved[2])
+ return STATUS_INVALID_PARAMETER;
+
+ /* Wine only supports max 64 processors */
+ if (req_aff->Group) return STATUS_INVALID_PARAMETER;
+ if (req_aff->Mask & ~affinity_mask) return STATUS_INVALID_PARAMETER;
+ if (!req_aff->Mask) return STATUS_INVALID_PARAMETER;
+ SERVER_START_REQ( set_thread_info )
+ {
+ req->handle = wine_server_obj_handle( handle );
+ req->affinity = req_aff->Mask;
+ req->mask = SET_THREAD_INFO_AFFINITY;
+ status = wine_server_call( req );
+ }
+ SERVER_END_REQ;
+ }
+ return status;
case ThreadBasicInformation:
case ThreadTimes:
case ThreadPriority:
diff --git a/include/winternl.h b/include/winternl.h
index 2b10f8d..3e64b4d 100644
--- a/include/winternl.h
+++ b/include/winternl.h
@@ -859,6 +859,22 @@ typedef enum _THREADINFOCLASS {
ThreadSetTlsArrayAddress,
ThreadIsIoPending,
ThreadHideFromDebugger,
+ ThreadBreakOnTermination,
+ ThreadSwitchLegacyState,
+ ThreadIsTerminated,
+ ThreadLastSystemCall,
+ ThreadIoPriority,
+ ThreadCycleTime,
+ ThreadPagePriority,
+ ThreadActualBasePriority,
+ ThreadTebInformation,
+ ThreadCSwitchMon,
+ ThreadCSwitchPmu,
+ ThreadWow64Context,
+ ThreadGroupInformation,
+ ThreadUmsInformation,
+ ThreadCounterProfiling,
+ ThreadIdealProcessorEx,
MaxThreadInfoClass
} THREADINFOCLASS;
--
2.5.1

View File

@ -0,0 +1,275 @@
From 318239782eedd7da56d610d448c17b355ab0f1be 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..3b4eab8 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,
+ "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

View File

@ -0,0 +1 @@
Fixes: [36549] Implement {Set,Get}ThreadGroupAffinity and related ntdll functions

View File

@ -158,6 +158,7 @@ patch_enable_all ()
enable_kernel32_Profile="$1"
enable_kernel32_SetFileCompletionNotificationModes="$1"
enable_kernel32_SetFileInformationByHandle="$1"
enable_kernel32_ThreadGroupAffinity="$1"
enable_kernel32_TimezoneInformation_Registry="$1"
enable_kernel32_VerifyVersionInfo="$1"
enable_libs_Debug_Channel="$1"
@ -566,6 +567,9 @@ patch_enable ()
kernel32-SetFileInformationByHandle)
enable_kernel32_SetFileInformationByHandle="$2"
;;
kernel32-ThreadGroupAffinity)
enable_kernel32_ThreadGroupAffinity="$2"
;;
kernel32-TimezoneInformation_Registry)
enable_kernel32_TimezoneInformation_Registry="$2"
;;
@ -3506,6 +3510,24 @@ if test "$enable_kernel32_SetFileCompletionNotificationModes" -eq 1; then
) >> "$patchlist"
fi
# Patchset kernel32-ThreadGroupAffinity
# |
# | This patchset fixes the following Wine bugs:
# | * [#36549] Implement {Set,Get}ThreadGroupAffinity and related ntdll functions
# |
# | Modified files:
# | * dlls/kernel32/kernel32.spec, dlls/kernel32/tests/thread.c, dlls/kernel32/thread.c, dlls/ntdll/thread.c,
# | include/winternl.h
# |
if test "$enable_kernel32_ThreadGroupAffinity" -eq 1; then
patch_apply kernel32-ThreadGroupAffinity/0001-ntdll-Implement-ThreadGroupInformation-class.patch
patch_apply kernel32-ThreadGroupAffinity/0002-kernel32-Implement-Set-GetThreadGroupAffinity.patch
(
echo '+ { "Michael Müller", "ntdll: Implement ThreadGroupInformation class.", 1 },';
echo '+ { "Michael Müller", "kernel32: Implement Set/GetThreadGroupAffinity.", 1 },';
) >> "$patchlist"
fi
# Patchset kernel32-TimezoneInformation_Registry
# |
# | Modified files: