diff --git a/dlls/kernel32/tests/fiber.c b/dlls/kernel32/tests/fiber.c index db2bd0923b7..b058dae7491 100644 --- a/dlls/kernel32/tests/fiber.c +++ b/dlls/kernel32/tests/fiber.c @@ -18,6 +18,11 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ +#include + +#include +#define WIN32_NO_STATUS +#include #include "wine/test.h" static LPVOID (WINAPI *pCreateFiber)(SIZE_T,LPFIBER_START_ROUTINE,LPVOID); @@ -32,6 +37,7 @@ static DWORD (WINAPI *pFlsAlloc)(PFLS_CALLBACK_FUNCTION); static BOOL (WINAPI *pFlsFree)(DWORD); static PVOID (WINAPI *pFlsGetValue)(DWORD); static BOOL (WINAPI *pFlsSetValue)(DWORD,PVOID); +static NTSTATUS (WINAPI *pRtlFlsAlloc)(PFLS_CALLBACK_FUNCTION,DWORD*); static void *fibers[3]; static BYTE testparam = 185; @@ -44,6 +50,7 @@ static int cbCount = 0; static VOID init_funcs(void) { HMODULE hKernel32 = GetModuleHandleA("kernel32.dll"); + HMODULE hntdll = GetModuleHandleA("ntdll.dll"); #define X(f) p##f = (void*)GetProcAddress(hKernel32, #f); X(CreateFiber); @@ -59,6 +66,11 @@ static VOID init_funcs(void) X(FlsGetValue); X(FlsSetValue); #undef X + +#define X(f) p##f = (void*)GetProcAddress(hntdll, #f); + X(RtlFlsAlloc); +#undef X + } static VOID WINAPI FiberLocalStorageProc(PVOID lpFlsData) @@ -171,9 +183,14 @@ static void test_FiberHandling(void) if (pIsThreadAFiber) ok(!pIsThreadAFiber(), "IsThreadAFiber reported TRUE\n"); } +#define FLS_TEST_INDEX_COUNT 4096 + static void test_FiberLocalStorage(void) { + static DWORD fls_indices[FLS_TEST_INDEX_COUNT]; + unsigned int i, count; DWORD fls, fls_2; + NTSTATUS status; BOOL ret; void* val; @@ -183,6 +200,31 @@ static void test_FiberLocalStorage(void) return; } + if (pRtlFlsAlloc) + { + for (i = 0; i < FLS_TEST_INDEX_COUNT; ++i) + { + fls_indices[i] = 0xdeadbeef; + status = pRtlFlsAlloc(NULL, &fls_indices[i]); + ok(!status || status == STATUS_NO_MEMORY, "Got unexpected status %#x.\n", status); + if (status) + { + ok(fls_indices[i] == 0xdeadbeef, "Got unexpected index %#x.\n", fls_indices[i]); + break; + } + } + count = i; + /* FLS limits are increased since Win10 18312. */ + ok(count && (count <= 127 || (count > 4000 && count < 4096)), "Got unexpected count %u.\n", count); + + for (i = 0; i < count; ++i) + pFlsFree(fls_indices[i]); + } + else + { + win_skip("RtlFlsAlloc is not available.\n"); + } + /* Test an unallocated index * FlsFree should fail * FlsGetValue and FlsSetValue should succeed diff --git a/dlls/kernelbase/thread.c b/dlls/kernelbase/thread.c index f20d460d07d..c302bbd1b85 100644 --- a/dlls/kernelbase/thread.c +++ b/dlls/kernelbase/thread.c @@ -1066,38 +1066,8 @@ void WINAPI DECLSPEC_HOTPATCH SwitchToFiber( LPVOID fiber ) DWORD WINAPI DECLSPEC_HOTPATCH FlsAlloc( PFLS_CALLBACK_FUNCTION callback ) { DWORD index; - PEB * const peb = NtCurrentTeb()->Peb; - RtlAcquirePebLock(); - if (!peb->FlsCallback && - !(peb->FlsCallback = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, - 8 * sizeof(peb->FlsBitmapBits) * sizeof(void*) ))) - { - SetLastError( ERROR_NOT_ENOUGH_MEMORY ); - index = FLS_OUT_OF_INDEXES; - } - else - { - index = RtlFindClearBitsAndSet( peb->FlsBitmap, 1, 1 ); - if (index != ~0U) - { - if (!NtCurrentTeb()->FlsSlots && - !(NtCurrentTeb()->FlsSlots = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, - 8 * sizeof(peb->FlsBitmapBits) * sizeof(void*) ))) - { - RtlClearBits( peb->FlsBitmap, index, 1 ); - index = FLS_OUT_OF_INDEXES; - SetLastError( ERROR_NOT_ENOUGH_MEMORY ); - } - else - { - NtCurrentTeb()->FlsSlots[index] = 0; /* clear the value */ - peb->FlsCallback[index] = callback; - } - } - else SetLastError( ERROR_NO_MORE_ITEMS ); - } - RtlReleasePebLock(); + if (!set_ntstatus( RtlFlsAlloc( callback, &index ))) return FLS_OUT_OF_INDEXES; return index; } diff --git a/dlls/ntdll/ntdll.spec b/dlls/ntdll/ntdll.spec index 0ec73d3d1d5..aac2af26f36 100644 --- a/dlls/ntdll/ntdll.spec +++ b/dlls/ntdll/ntdll.spec @@ -666,6 +666,7 @@ @ stdcall RtlFindSetRuns(ptr ptr long long) @ stdcall RtlFirstEntrySList(ptr) @ stdcall RtlFirstFreeAce(ptr ptr) +@ stdcall RtlFlsAlloc(ptr ptr) @ stub RtlFlushPropertySet # @ stub RtlFlushSecureMemoryCache @ stdcall RtlFormatCurrentUserKeyPath(ptr) diff --git a/dlls/ntdll/thread.c b/dlls/ntdll/thread.c index 0f31fe18a7d..f277a52dc06 100644 --- a/dlls/ntdll/thread.c +++ b/dlls/ntdll/thread.c @@ -246,3 +246,46 @@ TEB_ACTIVE_FRAME * WINAPI RtlGetFrame(void) { return NtCurrentTeb()->ActiveFrame; } + + +/*********************************************************************** + * Fibers + ***********************************************************************/ + + +/*********************************************************************** + * RtlFlsAlloc (NTDLL.@) + */ +NTSTATUS WINAPI DECLSPEC_HOTPATCH RtlFlsAlloc( PFLS_CALLBACK_FUNCTION callback, DWORD *ret_index ) +{ + PEB * const peb = NtCurrentTeb()->Peb; + NTSTATUS status = STATUS_NO_MEMORY; + DWORD index; + + RtlAcquirePebLock(); + if (peb->FlsCallback || + (peb->FlsCallback = RtlAllocateHeap( GetProcessHeap(), HEAP_ZERO_MEMORY, + 8 * sizeof(peb->FlsBitmapBits) * sizeof(void*) ))) + { + index = RtlFindClearBitsAndSet( peb->FlsBitmap, 1, 1 ); + if (index != ~0U) + { + if (!NtCurrentTeb()->FlsSlots && + !(NtCurrentTeb()->FlsSlots = RtlAllocateHeap( GetProcessHeap(), HEAP_ZERO_MEMORY, + 8 * sizeof(peb->FlsBitmapBits) * sizeof(void*) ))) + { + RtlClearBits( peb->FlsBitmap, index, 1 ); + } + else + { + NtCurrentTeb()->FlsSlots[index] = 0; /* clear the value */ + peb->FlsCallback[index] = callback; + status = STATUS_SUCCESS; + } + } + } + RtlReleasePebLock(); + if (!status) + *ret_index = index; + return status; +} diff --git a/include/winternl.h b/include/winternl.h index 7be69b29014..ba9d9442590 100644 --- a/include/winternl.h +++ b/include/winternl.h @@ -3371,6 +3371,7 @@ NTSYSAPI ULONG WINAPI RtlFindSetBits(PCRTL_BITMAP,ULONG,ULONG); NTSYSAPI ULONG WINAPI RtlFindSetBitsAndClear(PRTL_BITMAP,ULONG,ULONG); NTSYSAPI ULONG WINAPI RtlFindSetRuns(PCRTL_BITMAP,PRTL_BITMAP_RUN,ULONG,BOOLEAN); NTSYSAPI BOOLEAN WINAPI RtlFirstFreeAce(PACL,PACE_HEADER *); +NTSYSAPI NTSTATUS WINAPI RtlFlsAlloc(PFLS_CALLBACK_FUNCTION,ULONG *); NTSYSAPI NTSTATUS WINAPI RtlFormatCurrentUserKeyPath(PUNICODE_STRING); NTSYSAPI NTSTATUS WINAPI RtlFormatMessage(LPCWSTR,ULONG,BOOLEAN,BOOLEAN,BOOLEAN,__ms_va_list *,LPWSTR,ULONG,ULONG*); NTSYSAPI NTSTATUS WINAPI RtlFormatMessageEx(LPCWSTR,ULONG,BOOLEAN,BOOLEAN,BOOLEAN,__ms_va_list *,LPWSTR,ULONG,ULONG*,ULONG);