From e52bac386a69e57c303fdd3dede2f5f35138ed6d Mon Sep 17 00:00:00 2001
From: Dan Kegel <dank@kegel.com>
Date: Sat, 29 Sep 2012 03:46:56 -0700
Subject: [PATCH 07/14] vcomp: better stub for _vcomp_fork

---
 configure.ac                    |    3 +-
 dlls/vcomp/Makefile.in          |    1 +
 dlls/vcomp/fork.c               |  157 +++++++++++++++++++++++++++++++++++++++
 dlls/vcomp/tests/Makefile.in    |   10 +++
 dlls/vcomp/tests/fork.c         |   81 ++++++++++++++++++++
 dlls/vcomp/tests/vcomp.manifest |   21 ++++++
 dlls/vcomp/tests/vcomp.rc       |   22 ++++++
 dlls/vcomp/vcomp.spec           |    2 +-
 8 files changed, 295 insertions(+), 2 deletions(-)
 create mode 100644 dlls/vcomp/fork.c
 create mode 100644 dlls/vcomp/tests/Makefile.in
 create mode 100644 dlls/vcomp/tests/fork.c
 create mode 100644 dlls/vcomp/tests/vcomp.manifest
 create mode 100644 dlls/vcomp/tests/vcomp.rc

diff --git a/configure.ac b/configure.ac
index 79b1175..d83a01f 100644
--- a/configure.ac
+++ b/configure.ac
@@ -3001,7 +3001,8 @@ WINE_CONFIG_DLL(uxtheme,,[implib])
 WINE_CONFIG_TEST(dlls/uxtheme/tests)
 WINE_CONFIG_DLL(vbscript)
 WINE_CONFIG_TEST(dlls/vbscript/tests)
-WINE_CONFIG_DLL(vcomp)
+WINE_CONFIG_DLL(vcomp,,[implib])
+WINE_CONFIG_TEST(dlls/vcomp/tests)
 WINE_CONFIG_DLL(vcomp100)
 WINE_CONFIG_DLL(vcomp90)
 WINE_CONFIG_DLL(vdhcp.vxd,enable_win16)
diff --git a/dlls/vcomp/Makefile.in b/dlls/vcomp/Makefile.in
index d256526..971cf0f 100644
--- a/dlls/vcomp/Makefile.in
+++ b/dlls/vcomp/Makefile.in
@@ -1,6 +1,7 @@
 MODULE = vcomp.dll
 
 C_SRCS = \
+	fork.c \
 	main.c
 
 @MAKE_DLL_RULES@
diff --git a/dlls/vcomp/fork.c b/dlls/vcomp/fork.c
new file mode 100644
index 0000000..47a3f7f
--- /dev/null
+++ b/dlls/vcomp/fork.c
@@ -0,0 +1,157 @@
+/*
+ * vcomp fork/join implementation
+ *
+ * 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
+ */
+
+#include "config.h"
+
+#include <stdarg.h>
+
+#include "windef.h"
+#include "winbase.h"
+#include "wine/debug.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(vcomp);
+
+void WINAPIV _vcomp_fork(DWORD parallel, int nargs, void *helper, ...);
+void CDECL _vcomp_fork_body(DWORD parallel, int nargs, void *helper, DWORD *args);
+void CDECL _vcomp_fork_call_helper(void *helper, int nargs, DWORD *args);
+
+
+/* Marshal helper's arguments into array, then call _vcomp_fork_body.
+ * The helper's arguments are always pointers, never floating point numbers.
+ */
+
+#ifdef __i386__
+/* Happily, on x86, we can write the first part in C, too. */
+void WINAPIV _vcomp_fork(DWORD parallel, int nargs, void *helper, ...)
+{
+    va_list valist;
+    va_start(valist, helper);
+    _vcomp_fork_body(parallel, nargs, helper, (DWORD *)valist);
+    va_end(valist);
+}
+#endif
+
+#ifdef __x86_64__
+/* on entry: rcx = parallel, rdx = nargs, r8 = helper, r9 = 1st vararg
+ * The varargs are always pointers.
+ */
+__ASM_GLOBAL_FUNC(_vcomp_fork,
+    "pushq %rbp\n\t"
+    __ASM_CFI(".cfi_adjust_cfa_offset 8\n\t")
+    __ASM_CFI(".cfi_rel_offset %rbp,0\n\t")
+    "movq %rsp,%rbp\n\t"
+    __ASM_CFI(".cfi_def_cfa_register %rbp\n\t")
+    "movq %r9,40(%rbp)\n\t"   /* 1st vararg to shadow area */
+    "leaq 40(%rbp),%r9\n\t"    /* addr of 1st vararg */
+    "callq _vcomp_fork_body\n\t"
+    __ASM_CFI(".cfi_def_cfa_register %rsp\n\t")
+    "popq %rbp\n\t"
+    __ASM_CFI(".cfi_adjust_cfa_offset -8\n\t")
+    __ASM_CFI(".cfi_same_value %rbp\n\t")
+    "ret\n")
+#endif
+
+
+/* Do the actual forking and joining */
+
+void CDECL _vcomp_fork_body(DWORD parallel, int nargs, void *helper, DWORD *args)
+{
+    TRACE("(%d, %d, %p, %p): stub\n", parallel, nargs, helper, args);
+    _vcomp_fork_call_helper(helper, nargs, args);
+}
+
+
+/* Push the arguments back onto the stack, and call the helper
+ * function (usually generated by the visual c compiler)
+ * for this parallel section.
+ */
+
+#ifdef __i386__
+__ASM_GLOBAL_FUNC(_vcomp_fork_call_helper,
+    "pushl %ebp\n\t"
+    __ASM_CFI(".cfi_adjust_cfa_offset 4\n\t")
+    __ASM_CFI(".cfi_rel_offset %ebp,0\n\t")
+    "movl %esp,%ebp\n\t"
+    __ASM_CFI(".cfi_def_cfa_register %ebp\n\t")
+    "pushl %esi\n\t"
+    __ASM_CFI(".cfi_rel_offset %esi,-4\n\t")
+    "pushl %edi\n\t"
+    __ASM_CFI(".cfi_rel_offset %edi,-8\n\t")
+    "movl 12(%ebp),%edx\n\t"      /* edx = nargs */
+    "movl %esp,%edi\n\t"
+    "shll $2,%edx\n\t"
+    "jz 1f\n\t"                   /* if (((edx *= sizeof(int))) != 0) */
+    "subl %edx,%edi\n\t"              /* reserve space for copy of varargs */
+    "andl $~15,%edi\n\t"              /* pad if needed for 16 byte alignmnt */
+    "movl %edi,%esp\n\t"              /* esp as if we had pushed varargs */
+    "movl 12(%ebp),%ecx\n\t"          /* ecx = nargs */
+    "movl 16(%ebp),%esi\n\t"          /* si -> first vararg to copy */
+    "cld\n\t"
+    "rep; movsl\n"
+    "1:\tcall *8(%ebp)\n\t"
+    "leal -8(%ebp),%esp\n\t"
+    "popl %edi\n\t"
+    __ASM_CFI(".cfi_same_value %edi\n\t")
+    "popl %esi\n\t"
+    __ASM_CFI(".cfi_same_value %esi\n\t")
+    "popl %ebp\n\t"
+    __ASM_CFI(".cfi_def_cfa %esp,4\n\t")
+    __ASM_CFI(".cfi_same_value %ebp\n\t")
+    "ret\n")
+#endif
+
+#ifdef __x86_64__
+/* on entry: rcx = helper, rdx = nargs, r8 = adr of args */
+__ASM_GLOBAL_FUNC(_vcomp_fork_call_helper,
+    "pushq %rbp\n\t"
+    __ASM_CFI(".cfi_adjust_cfa_offset 8\n\t")
+    __ASM_CFI(".cfi_rel_offset %rbp,0\n\t")
+    "movq %rsp,%rbp\n\t"
+    __ASM_CFI(".cfi_def_cfa_register %rbp\n\t")
+    "pushq %rsi\n\t"
+    __ASM_CFI(".cfi_rel_offset %rsi,-8\n\t")
+    "pushq %rdi\n\t"
+    __ASM_CFI(".cfi_rel_offset %rdi,-16\n\t")
+    "movq %rcx,%rax\n\t"
+    "movq $4,%rcx\n\t"
+    "cmp %rcx,%rdx\n\t"
+    "cmovgq %rdx,%rcx\n\t"
+    "leaq 0(,%rcx,8),%rdx\n\t"
+    "subq %rdx,%rsp\n\t"
+    "andq $~15,%rsp\n\t"
+    "movq %rsp,%rdi\n\t"
+    "movq %r8,%rsi\n\t"
+    "rep; movsq\n\t"
+    "movq 0(%rsp),%rcx\n\t"
+    "movq 8(%rsp),%rdx\n\t"
+    "movq 16(%rsp),%r8\n\t"
+    "movq 24(%rsp),%r9\n\t"
+    "callq *%rax\n\t"
+    "leaq -16(%rbp),%rsp\n\t"
+    "popq %rdi\n\t"
+    __ASM_CFI(".cfi_same_value %rdi\n\t")
+    "popq %rsi\n\t"
+    __ASM_CFI(".cfi_same_value %rsi\n\t")
+    __ASM_CFI(".cfi_def_cfa_register %rsp\n\t")
+    "popq %rbp\n\t"
+    __ASM_CFI(".cfi_adjust_cfa_offset -8\n\t")
+    __ASM_CFI(".cfi_same_value %rbp\n\t")
+    "ret\n")
+#endif
diff --git a/dlls/vcomp/tests/Makefile.in b/dlls/vcomp/tests/Makefile.in
new file mode 100644
index 0000000..7a2e103
--- /dev/null
+++ b/dlls/vcomp/tests/Makefile.in
@@ -0,0 +1,10 @@
+TESTDLL = vcomp.dll
+IMPORTS = vcomp
+
+C_SRCS = \
+	fork.c
+
+RC_SRCS = \
+	vcomp.rc
+
+@MAKE_TEST_RULES@
diff --git a/dlls/vcomp/tests/fork.c b/dlls/vcomp/tests/fork.c
new file mode 100644
index 0000000..447c853
--- /dev/null
+++ b/dlls/vcomp/tests/fork.c
@@ -0,0 +1,81 @@
+/*
+ * Unit test suite for vcomp fork/join implementation
+ *
+ * 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
+ */
+
+#include "wine/test.h"
+
+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)
+
+static BOOL init(void)
+{
+    HMODULE vcomp = LoadLibraryA("vcomp.dll");
+    if(!vcomp) {
+        win_skip("vcomp.dll not installed\n");
+        return FALSE;
+    }
+
+    GETFUNC(_vcomp_fork);
+
+    return TRUE;
+}
+
+static LONG volatile ncalls;
+
+static void __cdecl _test_vcomp_fork_worker1(LONG volatile *p)
+{
+    if (p == 0) {
+        ok(p != 0, "oops, p is NULL\n");
+    }
+    InterlockedIncrement(p);
+}
+
+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);
+    ok(c == 3, "expected c == 3, got %d\n", c);
+    ok(d == 4, "expected d == 4, got %d\n", d);
+    ok(e == 5, "expected e == 5, got %d\n", d);
+    InterlockedIncrement(&ncalls);
+}
+
+static void test_vcomp_fork(void)
+{
+    ncalls = 0;
+    p_vcomp_fork(0, 1, _test_vcomp_fork_worker1, &ncalls);
+    ok(ncalls == 1, "expected 1 call, got %d\n", ncalls);
+
+    ncalls = 0;
+    p_vcomp_fork(0, 5, _test_vcomp_fork_worker5, 1, 2, 3, 4, 5);
+    ok(ncalls == 1, "expected 1 call, got %d\n", ncalls);
+
+    ncalls = 0;
+    p_vcomp_fork(1, 5, _test_vcomp_fork_worker5, 1, 2, 3, 4, 5);
+    ok(ncalls >= 1, "expected >= 1 call, got %d\n", ncalls);
+}
+
+START_TEST(fork)
+{
+    if (!init())
+        return;
+
+    test_vcomp_fork();
+}
diff --git a/dlls/vcomp/tests/vcomp.manifest b/dlls/vcomp/tests/vcomp.manifest
new file mode 100644
index 0000000..6c8bd91
--- /dev/null
+++ b/dlls/vcomp/tests/vcomp.manifest
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
+  <assemblyIdentity
+      type="win32"
+      name="Wine.vcomp.Test"
+      version="1.0.0.0"
+      processorArchitecture="*"
+  />
+<description>Wine vcomp test suite</description>
+<dependency>
+  <dependentAssembly>
+    <assemblyIdentity
+        type="win32"
+        name="Microsoft.VC80.OpenMP"
+        version="8.0.50608.0"
+        processorArchitecture="*"
+        publicKeyToken="1fc8b3b9a1e18e3b"
+    />
+  </dependentAssembly>
+</dependency>
+</assembly>
diff --git a/dlls/vcomp/tests/vcomp.rc b/dlls/vcomp/tests/vcomp.rc
new file mode 100644
index 0000000..c5f1d25
--- /dev/null
+++ b/dlls/vcomp/tests/vcomp.rc
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 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
+ */
+
+#include "winuser.h"
+
+/* @makedep: vcomp.manifest */
+1 RT_MANIFEST vcomp.manifest
diff --git a/dlls/vcomp/vcomp.spec b/dlls/vcomp/vcomp.spec
index 41b57fb..1378c8d 100644
--- a/dlls/vcomp/vcomp.spec
+++ b/dlls/vcomp/vcomp.spec
@@ -64,7 +64,7 @@
 @ stub _vcomp_for_static_init_i8
 @ stub _vcomp_for_static_simple_init
 @ stub _vcomp_for_static_simple_init_i8
-@ stub _vcomp_fork
+@ varargs _vcomp_fork(long long ptr)
 @ stub _vcomp_get_thread_num
 @ stub _vcomp_leave_critsect
 @ stub _vcomp_master_barrier
-- 
1.7.9.5

