From 4e8f43f42307e74ec4e093eb83cb345dd6507ac0 Mon Sep 17 00:00:00 2001 From: John Sheu Date: Tue, 2 Aug 2016 15:55:44 -0700 Subject: [PATCH] kernel32/tests: Add thread tests for fiber-local storage. Signed-off-by: John Sheu Signed-off-by: Alexandre Julliard --- dlls/kernel32/tests/thread.c | 225 +++++++++++++++++++++++------------ 1 file changed, 148 insertions(+), 77 deletions(-) diff --git a/dlls/kernel32/tests/thread.c b/dlls/kernel32/tests/thread.c index b5ad1dad71..a9a04df85e 100644 --- a/dlls/kernel32/tests/thread.c +++ b/dlls/kernel32/tests/thread.c @@ -1247,31 +1247,56 @@ static void test_RegisterWaitForSingleObject(void) ok(ret, "UnregisterWait failed with error %d\n", GetLastError()); } -static DWORD TLS_main; -static DWORD TLS_index0, TLS_index1; +static DWORD LS_main; +static DWORD LS_index0, LS_index1; +static DWORD LS_OutOfIndexesValue; -static DWORD WINAPI TLS_InheritanceProc(LPVOID p) +/* Function pointers to the FLS/TLS functions to test in LS_ThreadProc() */ +static DWORD (WINAPI *LS_AllocFunc)(void); +static PVOID (WINAPI *LS_GetValueFunc)(DWORD); +static BOOL (WINAPI *LS_SetValueFunc)(DWORD, PVOID); +static BOOL (WINAPI *LS_FreeFunc)(DWORD); + +/* Names of the functions tested in LS_ThreadProc(), for error messages */ +static const char* LS_AllocFuncName = ""; +static const char* LS_GetValueFuncName = ""; +static const char* LS_SetValueFuncName = ""; +static const char* LS_FreeFuncName = ""; + +/* FLS entry points, dynamically loaded in platforms that support them */ +static DWORD (WINAPI *pFlsAlloc)(PFLS_CALLBACK_FUNCTION); +static BOOL (WINAPI *pFlsFree)(DWORD); +static PVOID (WINAPI *pFlsGetValue)(DWORD); +static BOOL (WINAPI *pFlsSetValue)(DWORD,PVOID); + +/* A thunk function to make FlsAlloc compatible with the signature of TlsAlloc */ +static DWORD WINAPI FLS_AllocFuncThunk(void) { - /* We should NOT inherit the TLS values from our parent or from the + return pFlsAlloc(NULL); +} + +static DWORD WINAPI LS_InheritanceProc(LPVOID p) +{ + /* We should NOT inherit the FLS/TLS values from our parent or from the main thread. */ LPVOID val; - val = TlsGetValue(TLS_main); - ok(val == NULL, "TLS inheritance failed\n"); + val = LS_GetValueFunc(LS_main); + ok(val == NULL, "%s inheritance failed\n", LS_GetValueFuncName); - val = TlsGetValue(TLS_index0); - ok(val == NULL, "TLS inheritance failed\n"); + val = LS_GetValueFunc(LS_index0); + ok(val == NULL, "%s inheritance failed\n", LS_GetValueFuncName); - val = TlsGetValue(TLS_index1); - ok(val == NULL, "TLS inheritance failed\n"); + val = LS_GetValueFunc(LS_index1); + ok(val == NULL, "%s inheritance failed\n", LS_GetValueFuncName); return 0; } -/* Basic TLS usage test. Make sure we can create slots and the values we - store in them are separate among threads. Also test TLS value - inheritance with TLS_InheritanceProc. */ -static DWORD WINAPI TLS_ThreadProc(LPVOID p) +/* Basic FLS/TLS usage test. Make sure we can create slots and the values we + store in them are separate among threads. Also test FLS/TLS value + inheritance with LS_InheritanceProc. */ +static DWORD WINAPI LS_ThreadProc(LPVOID p) { LONG_PTR id = (LONG_PTR) p; LPVOID val; @@ -1279,80 +1304,80 @@ static DWORD WINAPI TLS_ThreadProc(LPVOID p) if (sync_threads_and_run_one(0, id)) { - TLS_index0 = TlsAlloc(); - ok(TLS_index0 != TLS_OUT_OF_INDEXES, "TlsAlloc failed\n"); + LS_index0 = LS_AllocFunc(); + ok(LS_index0 != LS_OutOfIndexesValue, "%s failed\n", LS_AllocFuncName); } resync_after_run(); if (sync_threads_and_run_one(1, id)) { - TLS_index1 = TlsAlloc(); - ok(TLS_index1 != TLS_OUT_OF_INDEXES, "TlsAlloc failed\n"); + LS_index1 = LS_AllocFunc(); + ok(LS_index1 != LS_OutOfIndexesValue, "%s failed\n", LS_AllocFuncName); /* Slot indices should be different even if created in different threads. */ - ok(TLS_index0 != TLS_index1, "TlsAlloc failed\n"); + ok(LS_index0 != LS_index1, "%s failed\n", LS_AllocFuncName); /* Both slots should be initialized to NULL */ - val = TlsGetValue(TLS_index0); - ok(GetLastError() == ERROR_SUCCESS, "TlsGetValue failed\n"); - ok(val == NULL, "TLS slot not initialized correctly\n"); + val = LS_GetValueFunc(LS_index0); + ok(GetLastError() == ERROR_SUCCESS, "%s failed\n", LS_GetValueFuncName); + ok(val == NULL, "Slot not initialized correctly\n"); - val = TlsGetValue(TLS_index1); - ok(GetLastError() == ERROR_SUCCESS, "TlsGetValue failed\n"); - ok(val == NULL, "TLS slot not initialized correctly\n"); + val = LS_GetValueFunc(LS_index1); + ok(GetLastError() == ERROR_SUCCESS, "%s failed\n", LS_GetValueFuncName); + ok(val == NULL, "Slot not initialized correctly\n"); } resync_after_run(); if (sync_threads_and_run_one(0, id)) { - val = TlsGetValue(TLS_index0); - ok(GetLastError() == ERROR_SUCCESS, "TlsGetValue failed\n"); - ok(val == NULL, "TLS slot not initialized correctly\n"); + val = LS_GetValueFunc(LS_index0); + ok(GetLastError() == ERROR_SUCCESS, "%s failed\n", LS_GetValueFuncName); + ok(val == NULL, "Slot not initialized correctly\n"); - val = TlsGetValue(TLS_index1); - ok(GetLastError() == ERROR_SUCCESS, "TlsGetValue failed\n"); - ok(val == NULL, "TLS slot not initialized correctly\n"); + val = LS_GetValueFunc(LS_index1); + ok(GetLastError() == ERROR_SUCCESS, "%s failed\n", LS_GetValueFuncName); + ok(val == NULL, "Slot not initialized correctly\n"); - ret = TlsSetValue(TLS_index0, (LPVOID) 1); - ok(ret, "TlsSetValue failed\n"); + ret = LS_SetValueFunc(LS_index0, (LPVOID) 1); + ok(ret, "%s failed\n", LS_SetValueFuncName); - ret = TlsSetValue(TLS_index1, (LPVOID) 2); - ok(ret, "TlsSetValue failed\n"); + ret = LS_SetValueFunc(LS_index1, (LPVOID) 2); + ok(ret, "%s failed\n", LS_SetValueFuncName); - val = TlsGetValue(TLS_index0); - ok(GetLastError() == ERROR_SUCCESS, "TlsGetValue failed\n"); - ok(val == (LPVOID) 1, "TLS slot not initialized correctly\n"); + val = LS_GetValueFunc(LS_index0); + ok(GetLastError() == ERROR_SUCCESS, "%s failed\n", LS_GetValueFuncName); + ok(val == (LPVOID) 1, "Slot not initialized correctly\n"); - val = TlsGetValue(TLS_index1); - ok(GetLastError() == ERROR_SUCCESS, "TlsGetValue failed\n"); - ok(val == (LPVOID) 2, "TLS slot not initialized correctly\n"); + val = LS_GetValueFunc(LS_index1); + ok(GetLastError() == ERROR_SUCCESS, "%s failed\n", LS_GetValueFuncName); + ok(val == (LPVOID) 2, "Slot not initialized correctly\n"); } resync_after_run(); if (sync_threads_and_run_one(1, id)) { - val = TlsGetValue(TLS_index0); - ok(GetLastError() == ERROR_SUCCESS, "TlsGetValue failed\n"); - ok(val == NULL, "TLS slot not initialized correctly\n"); + val = LS_GetValueFunc(LS_index0); + ok(GetLastError() == ERROR_SUCCESS, "%s failed\n", LS_GetValueFuncName); + ok(val == NULL, "Slot not initialized correctly\n"); - val = TlsGetValue(TLS_index1); - ok(GetLastError() == ERROR_SUCCESS, "TlsGetValue failed\n"); - ok(val == NULL, "TLS slot not initialized correctly\n"); + val = LS_GetValueFunc(LS_index1); + ok(GetLastError() == ERROR_SUCCESS, "%s failed\n", LS_GetValueFuncName); + ok(val == NULL, "Slot not initialized correctly\n"); - ret = TlsSetValue(TLS_index0, (LPVOID) 3); - ok(ret, "TlsSetValue failed\n"); + ret = LS_SetValueFunc(LS_index0, (LPVOID) 3); + ok(ret, "%s failed\n", LS_SetValueFuncName); - ret = TlsSetValue(TLS_index1, (LPVOID) 4); - ok(ret, "TlsSetValue failed\n"); + ret = LS_SetValueFunc(LS_index1, (LPVOID) 4); + ok(ret, "%s failed\n", LS_SetValueFuncName); - val = TlsGetValue(TLS_index0); - ok(GetLastError() == ERROR_SUCCESS, "TlsGetValue failed\n"); - ok(val == (LPVOID) 3, "TLS slot not initialized correctly\n"); + val = LS_GetValueFunc(LS_index0); + ok(GetLastError() == ERROR_SUCCESS, "%s failed\n", LS_GetValueFuncName); + ok(val == (LPVOID) 3, "Slot not initialized correctly\n"); - val = TlsGetValue(TLS_index1); - ok(GetLastError() == ERROR_SUCCESS, "TlsGetValue failed\n"); - ok(val == (LPVOID) 4, "TLS slot not initialized correctly\n"); + val = LS_GetValueFunc(LS_index1); + ok(GetLastError() == ERROR_SUCCESS, "%s failed\n", LS_GetValueFuncName); + ok(val == (LPVOID) 4, "Slot not initialized correctly\n"); } resync_after_run(); @@ -1361,36 +1386,36 @@ static DWORD WINAPI TLS_ThreadProc(LPVOID p) HANDLE thread; DWORD waitret, tid; - val = TlsGetValue(TLS_index0); - ok(GetLastError() == ERROR_SUCCESS, "TlsGetValue failed\n"); - ok(val == (LPVOID) 1, "TLS slot not initialized correctly\n"); + val = LS_GetValueFunc(LS_index0); + ok(GetLastError() == ERROR_SUCCESS, "%s failed\n", LS_GetValueFuncName); + ok(val == (LPVOID) 1, "Slot not initialized correctly\n"); - val = TlsGetValue(TLS_index1); - ok(GetLastError() == ERROR_SUCCESS, "TlsGetValue failed\n"); - ok(val == (LPVOID) 2, "TLS slot not initialized correctly\n"); + val = LS_GetValueFunc(LS_index1); + ok(GetLastError() == ERROR_SUCCESS, "%s failed\n", LS_GetValueFuncName); + ok(val == (LPVOID) 2, "Slot not initialized correctly\n"); - thread = CreateThread(NULL, 0, TLS_InheritanceProc, 0, 0, &tid); + thread = CreateThread(NULL, 0, LS_InheritanceProc, 0, 0, &tid); ok(thread != NULL, "CreateThread failed\n"); waitret = WaitForSingleObject(thread, 60000); ok(waitret == WAIT_OBJECT_0, "WaitForSingleObject failed\n"); CloseHandle(thread); - ret = TlsFree(TLS_index0); - ok(ret, "TlsFree failed\n"); + ret = LS_FreeFunc(LS_index0); + ok(ret, "%s failed\n", LS_FreeFuncName); } resync_after_run(); if (sync_threads_and_run_one(1, id)) { - ret = TlsFree(TLS_index1); - ok(ret, "TlsFree failed\n"); + ret = LS_FreeFunc(LS_index1); + ok(ret, "%s failed\n", LS_FreeFuncName); } resync_after_run(); return 0; } -static void test_TLS(void) +static void run_LS_tests(void) { HANDLE threads[2]; LONG_PTR i; @@ -1399,17 +1424,17 @@ static void test_TLS(void) init_thread_sync_helpers(); - /* Allocate a TLS slot in the main thread to test for inheritance. */ - TLS_main = TlsAlloc(); - ok(TLS_main != TLS_OUT_OF_INDEXES, "TlsAlloc failed\n"); - suc = TlsSetValue(TLS_main, (LPVOID) 4114); - ok(suc, "TlsSetValue failed\n"); + /* Allocate a slot in the main thread to test for inheritance. */ + LS_main = LS_AllocFunc(); + ok(LS_main != LS_OutOfIndexesValue, "%s failed\n", LS_AllocFuncName); + suc = LS_SetValueFunc(LS_main, (LPVOID) 4114); + ok(suc, "%s failed\n", LS_SetValueFuncName); for (i = 0; i < 2; ++i) { DWORD tid; - threads[i] = CreateThread(NULL, 0, TLS_ThreadProc, (LPVOID) i, 0, &tid); + threads[i] = CreateThread(NULL, 0, LS_ThreadProc, (LPVOID) i, 0, &tid); ok(threads[i] != NULL, "CreateThread failed\n"); } @@ -1419,11 +1444,51 @@ static void test_TLS(void) for (i = 0; i < 2; ++i) CloseHandle(threads[i]); - suc = TlsFree(TLS_main); - ok(suc, "TlsFree failed\n"); + suc = LS_FreeFunc(LS_main); + ok(suc, "%s failed\n", LS_FreeFuncName); cleanup_thread_sync_helpers(); } +static void test_TLS(void) +{ + LS_OutOfIndexesValue = TLS_OUT_OF_INDEXES; + + LS_AllocFunc = &TlsAlloc; + LS_GetValueFunc = &TlsGetValue; + LS_SetValueFunc = &TlsSetValue; + LS_FreeFunc = &TlsFree; + + LS_AllocFuncName = "TlsAlloc"; + LS_GetValueFuncName = "TlsGetValue"; + LS_SetValueFuncName = "TlsSetValue"; + LS_FreeFuncName = "TlsFree"; + + run_LS_tests(); +} + +static void test_FLS(void) +{ + if (!pFlsAlloc || !pFlsFree || !pFlsGetValue || !pFlsSetValue) + { + win_skip("Fiber Local Storage not supported\n"); + return; + } + + LS_OutOfIndexesValue = FLS_OUT_OF_INDEXES; + + LS_AllocFunc = &FLS_AllocFuncThunk; + LS_GetValueFunc = pFlsGetValue; + LS_SetValueFunc = pFlsSetValue; + LS_FreeFunc = pFlsFree; + + LS_AllocFuncName = "FlsAlloc"; + LS_GetValueFuncName = "FlsGetValue"; + LS_SetValueFuncName = "FlsSetValue"; + LS_FreeFuncName = "FlsFree"; + + run_LS_tests(); +} + static void test_ThreadErrorMode(void) { DWORD oldmode; @@ -1945,6 +2010,11 @@ static void init_funcs(void) X(GetThreadGroupAffinity); X(SetThreadGroupAffinity); + + X(FlsAlloc); + X(FlsFree); + X(FlsSetValue); + X(FlsGetValue); #undef X #define X(f) p##f = (void*)GetProcAddress(ntdll, #f) @@ -2010,6 +2080,7 @@ START_TEST(thread) test_QueueUserWorkItem(); test_RegisterWaitForSingleObject(); test_TLS(); + test_FLS(); test_ThreadErrorMode(); #if (defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))) || (defined(_MSC_VER) && defined(__i386__)) test_thread_fpu_cw();