[PATCH 2/5] kernelbase: Move FlsAlloc() implementation to ntdll.RtlFlsAlloc().

Paul Gofman pgofman at codeweavers.com
Tue Sep 29 15:15:29 CDT 2020


Signed-off-by: Paul Gofman <pgofman at codeweavers.com>
---
    The idea is to move FLS handling to ntdll as is first and then proceed with the missing bits:
        - maintain FLS storage list;
        - use dedicate lock instead of PEB lock;
        - call FLS callbacks.
    Apart from the Rtl functions introduced by this series there is also RtlProcessFlsData()
    which seems to serve as a cleanup for FLS data storage responsible for removing storage
    from the linked list, calling FLS callbacks and freeing storage memory.

 dlls/kernel32/tests/fiber.c | 42 ++++++++++++++++++++++++++++++++++++
 dlls/kernelbase/thread.c    | 33 ++++------------------------
 dlls/ntdll/ntdll.spec       |  1 +
 dlls/ntdll/thread.c         | 43 +++++++++++++++++++++++++++++++++++++
 include/winternl.h          |  1 +
 5 files changed, 91 insertions(+), 29 deletions(-)

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 <stdarg.h>
+
+#include <ntstatus.h>
+#define WIN32_NO_STATUS
+#include <winternl.h>
 #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..bdc7502632b 100644
--- a/dlls/kernelbase/thread.c
+++ b/dlls/kernelbase/thread.c
@@ -1065,39 +1065,14 @@ void WINAPI DECLSPEC_HOTPATCH SwitchToFiber( LPVOID fiber )
  */
 DWORD WINAPI DECLSPEC_HOTPATCH FlsAlloc( PFLS_CALLBACK_FUNCTION callback )
 {
+    NTSTATUS status;
     DWORD index;
-    PEB * const peb = NtCurrentTeb()->Peb;
 
-    RtlAcquirePebLock();
-    if (!peb->FlsCallback &&
-        !(peb->FlsCallback = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
-                                        8 * sizeof(peb->FlsBitmapBits) * sizeof(void*) )))
+    if ((status = RtlFlsAlloc( callback, &index )))
     {
-        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 );
+        set_ntstatus( status );
+        return FLS_OUT_OF_INDEXES;
     }
-    RtlReleasePebLock();
     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);
-- 
2.26.2




More information about the wine-devel mailing list