From 8640a24b09c369534b2741ea879307c9807a3289 Mon Sep 17 00:00:00 2001
From: Dan Kegel <dank@kegel.com>
Date: Wed, 17 Oct 2012 09:15:06 -0700
Subject: [PATCH 4/6] vcomp: implement omp_in_parallel

---
 dlls/vcomp/fork.c       |   21 ++++++++++++++++++++
 dlls/vcomp/main.c       |   15 ++++++++++++++
 dlls/vcomp/tests/fork.c |   49 +++++++++++++++++++++++++++++++++++++++++++++++
 dlls/vcomp/vcomp.spec   |    2 +-
 4 files changed, 86 insertions(+), 1 deletions(-)

diff --git a/dlls/vcomp/fork.c b/dlls/vcomp/fork.c
index 13a7b56..284853d 100644
--- a/dlls/vcomp/fork.c
+++ b/dlls/vcomp/fork.c
@@ -26,6 +26,15 @@
 #include "winbase.h"
 #include "wine/debug.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);
+}
+
 WINE_DEFAULT_DEBUG_CHANNEL(vcomp);
 
 void CDECL _vcomp_fork_call_wrapper(void *wrapper, int nargs, __ms_va_list args);
@@ -75,9 +84,14 @@ void CDECL _vcomp_fork_call_wrapper(void *wrapper, int nargs, __ms_va_list args)
 void WINAPIV _vcomp_fork(BOOL ifval, int nargs, void *wrapper, ...)
 {
     __ms_va_list valist;
+    struct vcomp_team team;
+
     TRACE("(%d, %d, %p, ...)\n", ifval, nargs, wrapper);
+    team.parent = (struct vcomp_team *) TlsGetValue(vcomp_context_tls_idx);
+    TlsSetValue(vcomp_context_tls_idx, &team);
     __ms_va_start(valist, wrapper);
     _vcomp_fork_call_wrapper(wrapper, nargs, valist);
+    TlsSetValue(vcomp_context_tls_idx, team.parent);
     __ms_va_end(valist);
 }
 
@@ -159,3 +173,10 @@ void CDECL _vcomp_fork_call_wrapper(void *wrapper, int nargs, __ms_va_list args)
 }
 
 #endif
+
+int CDECL omp_in_parallel(void)
+{
+    int val = (vcomp_get_team() != NULL);
+    TRACE("returning %d\n", val);
+    return val;
+}
diff --git a/dlls/vcomp/main.c b/dlls/vcomp/main.c
index 38b76da..0cf0e29 100644
--- a/dlls/vcomp/main.c
+++ b/dlls/vcomp/main.c
@@ -29,6 +29,8 @@
 
 WINE_DEFAULT_DEBUG_CHANNEL(vcomp);
 
+DWORD vcomp_context_tls_idx;
+
 int CDECL omp_get_dynamic(void)
 {
     TRACE("stub\n");
@@ -117,8 +119,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/fork.c b/dlls/vcomp/tests/fork.c
index 7e4e9d6..f12d124 100644
--- a/dlls/vcomp/tests/fork.c
+++ b/dlls/vcomp/tests/fork.c
@@ -22,6 +22,9 @@
 
 static void WINAPIV (*p_vcomp_fork)(BOOL ifval, int nargs, void *wrapper, ...);
 static int CDECL (*pomp_get_max_threads)(void);
+static int CDECL (*pomp_get_num_threads)(void);
+static int CDECL (*pomp_in_parallel)(void);
+static void CDECL (*pomp_set_num_threads)(int);
 
 #define GETFUNC(x) do { p##x = (void*)GetProcAddress(vcomp, #x); ok(p##x != NULL, "Export '%s' not found\n", #x); } while(0)
 
@@ -33,6 +36,9 @@ static BOOL init(void)
         return FALSE;
     }
 
+    GETFUNC(omp_get_num_threads);
+    GETFUNC(omp_in_parallel);
+    GETFUNC(omp_set_num_threads);
     GETFUNC(_vcomp_fork);
     GETFUNC(omp_get_max_threads);
 
@@ -138,6 +144,48 @@ static void test_vcomp_fork_float(void)
     p_vcomp_fork_f5(TRUE, 5, _test_vcomp_fork_float_worker, 1.5f, 2.5f, 3.5f, 4.5f, 5.5f);
 }
 
+#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;
+    LONG volatile ncalls;
+
+    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(fork)
 {
     if (!init())
@@ -146,4 +194,5 @@ START_TEST(fork)
     test_vcomp_fork_ptr();
     test_vcomp_fork_uintptr();
     test_vcomp_fork_float();
+    test_omp_in_parallel();
 }
diff --git a/dlls/vcomp/vcomp.spec b/dlls/vcomp/vcomp.spec
index 8bc66e8..156233f 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)
-- 
1.7.4.1

