ntdll: Call FLS callbacks.

Signed-off-by: Paul Gofman <pgofman@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Paul Gofman 2020-10-09 05:51:27 +03:00 committed by Alexandre Julliard
parent 7341f4ad1e
commit ec1ea1ea1b
4 changed files with 120 additions and 33 deletions

View File

@ -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;

View File

@ -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(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)
{
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);
}
}
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());

View File

@ -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;

View File

@ -374,7 +374,7 @@ NTSTATUS WINAPI DECLSPEC_HOTPATCH RtlFlsAlloc( PFLS_CALLBACK_FUNCTION callback,
}
++chunk->count;
chunk->callbacks[index].callback = callback ? callback : (void *)~(ULONG_PTR)0;
chunk->callbacks[index].callback = callback ? callback : (PFLS_CALLBACK_FUNCTION)~(ULONG_PTR)0;
if ((*ret_index = fls_index_from_chunk_index( chunk_index, index )) > fls_data.fls_high_index)
fls_data.fls_high_index = *ret_index;
@ -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;