kernel32/tests: Add tests for TLS functions.

This commit is contained in:
Dan Hipschman 2008-06-20 16:10:31 -07:00 committed by Alexandre Julliard
parent 1ad733e4e0
commit e22af18e7a
1 changed files with 228 additions and 0 deletions

View File

@ -21,6 +21,7 @@
/* Define _WIN32_WINNT to get SetThreadIdealProcessor on Windows */
#define _WIN32_WINNT 0x0500
#include <assert.h>
#include <stdarg.h>
#include <stdio.h>
@ -99,6 +100,57 @@ In addition there are no checks that the inheritance works properly in
CreateThread
*/
/* Functions to ensure that from a group of threads, only one executes
certain chunks of code at a time, and we know which one is executing
it. It basically makes multithreaded execution linear, which defeats
the purpose of multiple threads, but makes testing easy. */
static HANDLE all_synced;
static LONG num_syncing_threads, num_synced;
static void init_thread_sync_helpers(LONG num_threads)
{
all_synced = CreateEvent(NULL, FALSE, FALSE, NULL);
ok(all_synced != NULL, "CreateEvent failed\n");
num_syncing_threads = num_threads;
num_synced = 0;
}
static BOOL sync_threads_and_run_one(DWORD sync_id, DWORD my_id)
{
LONG num = InterlockedIncrement(&num_synced);
assert(0 < num && num <= num_syncing_threads);
if (num == num_syncing_threads)
/* FIXME: MSDN claims PulseEvent is unreliable. For a test this isn't
so important, but we could use condition variables with more effort.
The given approach is clearer, though. */
PulseEvent(all_synced);
else
{
DWORD ret = WaitForSingleObject(all_synced, 60000);
ok(ret == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
}
return sync_id == my_id;
}
static void resync_after_run(void)
{
LONG num = InterlockedDecrement(&num_synced);
assert(0 <= num && num < num_syncing_threads);
if (num == 0)
PulseEvent(all_synced);
else
{
DWORD ret = WaitForSingleObject(all_synced, 60000);
ok(ret == WAIT_OBJECT_0, "WaitForSingleObject failed\n");
}
}
static void cleanup_thread_sync_helpers(void)
{
CloseHandle(all_synced);
all_synced = NULL;
}
DWORD tlsIndex;
typedef struct {
@ -953,6 +1005,181 @@ 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 WINAPI TLS_InheritanceProc(LPVOID p)
{
/* We should NOT inherit the TLS values from our parent or from the
main thread. */
LPVOID val;
val = TlsGetValue(TLS_main);
ok(val == NULL, "TLS inheritance failed\n");
val = TlsGetValue(TLS_index0);
ok(val == NULL, "TLS inheritance failed\n");
val = TlsGetValue(TLS_index1);
ok(val == NULL, "TLS inheritance failed\n");
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)
{
LONG id = (LONG) p;
LPVOID val;
BOOL ret;
if (sync_threads_and_run_one(0, id))
{
TLS_index0 = TlsAlloc();
ok(TLS_index0 != TLS_OUT_OF_INDEXES, "TlsAlloc failed\n");
}
resync_after_run();
if (sync_threads_and_run_one(1, id))
{
TLS_index1 = TlsAlloc();
ok(TLS_index1 != TLS_OUT_OF_INDEXES, "TlsAlloc failed\n");
/* Slot indices should be different even if created in different
threads. */
ok(TLS_index0 != TLS_index1, "TlsAlloc failed\n");
/* 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 = TlsGetValue(TLS_index1);
ok(GetLastError() == ERROR_SUCCESS, "TlsGetValue failed\n");
ok(val == NULL, "TLS 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 = TlsGetValue(TLS_index1);
ok(GetLastError() == ERROR_SUCCESS, "TlsGetValue failed\n");
ok(val == NULL, "TLS slot not initialized correctly\n");
ret = TlsSetValue(TLS_index0, (LPVOID) 1);
ok(ret, "TlsSetValue failed\n");
ret = TlsSetValue(TLS_index1, (LPVOID) 2);
ok(ret, "TlsSetValue failed\n");
val = TlsGetValue(TLS_index0);
ok(GetLastError() == ERROR_SUCCESS, "TlsGetValue failed\n");
ok(val == (LPVOID) 1, "TLS 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");
}
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 = TlsGetValue(TLS_index1);
ok(GetLastError() == ERROR_SUCCESS, "TlsGetValue failed\n");
ok(val == NULL, "TLS slot not initialized correctly\n");
ret = TlsSetValue(TLS_index0, (LPVOID) 3);
ok(ret, "TlsSetValue failed\n");
ret = TlsSetValue(TLS_index1, (LPVOID) 4);
ok(ret, "TlsSetValue failed\n");
val = TlsGetValue(TLS_index0);
ok(GetLastError() == ERROR_SUCCESS, "TlsGetValue failed\n");
ok(val == (LPVOID) 3, "TLS 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");
}
resync_after_run();
if (sync_threads_and_run_one(0, id))
{
HANDLE thread;
DWORD waitret;
val = TlsGetValue(TLS_index0);
ok(GetLastError() == ERROR_SUCCESS, "TlsGetValue failed\n");
ok(val == (LPVOID) 1, "TLS 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");
thread = CreateThread(NULL, 0, TLS_InheritanceProc, 0, 0, NULL);
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");
}
resync_after_run();
if (sync_threads_and_run_one(1, id))
{
ret = TlsFree(TLS_index1);
ok(ret, "TlsFree failed\n");
}
resync_after_run();
return 0;
}
static void test_TLS(void)
{
HANDLE threads[2];
LONG i;
DWORD ret;
BOOL suc;
init_thread_sync_helpers(2);
/* 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");
for (i = 0; i < 2; ++i)
{
threads[i] = CreateThread(NULL, 0, TLS_ThreadProc, (LPVOID) i, 0, NULL);
ok(threads[i] != NULL, "CreateThread failed\n");
}
ret = WaitForMultipleObjects(2, threads, TRUE, 60000);
ok(ret == WAIT_OBJECT_0, "WaitForMultipleObjects failed\n");
for (i = 0; i < 2; ++i)
CloseHandle(threads[i]);
suc = TlsFree(TLS_main);
ok(suc, "TlsFree failed\n");
cleanup_thread_sync_helpers();
}
START_TEST(thread)
{
HINSTANCE lib;
@ -1012,4 +1239,5 @@ START_TEST(thread)
#endif
test_QueueUserWorkItem();
test_RegisterWaitForSingleObject();
test_TLS();
}