From 8cdd12f6dc0427d68d459daad3a83b2915495972 Mon Sep 17 00:00:00 2001
From: Dan Kegel <dank@kegel.com>
Date: Sat, 29 Sep 2012 09:12:44 -0700
Subject: [PATCH 08/14] vcomp: better stub for omp_in_parallel

---
 dlls/vcomp/fork.c          |    6 ++++++
 dlls/vcomp/main.c          |   23 +++++++++++++++++++++
 dlls/vcomp/tests/main.c    |   48 ++++++++++++++++++++++++++++++++++++++++++++
 dlls/vcomp/vcomp.spec      |    2 +-
 dlls/vcomp/vcomp_private.h |   34 +++++++++++++++++++++++++++++++
 5 files changed, 112 insertions(+), 1 deletion(-)
 create mode 100644 dlls/vcomp/vcomp_private.h

diff --git a/dlls/vcomp/fork.c b/dlls/vcomp/fork.c
index 1352385..c9a9af7 100644
--- a/dlls/vcomp/fork.c
+++ b/dlls/vcomp/fork.c
@@ -25,6 +25,7 @@
 #include "windef.h"
 #include "winbase.h"
 #include "wine/debug.h"
+#include "vcomp_private.h"
 
 WINE_DEFAULT_DEBUG_CHANNEL(vcomp);
 
@@ -73,8 +74,13 @@ __ASM_GLOBAL_FUNC(_vcomp_fork,
 
 static void __cdecl _vcomp_fork_body(DWORD parallel, int nargs, void *helper, DWORD *args)
 {
+    struct vcomp_team team;
+
     TRACE("(%d, %d, %p, %p): stub\n", parallel, nargs, helper, args);
+    team.parent = (struct vcomp_team *) TlsGetValue(vcomp_context_tls_idx);
+    TlsSetValue(vcomp_context_tls_idx, &team);
     _vcomp_fork_call_helper(helper, nargs, args);
+    TlsSetValue(vcomp_context_tls_idx, team.parent);
 }
 
 
diff --git a/dlls/vcomp/main.c b/dlls/vcomp/main.c
index 5faf0a1..957e45a 100644
--- a/dlls/vcomp/main.c
+++ b/dlls/vcomp/main.c
@@ -26,9 +26,12 @@
 #include "windef.h"
 #include "winbase.h"
 #include "wine/debug.h"
+#include "vcomp_private.h"
 
 WINE_DEFAULT_DEBUG_CHANNEL(vcomp);
 
+DWORD vcomp_context_tls_idx;
+
 int CDECL omp_get_dynamic(void)
 {
     TRACE("stub\n");
@@ -81,6 +84,13 @@ void CDECL omp_set_nested(int nested)
     TRACE("(%d): stub\n", nested);
 }
 
+int CDECL omp_in_parallel(void)
+{
+    int val = (vcomp_get_team() != NULL);
+    TRACE("returning %d\n", val);
+    return val;
+}
+
 void CDECL omp_set_num_threads(int num_threads)
 {
     TRACE("(%d): stub\n", num_threads);
@@ -101,8 +111,21 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
             return FALSE;    /* prefer native version */
         case DLL_PROCESS_ATTACH:
             DisableThreadLibraryCalls(hinstDLL);
+
+            vcomp_context_tls_idx = TlsAlloc();
+            if (vcomp_context_tls_idx == TLS_OUT_OF_INDEXES)
+            {
+                DWORD err = GetLastError();
+                ERR("Failed to allocate TLS index, err %#x.\n", err);
+                return FALSE;
+            }
             break;
         case DLL_PROCESS_DETACH:
+            if (!TlsFree(vcomp_context_tls_idx))
+            {
+                DWORD err = GetLastError();
+                ERR("Failed to free context TLS index, err %#x.\n", err);
+            }
             break;
     }
 
diff --git a/dlls/vcomp/tests/main.c b/dlls/vcomp/tests/main.c
index 1764b29..8dd66ed 100644
--- a/dlls/vcomp/tests/main.c
+++ b/dlls/vcomp/tests/main.c
@@ -20,6 +20,9 @@
 
 #include "wine/test.h"
 
+static int CDECL (*pomp_get_num_threads)(void);
+static int CDECL (*pomp_in_parallel)(void);
+static void CDECL (*pomp_set_num_threads)(int);
 static void WINAPIV (*p_vcomp_fork)(DWORD parallel, int nargs, void *helper, ...);
 
 #define GETFUNC(x) do { p##x = (void*)GetProcAddress(vcomp, #x); ok(p##x != NULL, "Export '%s' not found\n", #x); } while(0)
@@ -32,6 +35,9 @@ static BOOL init(void)
         return FALSE;
     }
 
+    GETFUNC(omp_get_num_threads);
+    GETFUNC(omp_in_parallel);
+    GETFUNC(omp_set_num_threads);
     GETFUNC(_vcomp_fork);
 
     return TRUE;
@@ -72,10 +78,52 @@ static void test_vcomp_fork(void)
     ok(ncalls >= 1, "expected >= 1 call, got %d\n", ncalls);
 }
 
+#define NLOOPS_SHORT 5
+#define SLEEP_MS_SHORT 50
+
+static void __cdecl _test_omp_in_parallel_nested_worker(LONG volatile *psum)
+{
+    if (pomp_in_parallel())
+        InterlockedIncrement(psum);
+}
+
+static void __cdecl _test_omp_in_parallel_worker(LONG volatile *psum)
+{
+    int i;
+    InterlockedIncrement(psum);
+    for (i=0; i<NLOOPS_SHORT; i++) {
+        p_vcomp_fork(1, 1, _test_omp_in_parallel_nested_worker, psum);
+        if (pomp_in_parallel())
+            InterlockedIncrement(psum);
+        Sleep(SLEEP_MS_SHORT);
+    }
+}
+
+static void test_omp_in_parallel(void)
+{
+    int par;
+    int old_nt;
+
+    old_nt = pomp_get_num_threads();
+    pomp_set_num_threads(1);
+
+    ncalls = 0;
+    p_vcomp_fork(1, 1, _test_omp_in_parallel_worker, &ncalls);
+
+    ok(ncalls == 1 + 2 * NLOOPS_SHORT,
+        "omp_in_parallel false in parallel region?!\n");
+
+    par = pomp_in_parallel();
+    ok(par == 0, "omp_in_parallel true outside parallel region?!\n");
+
+    pomp_set_num_threads(old_nt);
+}
+
 START_TEST(main)
 {
     if (!init())
         return;
 
     test_vcomp_fork();
+    test_omp_in_parallel();
 }
diff --git a/dlls/vcomp/vcomp.spec b/dlls/vcomp/vcomp.spec
index 1378c8d..39a1842 100644
--- a/dlls/vcomp/vcomp.spec
+++ b/dlls/vcomp/vcomp.spec
@@ -98,7 +98,7 @@
 @ cdecl omp_get_thread_num()
 @ stub omp_get_wtick
 @ cdecl omp_get_wtime()
-@ stub omp_in_parallel
+@ cdecl omp_in_parallel()
 @ stub omp_init_lock
 @ stub omp_init_nest_lock
 @ cdecl omp_set_dynamic(long)
diff --git a/dlls/vcomp/vcomp_private.h b/dlls/vcomp/vcomp_private.h
new file mode 100644
index 0000000..f71b55e
--- /dev/null
+++ b/dlls/vcomp/vcomp_private.h
@@ -0,0 +1,34 @@
+/*
+ * vcmp wine internal private include file
+ *
+ * Copyright 2012 Dan Kegel
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef __WINE_VCOMP_PRIVATE_H
+#define __WINE_VCOMP_PRIVATE_H
+
+struct vcomp_team {
+    struct vcomp_team *parent;
+};
+
+extern DWORD vcomp_context_tls_idx;
+static inline struct vcomp_team *vcomp_get_team(void)
+{
+    return (struct vcomp_team *)TlsGetValue(vcomp_context_tls_idx);
+}
+
+#endif
-- 
1.7.9.5

