From 834bad439e59ae650b5cc658866794323da6a6a3 Mon Sep 17 00:00:00 2001
From: Dan Kegel <dank@kegel.com>
Date: Mon, 1 Oct 2012 20:27:32 -0700
Subject: [PATCH 10/14] vcomp: better stub for omp_in_parallel

---
 dlls/vcomp/fork.c          |   13 +++++++++++
 dlls/vcomp/main.c          |   15 +++++++++++++
 dlls/vcomp/tests/fork.c    |   52 ++++++++++++++++++++++++++++++++++++++++++--
 dlls/vcomp/vcomp.spec      |    2 +-
 dlls/vcomp/vcomp_private.h |   34 +++++++++++++++++++++++++++++
 5 files changed, 113 insertions(+), 3 deletions(-)
 create mode 100644 dlls/vcomp/vcomp_private.h

diff --git a/dlls/vcomp/fork.c b/dlls/vcomp/fork.c
index 47a3f7f..ca80c98 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,
 
 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);
 }
 
 
@@ -155,3 +161,10 @@ __ASM_GLOBAL_FUNC(_vcomp_fork_call_helper,
     __ASM_CFI(".cfi_same_value %rbp\n\t")
     "ret\n")
 #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 5faf0a1..9db3b9d 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");
@@ -101,8 +103,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 447c853..9c37271 100644
--- a/dlls/vcomp/tests/fork.c
+++ b/dlls/vcomp/tests/fork.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;
@@ -39,7 +45,7 @@ static BOOL init(void)
 
 static LONG volatile ncalls;
 
-static void __cdecl _test_vcomp_fork_worker1(LONG volatile *p)
+static void CDECL _test_vcomp_fork_worker1(LONG volatile *p)
 {
     if (p == 0) {
         ok(p != 0, "oops, p is NULL\n");
@@ -47,7 +53,7 @@ static void __cdecl _test_vcomp_fork_worker1(LONG volatile *p)
     InterlockedIncrement(p);
 }
 
-static void __cdecl _test_vcomp_fork_worker5(int a, int b, int c, int d, int e)
+static void CDECL _test_vcomp_fork_worker5(int a, int b, int c, int d, int e)
 {
     ok(a == 1, "expected a == 1, got %d\n", a);
     ok(b == 2, "expected b == 2, got %d\n", b);
@@ -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(fork)
 {
     if (!init())
         return;
 
     test_vcomp_fork();
+    test_omp_in_parallel();
 }
diff --git a/dlls/vcomp/vcomp.spec b/dlls/vcomp/vcomp.spec
index 8c8c51c..31e5b51 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

