[PATCH v3 0/5] MR9271: Implement group affinity support in CreateRemoteThreadEx.
This MR implements group affinity support in attributes list passed to CreateRemoteThreadEx(). (up to the current Wine limit of 64 logical cores). It also adds a couple of missing APIs definitions related to group affinity support. Notes: - duplicating for the Nth time struct \_PROC\_THREAD\_ATTRIBUTE\_LIST definition isn't very nice... perhaps we should define it somewhere? - it's very likely that CreateRemoteThreadEx() should call into NtCreateThreadEx() (instead of the Rtl counter part), but I opted for the simpler approach to set thread affinity after thread creation (this could be changed if needed). -- v3: kernelbase: Support group affinity attributes. kernel32/tests: Test thread creation with group affinity attributes. include: Add missing process group related definitions. kernelbase: Support affinity group in process/thread attributes list. kernel32: Test adding group affinity to proc/thread attributes list. https://gitlab.winehq.org/wine/wine/-/merge_requests/9271
From: Eric Pouech <epouech(a)codeweavers.com> Signed-off-by: Eric Pouech <epouech(a)codeweavers.com> --- dlls/kernel32/tests/process.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/dlls/kernel32/tests/process.c b/dlls/kernel32/tests/process.c index f539f69b3af..4e3a272270e 100644 --- a/dlls/kernel32/tests/process.c +++ b/dlls/kernel32/tests/process.c @@ -4391,6 +4391,7 @@ static void test_ProcThreadAttributeList(void) int i; struct _PROC_THREAD_ATTRIBUTE_LIST list, expect_list; HANDLE handles[4]; + GROUP_AFFINITY gaff = {.Group = 0, .Mask = 0xffff}; if (!pInitializeProcThreadAttributeList) { @@ -4490,6 +4491,18 @@ static void test_ProcThreadAttributeList(void) expect_list.attrs[i].value = handles; } + ret = pUpdateProcThreadAttribute(&list, 0, PROC_THREAD_ATTRIBUTE_GROUP_AFFINITY, &gaff, sizeof(gaff), NULL, NULL); + todo_wine + ok(ret, "got %d gle %ld\n", ret, GetLastError()); + if (ret) + { + unsigned int i = expect_list.count++; + expect_list.mask |= 1 << ProcThreadAttributeGroupAffinity; + expect_list.attrs[i].attr = PROC_THREAD_ATTRIBUTE_GROUP_AFFINITY; + expect_list.attrs[i].size = sizeof(GROUP_AFFINITY); + expect_list.attrs[i].value = &gaff; + } + ok(!memcmp(&list, &expect_list, size), "mismatch\n"); pDeleteProcThreadAttributeList(&list); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/9271
From: Eric Pouech <epouech(a)codeweavers.com> Signed-off-by: Eric Pouech <epouech(a)codeweavers.com> --- dlls/kernel32/tests/process.c | 1 - dlls/kernelbase/process.c | 3 +++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/dlls/kernel32/tests/process.c b/dlls/kernel32/tests/process.c index 4e3a272270e..db7b364534d 100644 --- a/dlls/kernel32/tests/process.c +++ b/dlls/kernel32/tests/process.c @@ -4492,7 +4492,6 @@ static void test_ProcThreadAttributeList(void) } ret = pUpdateProcThreadAttribute(&list, 0, PROC_THREAD_ATTRIBUTE_GROUP_AFFINITY, &gaff, sizeof(gaff), NULL, NULL); - todo_wine ok(ret, "got %d gle %ld\n", ret, GetLastError()); if (ret) { diff --git a/dlls/kernelbase/process.c b/dlls/kernelbase/process.c index e1c28fc67ed..56ee5b2fbfb 100644 --- a/dlls/kernelbase/process.c +++ b/dlls/kernelbase/process.c @@ -1798,6 +1798,9 @@ static inline DWORD validate_proc_thread_attribute( DWORD_PTR attr, SIZE_T size case PROC_THREAD_ATTRIBUTE_MACHINE_TYPE: if (size != sizeof(USHORT)) return ERROR_BAD_LENGTH; break; + case PROC_THREAD_ATTRIBUTE_GROUP_AFFINITY: + if (size != sizeof(GROUP_AFFINITY)) return ERROR_BAD_LENGTH; + break; default: FIXME( "Unhandled attribute %Iu\n", attr & PROC_THREAD_ATTRIBUTE_NUMBER ); return ERROR_NOT_SUPPORTED; -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/9271
From: Eric Pouech <epouech(a)codeweavers.com> --- include/winbase.h | 6 ++++++ include/winnt.h | 23 +++++++++++++++++------ include/winternl.h | 2 ++ 3 files changed, 25 insertions(+), 6 deletions(-) diff --git a/include/winbase.h b/include/winbase.h index c96f58a61b3..0213b40ef57 100644 --- a/include/winbase.h +++ b/include/winbase.h @@ -1823,6 +1823,7 @@ WINADVAPI PVOID WINAPI FreeSid(PSID); WINADVAPI BOOL WINAPI GetAce(PACL,DWORD,LPVOID*); WINADVAPI BOOL WINAPI GetAclInformation(PACL,LPVOID,DWORD,ACL_INFORMATION_CLASS); WINBASEAPI DWORD WINAPI GetActiveProcessorCount(WORD); +WINBASEAPI WORD WINAPI GetActiveProcessorGroupCount(void); WINBASEAPI HRESULT WINAPI GetApplicationRestartSettings(HANDLE,WCHAR*,DWORD*,DWORD*); WINBASEAPI UINT WINAPI GetAtomNameA(ATOM,LPSTR,INT); WINBASEAPI UINT WINAPI GetAtomNameW(ATOM,LPWSTR,INT); @@ -1921,6 +1922,7 @@ WINBASEAPI DWORD WINAPI GetLongPathNameW(LPCWSTR,LPWSTR,DWORD); #define GetLongPathName WINELIB_NAME_AW(GetLongPathName) WINBASEAPI BOOL WINAPI GetMailslotInfo(HANDLE,LPDWORD,LPDWORD,LPDWORD,LPDWORD); WINBASEAPI DWORD WINAPI GetMaximumProcessorCount(WORD); +WINBASEAPI WORD WINAPI GetMaximumProcessorGroupCount(void); WINBASEAPI DWORD WINAPI GetModuleFileNameA(HMODULE,LPSTR,DWORD); WINBASEAPI DWORD WINAPI GetModuleFileNameW(HMODULE,LPWSTR,DWORD); #define GetModuleFileName WINELIB_NAME_AW(GetModuleFileName) @@ -1969,6 +1971,7 @@ WINBASEAPI BOOL WINAPI GetPrivateProfileStructW(LPCWSTR,LPCWSTR,LPVOID,UI #define GetPrivateProfileStruct WINELIB_NAME_AW(GetPrivateProfileStruct) WINBASEAPI FARPROC WINAPI GetProcAddress(HMODULE,LPCSTR); WINBASEAPI BOOL WINAPI GetProcessAffinityMask(HANDLE,PDWORD_PTR,PDWORD_PTR); +WINBASEAPI BOOL WINAPI GetProcessGroupAffinity(HANDLE, PUSHORT, PUSHORT); WINBASEAPI DWORD WINAPI GetProcessHeaps(DWORD,PHANDLE); WINBASEAPI DWORD WINAPI GetProcessId(HANDLE); WINBASEAPI DWORD WINAPI GetProcessIdOfThread(HANDLE); @@ -2031,6 +2034,7 @@ WINBASEAPI DWORD WINAPI GetTempPathW(DWORD,LPWSTR); #define GetTempPath WINELIB_NAME_AW(GetTempPath) WINBASEAPI BOOL WINAPI GetThreadContext(HANDLE,CONTEXT *); WINBASEAPI DWORD WINAPI GetThreadErrorMode(void); +WINBASEAPI BOOL WINAPI GetThreadGroupAffinity(HANDLE, PGROUP_AFFINITY); WINBASEAPI DWORD WINAPI GetThreadId(HANDLE); WINBASEAPI BOOL WINAPI GetThreadIOPendingFlag(HANDLE,PBOOL); WINBASEAPI INT WINAPI GetThreadPriority(HANDLE); @@ -2409,7 +2413,9 @@ WINBASEAPI DWORD_PTR WINAPI SetThreadAffinityMask(HANDLE,DWORD_PTR); WINBASEAPI BOOL WINAPI SetThreadContext(HANDLE,const CONTEXT *); WINBASEAPI BOOL WINAPI SetThreadErrorMode(DWORD,LPDWORD); WINBASEAPI DWORD WINAPI SetThreadExecutionState(EXECUTION_STATE); +WINBASEAPI BOOL WINAPI SetThreadGroupAffinity(HANDLE, const GROUP_AFFINITY *, GROUP_AFFINITY *); WINBASEAPI DWORD WINAPI SetThreadIdealProcessor(HANDLE,DWORD); +WINBASEAPI BOOL WINAPI SetThreadIdealProcessorEx(HANDLE, PROCESSOR_NUMBER *, PROCESSOR_NUMBER *); WINBASEAPI BOOL WINAPI SetThreadPriority(HANDLE,INT); WINBASEAPI BOOL WINAPI SetThreadPriorityBoost(HANDLE,BOOL); WINADVAPI BOOL WINAPI SetThreadToken(PHANDLE,HANDLE); diff --git a/include/winnt.h b/include/winnt.h index d360f5d0178..e53446472d6 100644 --- a/include/winnt.h +++ b/include/winnt.h @@ -734,10 +734,11 @@ typedef DWORD FLONG; #define PROCESSOR_OPTIL 18767 #ifdef _WIN64 -#define MAXIMUM_PROCESSORS 64 +#define MAXIMUM_PROC_PER_GROUP 64 #else -#define MAXIMUM_PROCESSORS 32 +#define MAXIMUM_PROC_PER_GROUP 32 #endif +#define MAXIMUM_PROCESSORS MAXIMUM_PROC_PER_GROUP typedef struct _MEMORY_BASIC_INFORMATION { @@ -6666,8 +6667,13 @@ typedef struct _PROCESSOR_RELATIONSHIP typedef struct _NUMA_NODE_RELATIONSHIP { DWORD NodeNumber; - BYTE Reserved[20]; - GROUP_AFFINITY GroupMask; + BYTE Reserved[18]; + WORD GroupCount; + union + { + GROUP_AFFINITY GroupMask; + GROUP_AFFINITY GroupMasks[ANYSIZE_ARRAY]; + }; } NUMA_NODE_RELATIONSHIP, *PNUMA_NODE_RELATIONSHIP; typedef struct _CACHE_RELATIONSHIP @@ -6677,8 +6683,13 @@ typedef struct _CACHE_RELATIONSHIP WORD LineSize; DWORD CacheSize; PROCESSOR_CACHE_TYPE Type; - BYTE Reserved[20]; - GROUP_AFFINITY GroupMask; + BYTE Reserved[18]; + WORD GroupCount; + union + { + GROUP_AFFINITY GroupMask; + GROUP_AFFINITY GroupMasks[ANYSIZE_ARRAY]; + }; } CACHE_RELATIONSHIP, *PCACHE_RELATIONSHIP; typedef struct _GROUP_RELATIONSHIP diff --git a/include/winternl.h b/include/winternl.h index 2c985465096..6ee4192bb64 100644 --- a/include/winternl.h +++ b/include/winternl.h @@ -4586,6 +4586,7 @@ NTSYSAPI NTSTATUS WINAPI NtFreeVirtualMemory(HANDLE,PVOID*,SIZE_T*,ULONG); NTSYSAPI NTSTATUS WINAPI NtFsControlFile(HANDLE,HANDLE,PIO_APC_ROUTINE,PVOID,PIO_STATUS_BLOCK,ULONG,PVOID,ULONG,PVOID,ULONG); NTSYSAPI NTSTATUS WINAPI NtGetContextThread(HANDLE,CONTEXT*); NTSYSAPI ULONG WINAPI NtGetCurrentProcessorNumber(void); +NTSYSAPI ULONG WINAPI NtGetCurrentProcessorNumberEx(PROCESSOR_NUMBER*); NTSYSAPI NTSTATUS WINAPI NtGetNextProcess(HANDLE,ACCESS_MASK,ULONG,ULONG,HANDLE*); NTSYSAPI NTSTATUS WINAPI NtGetNextThread(HANDLE,HANDLE,ACCESS_MASK,ULONG,ULONG,HANDLE*); NTSYSAPI NTSTATUS WINAPI NtGetNlsSectionPtr(ULONG,ULONG,void*,void**,SIZE_T*); @@ -4955,6 +4956,7 @@ NTSYSAPI NTSTATUS WINAPI RtlGetCompressionWorkSpaceSize(USHORT,PULONG,PULONG); NTSYSAPI NTSTATUS WINAPI RtlGetControlSecurityDescriptor(PSECURITY_DESCRIPTOR, PSECURITY_DESCRIPTOR_CONTROL,LPDWORD); NTSYSAPI ULONG WINAPI RtlGetCurrentDirectory_U(ULONG, LPWSTR); NTSYSAPI PEB * WINAPI RtlGetCurrentPeb(void); +NTSYSAPI ULONG WINAPI RtlGetCurrentProcessorNumber(void); NTSYSAPI void WINAPI RtlGetCurrentProcessorNumberEx(PROCESSOR_NUMBER*); NTSYSAPI HANDLE WINAPI RtlGetCurrentTransaction(void); NTSYSAPI NTSTATUS WINAPI RtlGetDaclSecurityDescriptor(PSECURITY_DESCRIPTOR,PBOOLEAN,PACL *,PBOOLEAN); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/9271
From: Eric Pouech <epouech(a)codeweavers.com> Signed-off-by: Eric Pouech <epouech(a)codeweavers.com> --- dlls/kernel32/tests/thread.c | 95 ++++++++++++++++++++++++++++++++++-- 1 file changed, 92 insertions(+), 3 deletions(-) diff --git a/dlls/kernel32/tests/thread.c b/dlls/kernel32/tests/thread.c index c0303b471e8..27a21b1c39c 100644 --- a/dlls/kernel32/tests/thread.c +++ b/dlls/kernel32/tests/thread.c @@ -88,21 +88,26 @@ static BOOL (WINAPI *pUnregisterWait)(HANDLE); static BOOL (WINAPI *pIsWow64Process)(HANDLE,PBOOL); static BOOL (WINAPI *pSetThreadErrorMode)(DWORD,PDWORD); static DWORD (WINAPI *pGetThreadErrorMode)(void); -static DWORD (WINAPI *pRtlGetThreadErrorMode)(void); static PTP_POOL (WINAPI *pCreateThreadpool)(PVOID); static void (WINAPI *pCloseThreadpool)(PTP_POOL); static PTP_WORK (WINAPI *pCreateThreadpoolWork)(PTP_WORK_CALLBACK,PVOID,PTP_CALLBACK_ENVIRON); 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 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 HRESULT (WINAPI *pSetThreadDescription)(HANDLE,const WCHAR *); static HRESULT (WINAPI *pGetThreadDescription)(HANDLE,WCHAR **); +static HANDLE (WINAPI *pCreateRemoteThreadEx)(HANDLE, SECURITY_ATTRIBUTES *, SIZE_T, LPTHREAD_START_ROUTINE, + LPVOID, DWORD, LPPROC_THREAD_ATTRIBUTE_LIST, DWORD *); +static NTSTATUS (WINAPI *pNtSetInformationThread)(HANDLE,THREADINFOCLASS,LPCVOID,ULONG); static PVOID (WINAPI *pRtlAddVectoredExceptionHandler)(ULONG,PVECTORED_EXCEPTION_HANDLER); static ULONG (WINAPI *pRtlRemoveVectoredExceptionHandler)(PVOID); +static NTSTATUS (WINAPI *pNtQueryInformationThread)(HANDLE,THREADINFOCLASS,PVOID,ULONG,PULONG); +static DWORD (WINAPI *pRtlGetThreadErrorMode)(void); static HANDLE create_target_process(const char *arg) { @@ -2634,6 +2639,12 @@ static void init_funcs(void) X(FlsFree); X(FlsSetValue); X(FlsGetValue); + + X(InitializeProcThreadAttributeList); + X(UpdateProcThreadAttribute); + X(DeleteProcThreadAttributeList); + + X(CreateRemoteThreadEx); #undef X #define X(f) p##f = (void*)GetProcAddress(ntdll, #f) @@ -2648,6 +2659,83 @@ static void init_funcs(void) #undef X } +static DWORD CALLBACK thread_ex_proc(void *_pmt) +{ + BOOL ret; + + ret = GetThreadGroupAffinity(GetCurrentThread(), (GROUP_AFFINITY *)_pmt); + ok(ret, "Expected GetTheadGroupAffinity to succeed\n"); + return 0; +} + +static void test_CreateRemoteThreadEx_affinity(void) +{ + struct _PROC_THREAD_ATTRIBUTE_LIST *attr_list; + GROUP_AFFINITY gaff, thread_gaff; + HANDLE handle; + SIZE_T size; + BOOL ret; + + if (RtlGetCurrentPeb()->NumberOfProcessors < 2) + { + skip("Not enough cores to test\n"); + return; + } + + ret = pInitializeProcThreadAttributeList(NULL, 1, 0, &size); + ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER, + "Got unexpected ret %#x, GetLastError() %lu.\n", ret, GetLastError()); + + attr_list = HeapAlloc(GetProcessHeap(), 0, size); + ret = pInitializeProcThreadAttributeList(attr_list, 1, 0, &size); + ok(ret, "Got unexpected ret %#x, GetLastError() %lu.\n", ret, GetLastError()); + memset(&gaff, 0, sizeof(gaff)); + gaff.Mask = (ULONG_PTR)1u << ((GetCurrentProcessorNumber() + 1) % RtlGetCurrentPeb()->NumberOfProcessors); + ret = pUpdateProcThreadAttribute(attr_list, 0, PROC_THREAD_ATTRIBUTE_GROUP_AFFINITY, + &gaff, sizeof(gaff), NULL, NULL); + ok(ret, "Couldn't update attr_list\n"); + + handle = pCreateRemoteThreadEx(GetCurrentProcess(), NULL, 0, &thread_ex_proc, &thread_gaff, 0, attr_list, NULL); + ok(handle != NULL, "Couldn't create thread %lu %lu\n", GetLastError(), RtlGetCurrentPeb()->NumberOfProcessors); + + ret = WaitForSingleObject(handle, INFINITE) == WAIT_OBJECT_0; + ok(ret, "Couldn't wait for thread termination\n"); + ok(thread_gaff.Group == gaff.Group, "Unexpected group %x (expecting %x)\n", thread_gaff.Group, gaff.Group); + todo_wine + ok(thread_gaff.Mask == gaff.Mask, "Unexpected affinity %Ix (expecting %Ix)\n", thread_gaff.Mask, gaff.Mask); + CloseHandle(handle); + + pDeleteProcThreadAttributeList(attr_list); + HeapFree(GetProcessHeap(), 0, attr_list); + + ret = pInitializeProcThreadAttributeList(NULL, 1, 0, &size); + ok(!ret && GetLastError() == ERROR_INSUFFICIENT_BUFFER, + "Got unexpected ret %#x, GetLastError() %lu.\n", ret, GetLastError()); + + /* check invalid core number */ + if ((RtlGetCurrentPeb()->NumberOfProcessors + 1) < MAXIMUM_PROCESSORS) + { + attr_list = HeapAlloc(GetProcessHeap(), 0, size); + ret = pInitializeProcThreadAttributeList(attr_list, 1, 0, &size); + ok(ret, "Got unexpected ret %#x, GetLastError() %lu.\n", ret, GetLastError()); + memset(&gaff, 0, sizeof(gaff)); + gaff.Mask = (ULONG_PTR)1u << (RtlGetCurrentPeb()->NumberOfProcessors + 1); + ret = pUpdateProcThreadAttribute(attr_list, 0, PROC_THREAD_ATTRIBUTE_GROUP_AFFINITY, + &gaff, sizeof(gaff), NULL, NULL); + ok(ret, "Couldn't update attr_list\n"); + + SetLastError(0xdeadbeef); + handle = pCreateRemoteThreadEx(GetCurrentProcess(), NULL, 0, &thread_ex_proc, &thread_gaff, 0, attr_list, NULL); + todo_wine + ok(handle == NULL, "Expecting failure\n"); + todo_wine + ok(GetLastError() == ERROR_INVALID_PARAMETER, "Unexpected gle %lu\n", GetLastError()); + if (handle) CloseHandle(handle); + pDeleteProcThreadAttributeList(attr_list); + HeapFree(GetProcessHeap(), 0, attr_list); + } +} + START_TEST(thread) { int argc; @@ -2709,6 +2797,7 @@ START_TEST(thread) test_thread_fpu_cw(); test_thread_actctx(); test_thread_description(); + test_CreateRemoteThreadEx_affinity(); test_threadpool(); } -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/9271
From: Eric Pouech <epouech(a)codeweavers.com> In CreateRemoteThreadEx(). Signed-off-by: Eric Pouech <epouech(a)codeweavers.com> --- dlls/kernel32/tests/thread.c | 3 --- dlls/kernelbase/thread.c | 40 ++++++++++++++++++++++++++++++++++-- 2 files changed, 38 insertions(+), 5 deletions(-) diff --git a/dlls/kernel32/tests/thread.c b/dlls/kernel32/tests/thread.c index 27a21b1c39c..c3316c3bdf0 100644 --- a/dlls/kernel32/tests/thread.c +++ b/dlls/kernel32/tests/thread.c @@ -2701,7 +2701,6 @@ static void test_CreateRemoteThreadEx_affinity(void) ret = WaitForSingleObject(handle, INFINITE) == WAIT_OBJECT_0; ok(ret, "Couldn't wait for thread termination\n"); ok(thread_gaff.Group == gaff.Group, "Unexpected group %x (expecting %x)\n", thread_gaff.Group, gaff.Group); - todo_wine ok(thread_gaff.Mask == gaff.Mask, "Unexpected affinity %Ix (expecting %Ix)\n", thread_gaff.Mask, gaff.Mask); CloseHandle(handle); @@ -2726,9 +2725,7 @@ static void test_CreateRemoteThreadEx_affinity(void) SetLastError(0xdeadbeef); handle = pCreateRemoteThreadEx(GetCurrentProcess(), NULL, 0, &thread_ex_proc, &thread_gaff, 0, attr_list, NULL); - todo_wine ok(handle == NULL, "Expecting failure\n"); - todo_wine ok(GetLastError() == ERROR_INVALID_PARAMETER, "Unexpected gle %lu\n", GetLastError()); if (handle) CloseHandle(handle); pDeleteProcThreadAttributeList(attr_list); diff --git a/dlls/kernelbase/thread.c b/dlls/kernelbase/thread.c index dbde4dcfaf3..5fb90b05af7 100644 --- a/dlls/kernelbase/thread.c +++ b/dlls/kernelbase/thread.c @@ -64,6 +64,22 @@ HANDLE WINAPI DECLSPEC_HOTPATCH CreateRemoteThread( HANDLE process, SECURITY_ATT return CreateRemoteThreadEx( process, sa, stack, start, param, flags, NULL, id ); } +struct proc_thread_attr +{ + DWORD_PTR attr; + SIZE_T size; + void *value; +}; + +struct _PROC_THREAD_ATTRIBUTE_LIST +{ + DWORD mask; /* bitmask of items in list */ + DWORD size; /* max number of items in list */ + DWORD count; /* number of items in list */ + DWORD pad; + DWORD_PTR unk; + struct proc_thread_attr attrs[1]; +}; /*************************************************************************** * CreateRemoteThreadEx (kernelbase.@) @@ -76,8 +92,22 @@ HANDLE WINAPI DECLSPEC_HOTPATCH CreateRemoteThreadEx( HANDLE process, SECURITY_A HANDLE handle; CLIENT_ID client_id; SIZE_T stack_reserve = 0, stack_commit = 0; + GROUP_AFFINITY *group_affinity = NULL; - if (attributes) FIXME("thread attributes ignored\n"); + if (attributes) + { + DWORD i; + for (i = 0; i < attributes->count; i++) + switch (attributes->attrs[i].attr) + { + case PROC_THREAD_ATTRIBUTE_GROUP_AFFINITY: + group_affinity = attributes->attrs[i].value; + break; + default: + FIXME("thread attributes %Ix ignored\n", attributes->attrs[i].attr); + break; + } + } if (flags & STACK_SIZE_PARAM_IS_A_RESERVATION) stack_reserve = stack; else stack_commit = stack; @@ -90,7 +120,13 @@ HANDLE WINAPI DECLSPEC_HOTPATCH CreateRemoteThreadEx( HANDLE process, SECURITY_A if (id) *id = HandleToULong( client_id.UniqueThread ); if (sa && sa->nLength >= sizeof(*sa) && sa->bInheritHandle) SetHandleInformation( handle, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT ); - if (!(flags & CREATE_SUSPENDED)) + if (group_affinity && !SetThreadGroupAffinity(handle, group_affinity, NULL)) + { + NtTerminateThread( handle, 0 ); + NtClose( handle ); + handle = 0; + } + else if (!(flags & CREATE_SUSPENDED)) { ULONG ret; if (NtResumeThread( handle, &ret )) -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/9271
Marc-Aurel Zent (@mzent) commented about include/winternl.h:
NTSYSAPI NTSTATUS WINAPI NtFsControlFile(HANDLE,HANDLE,PIO_APC_ROUTINE,PVOID,PIO_STATUS_BLOCK,ULONG,PVOID,ULONG,PVOID,ULONG); NTSYSAPI NTSTATUS WINAPI NtGetContextThread(HANDLE,CONTEXT*); NTSYSAPI ULONG WINAPI NtGetCurrentProcessorNumber(void); +NTSYSAPI ULONG WINAPI NtGetCurrentProcessorNumberEx(PROCESSOR_NUMBER*); FWIW `NtGetCurrentProcessorNumberEx()` is also a syscall.
-- https://gitlab.winehq.org/wine/wine/-/merge_requests/9271#note_120463
participants (3)
-
Eric Pouech -
eric pouech (@epo) -
Marc-Aurel Zent (@mzent)