Thread-safe testing framework

Francois Gouget fgouget at codeweavers.com
Sun Mar 31 20:55:54 CST 2002


   This patch should make the testing framework thread-safe.
   It does two things:
 * use Interlocked{Increment,Decrement} on the global counters
 * store the per-thread data in a thread local storage slot

   There is one last thing that could be added which is some
synchronization to prevent the test output from becoming mixed up (i.e.
typically traces and results from failed tests). But tests normally
print nothing or very little so I don't think it is really worth it.


Changelog:

   François Gouget <fgouget at codeweavers.com>

 * programs/winetest/wtmain.c

   Make the testing framework thread safe


-- 
François Gouget
fgouget at codeweavers.com
-------------- next part --------------
Index: programs/winetest/wtmain.c
===================================================================
RCS file: /home/wine/wine/programs/winetest/wtmain.c,v
retrieving revision 1.3
diff -u -r1.3 wtmain.c
--- programs/winetest/wtmain.c	22 Mar 2002 00:58:01 -0000	1.3
+++ programs/winetest/wtmain.c	30 Mar 2002 19:15:47 -0000
@@ -24,6 +24,7 @@
 #include <string.h>
 
 #include "wine/test.h"
+#include "winbase.h"
 
 /* debug level */
 int winetest_debug = 1;
@@ -39,18 +40,37 @@
 
 extern const struct test winetest_testlist[];
 static const struct test *current_test; /* test currently being run */
-/* FIXME: Access to all the following variables must be protected in a 
- * multithread test. Either via thread local storage or via critical sections
- */
-static const char* current_file;        /* file of current check */
-static int current_line;                /* line of current check */
 
-static int successes;         /* number of successful tests */
-static int failures;          /* number of failures */
-static int todo_successes;    /* number of successful tests inside todo block */
-static int todo_failures;     /* number of failures inside todo block */
-static int todo_level;        /* current todo nesting level */
-static int todo_do_loop;
+static LONG successes;       /* number of successful tests */
+static LONG failures;        /* number of failures */
+static LONG todo_successes;  /* number of successful tests inside todo block */
+static LONG todo_failures;   /* number of failures inside todo block */
+
+/* The following data must be kept track of on a per-thread basis */
+typedef struct
+{
+    const char* current_file;        /* file of current check */
+    int current_line;                /* line of current check */
+    int todo_level;                  /* current todo nesting level */
+    int todo_do_loop;
+} tls_data;
+static DWORD tls_index;
+
+tls_data* get_tls_data()
+{
+    tls_data* data;
+    DWORD last_error;
+
+    last_error=GetLastError();
+    data=TlsGetValue(tls_index);
+    if (!data)
+    {
+        data=HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(tls_data));
+        TlsSetValue(tls_index,data);
+    }
+    SetLastError(last_error);
+    return data;
+}
 
 /*
  * Checks condition.
@@ -65,13 +85,14 @@
 int winetest_ok( int condition, const char *msg, ... )
 {
     va_list valist;
+    tls_data* data=get_tls_data();
 
-    if (todo_level)
+    if (data->todo_level)
     {
         if (condition)
         {
             fprintf( stderr, "%s:%d: Test succeeded inside todo block",
-                     current_file, current_line );
+                     data->current_file, data->current_line );
             if (msg && msg[0])
             {
                 va_start(valist, msg);
@@ -80,17 +101,17 @@
                 va_end(valist);
             }
             fputc( '\n', stderr );
-            todo_failures++;
+            InterlockedIncrement(&todo_failures);
             return 0;
         }
-        else todo_successes++;
+        else InterlockedIncrement(&todo_successes);
     }
     else
     {
         if (!condition)
         {
             fprintf( stderr, "%s:%d: Test failed",
-                     current_file, current_line );
+                     data->current_file, data->current_line );
             if (msg && msg[0])
             {
                 va_start(valist, msg);
@@ -99,27 +120,30 @@
                 va_end(valist);
             }
             fputc( '\n', stderr );
-            failures++;
+            InterlockedIncrement(&failures);
             return 0;
         }
-        else successes++;
+        else InterlockedIncrement(&successes);
     }
     return 1;
 }
 
 winetest_ok_funcptr winetest_set_ok_location( const char* file, int line )
 {
-    current_file=file;
-    current_line=line;
+    tls_data* data=get_tls_data();
+    data->current_file=file;
+    data->current_line=line;
     return &winetest_ok;
 }
 
 void winetest_trace( const char *msg, ... )
 {
     va_list valist;
+    tls_data* data=get_tls_data();
 
     if (winetest_debug > 0)
     {
+        fprintf( stderr, "%s:%d:", data->current_file, data->current_line );
         va_start(valist, msg);
         vfprintf(stderr, msg, valist);
         va_end(valist);
@@ -128,29 +152,35 @@
 
 winetest_trace_funcptr winetest_set_trace_location( const char* file, int line )
 {
-    current_file=file;
-    current_line=line;
+    tls_data* data=get_tls_data();
+    data->current_file=file;
+    data->current_line=line;
     return &winetest_trace;
 }
 
 void winetest_start_todo( const char* platform )
 {
+    tls_data* data=get_tls_data();
     if (strcmp(winetest_platform,platform)==0)
-        todo_level++;
-    todo_do_loop=1;
+        data->todo_level++;
+    data->todo_do_loop=1;
 }
 
 int winetest_loop_todo(void)
 {
-    int do_loop=todo_do_loop;
-    todo_do_loop=0;
+    tls_data* data=get_tls_data();
+    int do_loop=data->todo_do_loop;
+    data->todo_do_loop=0;
     return do_loop;
 }
 
 void winetest_end_todo( const char* platform )
 {
     if (strcmp(winetest_platform,platform)==0)
-        todo_level--;
+    {
+        tls_data* data=get_tls_data();
+        data->todo_level--;
+    }
 }
 
 /* Find a test by name */
@@ -185,13 +215,13 @@
         exit(1);
     }
     successes = failures = todo_successes = todo_failures = 0;
-    todo_level = 0;
+    tls_index=TlsAlloc();
     current_test = test;
     test->func();
 
     if (winetest_debug)
     {
-        fprintf( stderr, "%s: %d tests executed, %d marked as todo, %d %s.\n",
+        fprintf( stderr, "%s: %ld tests executed, %ld marked as todo, %ld %s.\n",
                  name, successes + failures + todo_successes + todo_failures,
                  todo_successes, failures + todo_failures,
                  (failures + todo_failures != 1) ? "failures" : "failure" );


More information about the wine-patches mailing list