tests: Add windows threading test support
diff --git a/tests/layer_validation_tests.cpp b/tests/layer_validation_tests.cpp
index ddf65d5..5ee66ae 100644
--- a/tests/layer_validation_tests.cpp
+++ b/tests/layer_validation_tests.cpp
@@ -74,38 +74,36 @@
 public:
     ErrorMonitor()
     {
-        pthread_mutexattr_t attr;
-        pthread_mutexattr_init(&attr);
-        pthread_mutex_init(&m_mutex, &attr);
-        pthread_mutex_lock(&m_mutex);
+        test_platform_thread_create_mutex(&m_mutex);
+        test_platform_thread_lock_mutex(&m_mutex);
         m_msgFlags = VK_DBG_REPORT_INFO_BIT;
         m_bailout = NULL;
-        pthread_mutex_unlock(&m_mutex);
+        test_platform_thread_unlock_mutex(&m_mutex);
     }
     void ClearState()
     {
-        pthread_mutex_lock(&m_mutex);
+        test_platform_thread_lock_mutex(&m_mutex);
         m_msgFlags = VK_DBG_REPORT_INFO_BIT;
         m_msgString.clear();
-        pthread_mutex_unlock(&m_mutex);
+        test_platform_thread_unlock_mutex(&m_mutex);
     }
     VkFlags GetState(std::string *msgString)
     {
-        pthread_mutex_lock(&m_mutex);
+        test_platform_thread_lock_mutex(&m_mutex);
         *msgString = m_msgString;
-        pthread_mutex_unlock(&m_mutex);
+        test_platform_thread_unlock_mutex(&m_mutex);
         return m_msgFlags;
     }
     void SetState(VkFlags msgFlags, const char *msgString)
     {
-        pthread_mutex_lock(&m_mutex);
+        test_platform_thread_lock_mutex(&m_mutex);
         if (m_bailout != NULL) {
             *m_bailout = true;
         }
         m_msgFlags = msgFlags;
         m_msgString.reserve(strlen(msgString));
         m_msgString = msgString;
-        pthread_mutex_unlock(&m_mutex);
+        test_platform_thread_unlock_mutex(&m_mutex);
     }
     void SetBailout(bool *bailout)
     {
@@ -113,10 +111,10 @@
     }
 
 private:
-    VkFlags                m_msgFlags;
-    std::string            m_msgString;
-    pthread_mutex_t        m_mutex;
-    bool*                  m_bailout;
+    VkFlags                    m_msgFlags;
+    std::string                m_msgString;
+    test_platform_thread_mutex m_mutex;
+    bool*                      m_bailout;
 };
 
 static void myDbgFunc(
@@ -2261,8 +2259,7 @@
 {
     VkFlags msgFlags;
     std::string msgString;
-    pthread_t thread;
-    pthread_attr_t thread_attr;
+    test_platform_thread thread;
 
     ASSERT_NO_FATAL_FAILURE(InitState());
     ASSERT_NO_FATAL_FAILURE(InitViewport());
@@ -2271,7 +2268,6 @@
     VkCommandBufferObj cmdBuffer(m_device);
 
     m_errorMonitor->ClearState();
-    pthread_attr_init(&thread_attr);
     BeginCommandBuffer(cmdBuffer);
 
     VkEventCreateInfo event_info;
@@ -2293,10 +2289,10 @@
     data.bailout = false;
     m_errorMonitor->SetBailout(&data.bailout);
     // Add many entries to command buffer from another thread.
-    pthread_create(&thread, &thread_attr, AddToCommandBuffer, (void *)&data);
+    test_platform_thread_create(&thread, AddToCommandBuffer, (void *)&data);
     // Add many entries to command buffer from this thread at the same time.
     AddToCommandBuffer(&data);
-    pthread_join(thread, NULL);
+    test_platform_thread_join(thread, NULL);
     EndCommandBuffer(cmdBuffer);
 
     msgFlags = m_errorMonitor->GetState(&msgString);
diff --git a/tests/test_common.h b/tests/test_common.h
index cc2acbf..fe59415 100644
--- a/tests/test_common.h
+++ b/tests/test_common.h
@@ -67,4 +67,136 @@
     ADD_FAILURE_AT(file, line) << "Assertion: `" << expr << "'";
 }
 
+#if defined(__linux__)
+/* Linux-specific common code: */
+
+#include <pthread.h>
+
+// Threads:
+typedef pthread_t test_platform_thread;
+
+static inline int test_platform_thread_create(test_platform_thread *thread, void *(* func) (void*), void *data)
+{
+    pthread_attr_t thread_attr;
+    pthread_attr_init(&thread_attr);
+    return pthread_create(thread, &thread_attr, func, data);
+}
+static inline int test_platform_thread_join(test_platform_thread thread, void **retval)
+{
+    return pthread_join(thread, retval);
+}
+
+// Thread IDs:
+typedef pthread_t test_platform_thread_id;
+static inline test_platform_thread_id test_platform_get_thread_id()
+{
+    return pthread_self();
+}
+
+// Thread mutex:
+typedef pthread_mutex_t test_platform_thread_mutex;
+static inline void test_platform_thread_create_mutex(test_platform_thread_mutex* pMutex)
+{
+    pthread_mutex_init(pMutex, NULL);
+}
+static inline void test_platform_thread_lock_mutex(test_platform_thread_mutex* pMutex)
+{
+    pthread_mutex_lock(pMutex);
+}
+static inline void test_platform_thread_unlock_mutex(test_platform_thread_mutex* pMutex)
+{
+    pthread_mutex_unlock(pMutex);
+}
+static inline void test_platform_thread_delete_mutex(test_platform_thread_mutex* pMutex)
+{
+    pthread_mutex_destroy(pMutex);
+}
+typedef pthread_cond_t test_platform_thread_cond;
+static inline void test_platform_thread_init_cond(test_platform_thread_cond* pCond)
+{
+    pthread_cond_init(pCond, NULL);
+}
+static inline void test_platform_thread_cond_wait(test_platform_thread_cond* pCond, test_platform_thread_mutex* pMutex)
+{
+    pthread_cond_wait(pCond, pMutex);
+}
+static inline void test_platform_thread_cond_broadcast(test_platform_thread_cond* pCond)
+{
+    pthread_cond_broadcast(pCond);
+}
+
+#elif defined(_WIN32) // defined(__linux__)
+/* Windows-specific common code: */
+#include <winsock2.h>
+#include <windows.h>
+
+// Threads:
+typedef HANDLE test_platform_thread;
+static inline int test_platform_thread_create(test_platform_thread *thread, void *(* func) (void *), void *data)
+{
+    DWORD threadID;
+    *thread = CreateThread(NULL,           // default security attributes
+              0,                           // use default stack size
+              (LPTHREAD_START_ROUTINE)func,
+              data,                        // thread function argument
+              0,                           // use default creation flags
+              &threadID);                  // returns thread identifier
+    return (*thread != NULL);
+}
+static inline int test_platform_thread_join(test_platform_thread thread, void **retval)
+{
+    return WaitForSingleObject(thread, INFINITE);
+}
+
+// Thread IDs:
+typedef DWORD test_platform_thread_id;
+static test_platform_thread_id test_platform_get_thread_id()
+{
+    return GetCurrentThreadId();
+}
+
+// Thread mutex:
+typedef CRITICAL_SECTION test_platform_thread_mutex;
+static void test_platform_thread_create_mutex(test_platform_thread_mutex* pMutex)
+{
+    InitializeCriticalSection(pMutex);
+}
+static void test_platform_thread_lock_mutex(test_platform_thread_mutex* pMutex)
+{
+    EnterCriticalSection(pMutex);
+}
+static void test_platform_thread_unlock_mutex(test_platform_thread_mutex* pMutex)
+{
+    LeaveCriticalSection(pMutex);
+}
+static void test_platform_thread_delete_mutex(test_platform_thread_mutex* pMutex)
+{
+    DeleteCriticalSection(pMutex);
+}
+typedef CONDITION_VARIABLE test_platform_thread_cond;
+static void test_platform_thread_init_cond(test_platform_thread_cond* pCond)
+{
+    InitializeConditionVariable(pCond);
+}
+static void test_platform_thread_cond_wait(test_platform_thread_cond* pCond, test_platform_thread_mutex* pMutex)
+{
+    SleepConditionVariableCS(pCond, pMutex, INFINITE);
+}
+static void test_platform_thread_cond_broadcast(test_platform_thread_cond* pCond)
+{
+    WakeAllConditionVariable(pCond);
+}
+#else // defined(_WIN32)
+
+#error The "test_common.h" file must be modified for this OS.
+
+// NOTE: In order to support another OS, an #elif needs to be added (above the
+// "#else // defined(_WIN32)") for that OS, and OS-specific versions of the
+// contents of this file must be created.
+
+// NOTE: Other OS-specific changes are also needed for this OS.  Search for
+// files with "WIN32" in it, as a quick way to find files that must be changed.
+
+#endif // defined(_WIN32)
+
 #endif // TEST_COMMON_H