[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