[PATCH 2/2] ntdll: Call FLS callbacks.

Paul Gofman pgofman at codeweavers.com
Thu Oct 8 21:51:27 CDT 2020


Signed-off-by: Paul Gofman <pgofman at codeweavers.com>
---
 dlls/kernel32/tests/fiber.c  | 24 +++++++++--
 dlls/kernel32/tests/loader.c | 79 ++++++++++++++++++++++++++----------
 dlls/ntdll/loader.c          |  8 +++-
 dlls/ntdll/thread.c          | 38 +++++++++++++++--
 4 files changed, 118 insertions(+), 31 deletions(-)

diff --git a/dlls/kernel32/tests/fiber.c b/dlls/kernel32/tests/fiber.c
index 30f9152c39e..1b5d0d1393a 100644
--- a/dlls/kernel32/tests/fiber.c
+++ b/dlls/kernel32/tests/fiber.c
@@ -223,8 +223,11 @@ static unsigned int check_linked_list(const LIST_ENTRY *le, const LIST_ENTRY *se
     return count;
 }
 
+static unsigned int test_fls_callback_call_count;
+
 static void WINAPI test_fls_callback(void *data)
 {
+    ++test_fls_callback_call_count;
 }
 
 static unsigned int test_fls_chunk_size(unsigned int chunk_index)
@@ -377,8 +380,11 @@ static void test_FiberLocalStorage(void)
             ok(status == STATUS_INVALID_PARAMETER, "Got unexpected status %#x.\n", status);
 
             g_fls_data->fls_callback_chunks[j]->callbacks[index].callback = test_fls_callback;
+            test_fls_callback_call_count = 0;
             status = pRtlFlsFree(fls_indices[0x10]);
             ok(!status, "Got unexpected status %#x.\n", status);
+            ok(test_fls_callback_call_count == 1, "Got unexpected callback call count %u.\n",
+                    test_fls_callback_call_count);
 
             ok(!fls_data->fls_data_chunks[j][0], "Got unexpected fls_data->fls_data_chunks[%u][0] %p.\n",
                     j, fls_data->fls_data_chunks[j][0]);
@@ -405,7 +411,7 @@ static void test_FiberLocalStorage(void)
             ok(val == (void *)0xdeadbeef, "Got unexpected val %p.\n", val);
             ok(!new_fls_data, "Got unexpected teb->FlsSlots %p.\n", new_fls_data);
 
-            status = pRtlFlsSetValue(fls_indices[1], NULL);
+            status = pRtlFlsSetValue(fls_indices[1], (void *)(ULONG_PTR)0x28);
             new_fls_data = teb->FlsSlots;
             ok(!status, "Got unexpected status %#x.\n", status);
             ok(!!new_fls_data, "Got unexpected teb->FlsSlots %p.\n", new_fls_data);
@@ -450,11 +456,15 @@ static void test_FiberLocalStorage(void)
             ok(result == WAIT_OBJECT_0, "Got unexpected result %u.\n", result);
             teb->FlsSlots = NULL;
 
+            test_fls_callback_call_count = 0;
             saved_entry = new_fls_data->fls_list_entry;
             pRtlProcessFlsData(new_fls_data, 1);
             ok(!teb->FlsSlots, "Got unexpected teb->FlsSlots %p.\n", teb->FlsSlots);
 
             teb->FlsSlots = fls_data;
+            ok(test_fls_callback_call_count == 1, "Got unexpected callback call count %u.\n",
+                    test_fls_callback_call_count);
+
             SetEvent(test_fiberlocalstorage_done_event);
             WaitForSingleObject(hthread, INFINITE);
             CloseHandle(hthread);
@@ -467,7 +477,13 @@ static void test_FiberLocalStorage(void)
                     saved_entry.Blink);
             size = HeapSize(GetProcessHeap(), 0, new_fls_data);
             ok(size == sizeof(*new_fls_data), "Got unexpected size %p.\n", (void *)size);
+            test_fls_callback_call_count = 0;
+            i = test_fls_chunk_index_from_index(fls_indices[1], &index);
+            new_fls_data->fls_data_chunks[i][index + 1] = (void *)(ULONG_PTR)0x28;
             pRtlProcessFlsData(new_fls_data, 2);
+            ok(!test_fls_callback_call_count, "Got unexpected callback call count %u.\n",
+                    test_fls_callback_call_count);
+
             if (0)
             {
                 /* crashes on Windows. */
@@ -676,7 +692,7 @@ static void test_FiberLocalStorageCallback(PFLS_CALLBACK_FUNCTION cbfunc)
 
     ret = pFlsFree( fls );
     ok(ret, "FlsFree failed with error %u\n", GetLastError() );
-    todo_wine ok( cbCount == 1, "Wrong callback count: %d\n", cbCount );
+    ok( cbCount == 1, "Wrong callback count: %d\n", cbCount );
 
     /* Test that callback is not executed if value is NULL */
     cbCount = 0;
@@ -741,14 +757,14 @@ static void test_FiberLocalStorageWithFibers(PFLS_CALLBACK_FUNCTION cbfunc)
     fls_value_to_set = val1;
     pDeleteFiber(fibers[1]);
     ok(fiberCount == 0, "Wrong fiber count: %d\n", fiberCount);
-    todo_wine ok(cbCount == 1, "Wrong callback count: %d\n", cbCount);
+    ok(cbCount == 1, "Wrong callback count: %d\n", cbCount);
 
     fiberCount = 0;
     cbCount = 0;
     fls_value_to_set = val2;
     pFlsFree(fls_index_to_set);
     ok(fiberCount == 0, "Wrong fiber count: %d\n", fiberCount);
-    todo_wine ok(cbCount == 2, "Wrong callback count: %d\n", cbCount);
+    ok(cbCount == 2, "Wrong callback count: %d\n", cbCount);
 
     fiberCount = 0;
     cbCount = 0;
diff --git a/dlls/kernel32/tests/loader.c b/dlls/kernel32/tests/loader.c
index 8e8834239ba..67fd62ef6aa 100644
--- a/dlls/kernel32/tests/loader.c
+++ b/dlls/kernel32/tests/loader.c
@@ -2318,12 +2318,34 @@ static VOID WINAPI fls_callback(PVOID lpFlsData)
     InterlockedIncrement(&fls_callback_count);
 }
 
+static LIST_ENTRY *fls_list_head;
+
+static unsigned int check_linked_list(const LIST_ENTRY *le, const LIST_ENTRY *search_entry, unsigned int *index_found)
+{
+    unsigned int count = 0;
+    LIST_ENTRY *entry;
+
+    *index_found = ~0;
+
+    for (entry = le->Flink; entry != le; entry = entry->Flink)
+    {
+        if (entry == search_entry)
+        {
+            ok(*index_found == ~0, "Duplicate list entry.\n");
+            *index_found = count;
+        }
+        ++count;
+    }
+    return count;
+}
+
 static BOOL WINAPI dll_entry_point(HINSTANCE hinst, DWORD reason, LPVOID param)
 {
     static LONG noop_thread_started;
-    static DWORD fls_index = FLS_OUT_OF_INDEXES;
+    static DWORD fls_index = FLS_OUT_OF_INDEXES, fls_index2 = FLS_OUT_OF_INDEXES;
     static int fls_count = 0;
     static int thread_detach_count = 0;
+    static int thread_count;
     DWORD ret;
 
     ok(!inside_loader_lock, "inside_loader_lock should not be set\n");
@@ -2352,8 +2374,11 @@ static BOOL WINAPI dll_entry_point(HINSTANCE hinst, DWORD reason, LPVOID param)
             bret = pFlsSetValue(fls_index, (void*) 0x31415);
             ok(bret, "FlsSetValue failed\n");
             fls_count++;
-        }
 
+            fls_index2 = pFlsAlloc(&fls_callback);
+            ok(fls_index2 != FLS_OUT_OF_INDEXES, "FlsAlloc returned %d\n", ret);
+        }
+        ++thread_count;
         break;
     case DLL_PROCESS_DETACH:
     {
@@ -2423,18 +2448,12 @@ todo_wine
             void* value;
             SetLastError(0xdeadbeef);
             value = pFlsGetValue(fls_index);
-            todo_wine
-            {
-                ok(broken(value == (void*) 0x31415) || /* Win2k3 */
-                   value == NULL, "FlsGetValue returned %p, expected NULL\n", value);
-            }
+            ok(broken(value == (void*) 0x31415) || /* Win2k3 */
+                value == NULL, "FlsGetValue returned %p, expected NULL\n", value);
             ok(GetLastError() == ERROR_SUCCESS, "FlsGetValue failed with error %u\n", GetLastError());
-            todo_wine
-            {
-                ok(broken(fls_callback_count == thread_detach_count) || /* Win2k3 */
-                   fls_callback_count == thread_detach_count + 1,
-                   "wrong FLS callback count %d, expected %d\n", fls_callback_count, thread_detach_count + 1);
-            }
+            ok(broken(fls_callback_count == thread_detach_count) || /* Win2k3 */
+                fls_callback_count == thread_detach_count + 1,
+                "wrong FLS callback count %d, expected %d\n", fls_callback_count, thread_detach_count + 1);
         }
         if (pFlsFree)
         {
@@ -2443,11 +2462,8 @@ todo_wine
             ret = pFlsFree(fls_index);
             ok(ret, "FlsFree failed with error %u\n", GetLastError());
             fls_index = FLS_OUT_OF_INDEXES;
-            todo_wine
-            {
-                ok(fls_callback_count == fls_count,
-                   "wrong FLS callback count %d, expected %d\n", fls_callback_count, fls_count);
-            }
+            ok(fls_callback_count == fls_count,
+                "wrong FLS callback count %d, expected %d\n", fls_callback_count, fls_count);
         }
 
         ok(attached_thread_count >= 2, "attached thread count should be >= 2\n");
@@ -2611,6 +2627,8 @@ todo_wine
     case DLL_THREAD_ATTACH:
         trace("dll: %p, DLL_THREAD_ATTACH, %p\n", hinst, param);
 
+        ++thread_count;
+
         ret = pRtlDllShutdownInProgress();
         ok(!ret, "RtlDllShutdownInProgress returned %d\n", ret);
 
@@ -2638,6 +2656,7 @@ todo_wine
         break;
     case DLL_THREAD_DETACH:
         trace("dll: %p, DLL_THREAD_DETACH, %p\n", hinst, param);
+        --thread_count;
         thread_detach_count++;
 
         ret = pRtlDllShutdownInProgress();
@@ -2656,15 +2675,25 @@ todo_wine
          */
         if (pFlsGetValue && fls_index != FLS_OUT_OF_INDEXES)
         {
+            unsigned int index, count;
             void* value;
+            BOOL bret;
+
             SetLastError(0xdeadbeef);
             value = pFlsGetValue(fls_index);
-            todo_wine
+            ok(broken(value == (void*) 0x31415) || /* Win2k3 */
+                !value, "FlsGetValue returned %p, expected NULL\n", value);
+            ok(GetLastError() == ERROR_SUCCESS, "FlsGetValue failed with error %u\n", GetLastError());
+
+            bret = pFlsSetValue(fls_index2, (void*) 0x31415);
+            ok(bret, "FlsSetValue failed\n");
+
+            if (fls_list_head)
             {
-                ok(broken(value == (void*) 0x31415) || /* Win2k3 */
-                   !value, "FlsGetValue returned %p, expected NULL\n", value);
+                count = check_linked_list(fls_list_head, &NtCurrentTeb()->FlsSlots->fls_list_entry, &index);
+                ok(count <= thread_count, "Got unexpected count %u, thread_count %u.\n", count, thread_count);
+                ok(index == ~0, "Got unexpected index %u.\n", index);
             }
-            ok(GetLastError() == ERROR_SUCCESS, "FlsGetValue failed with error %u\n", GetLastError());
         }
 
         break;
@@ -2689,6 +2718,12 @@ static void child_process(const char *dll_name, DWORD target_offset)
 
     trace("phase %d: writing %p at %#x\n", test_dll_phase, dll_entry_point, target_offset);
 
+    if (pFlsAlloc)
+    {
+        fls_list_head = NtCurrentTeb()->Peb->FlsListHead.Flink ? &NtCurrentTeb()->Peb->FlsListHead
+                : NtCurrentTeb()->FlsSlots->fls_list_entry.Flink;
+    }
+
     SetLastError(0xdeadbeef);
     mutex = CreateMutexW(NULL, FALSE, NULL);
     ok(mutex != 0, "CreateMutex error %d\n", GetLastError());
diff --git a/dlls/ntdll/loader.c b/dlls/ntdll/loader.c
index 8374dd97326..368448c9f8d 100644
--- a/dlls/ntdll/loader.c
+++ b/dlls/ntdll/loader.c
@@ -3194,6 +3194,10 @@ fail:
 void WINAPI LdrShutdownProcess(void)
 {
     TRACE("()\n");
+
+    if (!process_detaching)
+        RtlProcessFlsData( NtCurrentTeb()->FlsSlots, 1 );
+
     process_detaching = TRUE;
     process_detach();
 }
@@ -3228,6 +3232,8 @@ void WINAPI LdrShutdownThread(void)
     /* don't do any detach calls if process is exiting */
     if (process_detaching) return;
 
+    RtlProcessFlsData( NtCurrentTeb()->FlsSlots, 1 );
+
     RtlEnterCriticalSection( &loader_section );
     wm = get_modref( NtCurrentTeb()->Peb->ImageBaseAddress );
 
@@ -3254,7 +3260,7 @@ void WINAPI LdrShutdownThread(void)
         for (i = 0; i < tls_module_count; i++) RtlFreeHeap( GetProcessHeap(), 0, pointers[i] );
         RtlFreeHeap( GetProcessHeap(), 0, pointers );
     }
-    RtlProcessFlsData( NtCurrentTeb()->FlsSlots, 3 );
+    RtlProcessFlsData( NtCurrentTeb()->FlsSlots, 2 );
     NtCurrentTeb()->FlsSlots = NULL;
     RtlFreeHeap( GetProcessHeap(), 0, NtCurrentTeb()->TlsExpansionSlots );
     NtCurrentTeb()->TlsExpansionSlots = NULL;
diff --git a/dlls/ntdll/thread.c b/dlls/ntdll/thread.c
index 95511391d34..2926d6173bf 100644
--- a/dlls/ntdll/thread.c
+++ b/dlls/ntdll/thread.c
@@ -390,6 +390,7 @@ NTSTATUS WINAPI DECLSPEC_HOTPATCH RtlFlsAlloc( PFLS_CALLBACK_FUNCTION callback,
  */
 NTSTATUS WINAPI DECLSPEC_HOTPATCH RtlFlsFree( ULONG index )
 {
+    PFLS_CALLBACK_FUNCTION callback;
     unsigned int chunk_index, idx;
     FLS_INFO_CHUNK *chunk;
     LIST_ENTRY *entry;
@@ -404,7 +405,7 @@ NTSTATUS WINAPI DECLSPEC_HOTPATCH RtlFlsFree( ULONG index )
 
     chunk_index = fls_chunk_index_from_index( index, &idx );
     if (!(chunk = fls_data.fls_callback_chunks[chunk_index])
-            || !chunk->callbacks[idx].callback)
+            || !(callback = chunk->callbacks[idx].callback))
     {
         unlock_fls_data();
         return STATUS_INVALID_PARAMETER;
@@ -414,9 +415,15 @@ NTSTATUS WINAPI DECLSPEC_HOTPATCH RtlFlsFree( ULONG index )
     {
         TEB_FLS_DATA *fls = CONTAINING_RECORD(entry, TEB_FLS_DATA, fls_list_entry);
 
-        if (fls->fls_data_chunks[chunk_index])
+        if (fls->fls_data_chunks[chunk_index] && fls->fls_data_chunks[chunk_index][idx + 1])
         {
-            /* FIXME: call Fls callback */
+            if (callback != (void *)~(ULONG_PTR)0)
+            {
+                TRACE_(relay)("Calling FLS callback %p, arg %p.\n", callback,
+                        fls->fls_data_chunks[chunk_index][idx + 1]);
+
+                callback( fls->fls_data_chunks[chunk_index][idx + 1] );
+            }
             fls->fls_data_chunks[chunk_index][idx + 1] = NULL;
         }
     }
@@ -481,7 +488,7 @@ NTSTATUS WINAPI DECLSPEC_HOTPATCH RtlFlsGetValue( ULONG index, void **data )
 void WINAPI DECLSPEC_HOTPATCH RtlProcessFlsData( void *teb_fls_data, ULONG flags )
 {
     TEB_FLS_DATA *fls = teb_fls_data;
-    unsigned int i;
+    unsigned int i, index;
 
     TRACE_(thread)( "teb_fls_data %p, flags %#x.\n", teb_fls_data, flags );
 
@@ -494,6 +501,29 @@ void WINAPI DECLSPEC_HOTPATCH RtlProcessFlsData( void *teb_fls_data, ULONG flags
     if (flags & 1)
     {
         lock_fls_data();
+        for (i = 0; i < ARRAY_SIZE(fls->fls_data_chunks); ++i)
+        {
+            if (!fls->fls_data_chunks[i] || !fls_data.fls_callback_chunks[i]
+                    || !fls_data.fls_callback_chunks[i]->count)
+                continue;
+
+            for (index = 0; index < fls_chunk_size( i ); ++index)
+            {
+                PFLS_CALLBACK_FUNCTION callback = fls_data.fls_callback_chunks[i]->callbacks[index].callback;
+
+                if (!fls->fls_data_chunks[i][index + 1])
+                    continue;
+
+                if (callback && callback != (void *)~(ULONG_PTR)0)
+                {
+                    TRACE_(relay)("Calling FLS callback %p, arg %p.\n", callback,
+                            fls->fls_data_chunks[i][index + 1]);
+
+                    callback( fls->fls_data_chunks[i][index + 1] );
+                }
+                fls->fls_data_chunks[i][index + 1] = NULL;
+            }
+        }
         /* Not using RemoveEntryList() as Windows does not zero list entry here. */
         fls->fls_list_entry.Flink->Blink = fls->fls_list_entry.Blink;
         fls->fls_list_entry.Blink->Flink = fls->fls_list_entry.Flink;
-- 
2.26.2




More information about the wine-devel mailing list