Dan Hipschman : kernel32/tests: Add tests for TLS functions.

Alexandre Julliard julliard at winehq.org
Mon Jun 23 07:36:04 CDT 2008


Module: wine
Branch: master
Commit: e22af18e7a3b0b44512d780dc9ff664c63665dcd
URL:    http://source.winehq.org/git/wine.git/?a=commit;h=e22af18e7a3b0b44512d780dc9ff664c63665dcd

Author: Dan Hipschman <dsh at linux.ucla.edu>
Date:   Fri Jun 20 16:10:31 2008 -0700

kernel32/tests: Add tests for TLS functions.

---

 dlls/kernel32/tests/thread.c |  228 ++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 228 insertions(+), 0 deletions(-)

diff --git a/dlls/kernel32/tests/thread.c b/dlls/kernel32/tests/thread.c
index 7d83b25..d1ac617 100644
--- a/dlls/kernel32/tests/thread.c
+++ b/dlls/kernel32/tests/thread.c
@@ -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();
 }




More information about the wine-cvs mailing list