Module: wine Branch: master Commit: 505be3a0a2afeae3cebeaad48fc5f32e0b0336b7 URL: https://source.winehq.org/git/wine.git/?a=commit;h=505be3a0a2afeae3cebeaad48...
Author: Alexandre Julliard julliard@winehq.org Date: Sat Aug 24 10:03:51 2019 +0200
kernelbase: Implement SetThreadStackGuarantee().
Signed-off-by: Alexandre Julliard julliard@winehq.org
---
dlls/kernel32/tests/thread.c | 58 ++++++++++++++++++++++++++++++++++++++++++++ dlls/kernelbase/thread.c | 15 ++++++++++-- include/winternl.h | 4 +-- 3 files changed, 73 insertions(+), 4 deletions(-)
diff --git a/dlls/kernel32/tests/thread.c b/dlls/kernel32/tests/thread.c index 331db9b..f87f770 100644 --- a/dlls/kernel32/tests/thread.c +++ b/dlls/kernel32/tests/thread.c @@ -82,6 +82,7 @@ static HANDLE (WINAPI *pOpenThread)(DWORD,BOOL,DWORD); static BOOL (WINAPI *pQueueUserWorkItem)(LPTHREAD_START_ROUTINE,PVOID,ULONG); static DWORD (WINAPI *pSetThreadIdealProcessor)(HANDLE,DWORD); static BOOL (WINAPI *pSetThreadPriorityBoost)(HANDLE,BOOL); +static BOOL (WINAPI *pSetThreadStackGuarantee)(ULONG*); static BOOL (WINAPI *pRegisterWaitForSingleObject)(PHANDLE,HANDLE,WAITORTIMERCALLBACK,PVOID,ULONG,ULONG); static BOOL (WINAPI *pUnregisterWait)(HANDLE); static BOOL (WINAPI *pIsWow64Process)(HANDLE,PBOOL); @@ -1016,6 +1017,61 @@ static VOID test_GetCurrentThreadStackLimits(void) ok(high == (ULONG_PTR)NtCurrentTeb()->Tib.StackBase, "expected %p, got %lx\n", NtCurrentTeb()->Tib.StackBase, high); }
+static void test_SetThreadStackGuarantee(void) +{ + ULONG size; + BOOL ret; + + if (!pSetThreadStackGuarantee) + { + win_skip("SetThreadStackGuarantee not available.\n"); + return; + } + size = 0; + ret = pSetThreadStackGuarantee( &size ); + ok( ret, "failed err %u\n", GetLastError() ); + ok( size == 0, "wrong size %u\n", size ); + ok( NtCurrentTeb()->GuaranteedStackBytes == 0, "wrong teb %u\n", + NtCurrentTeb()->GuaranteedStackBytes ); + size = 0xdeadbef; + ret = pSetThreadStackGuarantee( &size ); + ok( !ret, "succeeded\n" ); + ok( GetLastError() == ERROR_INVALID_PARAMETER || GetLastError() == ERROR_INVALID_ADDRESS, + "wrong error %u\n", GetLastError()); + ok( size == 0, "wrong size %u\n", size ); + ok( NtCurrentTeb()->GuaranteedStackBytes == 0, "wrong teb %u\n", + NtCurrentTeb()->GuaranteedStackBytes ); + size = 200; + ret = pSetThreadStackGuarantee( &size ); + ok( ret, "failed err %u\n", GetLastError() ); + ok( size == 0, "wrong size %u\n", size ); + ok( NtCurrentTeb()->GuaranteedStackBytes == 4096 * sizeof(void *) / 4, "wrong teb %u\n", + NtCurrentTeb()->GuaranteedStackBytes ); + size = 5000; + ret = pSetThreadStackGuarantee( &size ); + ok( ret, "failed err %u\n", GetLastError() ); + ok( size == 4096 * sizeof(void *) / 4, "wrong size %u\n", size ); + ok( NtCurrentTeb()->GuaranteedStackBytes == 8192, "wrong teb %u\n", + NtCurrentTeb()->GuaranteedStackBytes ); + size = 2000; + ret = pSetThreadStackGuarantee( &size ); + ok( ret, "failed err %u\n", GetLastError() ); + ok( size == 8192, "wrong size %u\n", size ); + ok( NtCurrentTeb()->GuaranteedStackBytes == 8192, "wrong teb %u\n", + NtCurrentTeb()->GuaranteedStackBytes ); + size = 10000; + ret = pSetThreadStackGuarantee( &size ); + ok( ret, "failed err %u\n", GetLastError() ); + ok( size == 8192, "wrong size %u\n", size ); + ok( NtCurrentTeb()->GuaranteedStackBytes == 12288, "wrong teb %u\n", + NtCurrentTeb()->GuaranteedStackBytes ); + ret = pSetThreadStackGuarantee( &size ); + ok( ret, "failed err %u\n", GetLastError() ); + ok( size == 12288, "wrong size %u\n", size ); + ok( NtCurrentTeb()->GuaranteedStackBytes == 12288, "wrong teb %u\n", + NtCurrentTeb()->GuaranteedStackBytes ); +} + static VOID test_GetThreadExitCode(void) { DWORD exitCode, threadid; @@ -2029,6 +2085,7 @@ static void init_funcs(void) X(QueueUserWorkItem); X(SetThreadIdealProcessor); X(SetThreadPriorityBoost); + X(SetThreadStackGuarantee); X(RegisterWaitForSingleObject); X(UnregisterWait); X(IsWow64Process); @@ -2110,6 +2167,7 @@ START_TEST(thread) test_CreateThread_stack(); test_thread_priority(); test_GetCurrentThreadStackLimits(); + test_SetThreadStackGuarantee(); test_GetThreadTimes(); test_thread_processor(); test_GetThreadExitCode(); diff --git a/dlls/kernelbase/thread.c b/dlls/kernelbase/thread.c index cf8e6be..518ea93 100644 --- a/dlls/kernelbase/thread.c +++ b/dlls/kernelbase/thread.c @@ -470,8 +470,19 @@ BOOL WINAPI DECLSPEC_HOTPATCH SetThreadPriorityBoost( HANDLE thread, BOOL disabl */ BOOL WINAPI DECLSPEC_HOTPATCH SetThreadStackGuarantee( ULONG *size ) { - static int once; - if (once++ == 0) FIXME("(%p): stub\n", size); + ULONG prev_size = NtCurrentTeb()->GuaranteedStackBytes; + ULONG new_size = (*size + 4095) & ~4095; + + /* at least 2 pages on 64-bit */ + if (sizeof(void *) > sizeof(int)) new_size = max( new_size, 8192 ); + + *size = prev_size; + if (new_size >= (char *)NtCurrentTeb()->Tib.StackBase - (char *)NtCurrentTeb()->DeallocationStack) + { + SetLastError( ERROR_INVALID_PARAMETER ); + return FALSE; + } + if (new_size > prev_size) NtCurrentTeb()->GuaranteedStackBytes = (new_size + 4095) & ~4095; return TRUE; }
diff --git a/include/winternl.h b/include/winternl.h index 0ebfe8e..4715b05 100644 --- a/include/winternl.h +++ b/include/winternl.h @@ -397,8 +397,8 @@ typedef struct _TEB PVOID WinSockData; /* f6c/1738 */ ULONG GdiBatchCount; /* f70/1740 */ ULONG Spare2; /* f74/1744 */ - PVOID Spare3; /* f78/1748 */ - PVOID Spare4; /* f7c/1750 */ + ULONG GuaranteedStackBytes; /* f78/1748 */ + PVOID ReservedForPerf; /* f7c/1750 */ PVOID ReservedForOle; /* f80/1758 */ ULONG WaitingOnLoaderLock; /* f84/1760 */ PVOID Reserved5[3]; /* f88/1768 */