Signed-off-by: Paul Gofman pgofman@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;