diff --git a/README.md b/README.md index 8577bb63..a6ba6fca 100644 --- a/README.md +++ b/README.md @@ -38,11 +38,12 @@ Wine. All those differences are also documented on the Included bug fixes and improvements =================================== -**Bugfixes and features included in the next upcoming release [3]:** +**Bugfixes and features included in the next upcoming release [4]:** * Call DriverUnload function when unloading a device driver. * Fix check for end_frame in RtlUnwindEx on x86_64. ([Wine Bug #34254](https://bugs.winehq.org/show_bug.cgi?id=34254)) * Fix mouse jittering in Planetside 2 ([Wine Bug #32913](https://bugs.winehq.org/show_bug.cgi?id=32913)) +* Implement additional stubs for vcomp dlls ([Wine Bug #31640](https://bugs.winehq.org/show_bug.cgi?id=31640)) **Bugs fixed in Wine Staging 1.7.35 [146]:** diff --git a/debian/changelog b/debian/changelog index 5223acc4..92522647 100644 --- a/debian/changelog +++ b/debian/changelog @@ -2,6 +2,7 @@ wine-staging (1.7.36) UNRELEASED; urgency=low * Added patch to properly call DriverUnload when unloading device drivers. * Added patch to fix check for end_frame in RtlUnwindEx on x86_64. * Added patch to fix mouse jittering in Planetside 2. + * Added patch to implement additional stubs for vcomp dlls. -- Sebastian Lackner Sun, 25 Jan 2015 05:58:36 +0100 wine-staging (1.7.35) unstable; urgency=low diff --git a/patches/patchinstall.sh b/patches/patchinstall.sh index afde2576..80ee6d53 100755 --- a/patches/patchinstall.sh +++ b/patches/patchinstall.sh @@ -174,6 +174,7 @@ patch_enable_all () enable_user32_Mouse_Message_Hwnd="$1" enable_user32_ScrollWindowEx="$1" enable_user32_WndProc="$1" + enable_vcomp_Stub_Functions="$1" enable_windowscodecs_TGA_Decoder="$1" enable_wineboot_HKEY_DYN_DATA="$1" enable_winebuild_LinkerVersion="$1" @@ -542,6 +543,9 @@ patch_enable () user32-WndProc) enable_user32_WndProc="$2" ;; + vcomp-Stub_Functions) + enable_vcomp_Stub_Functions="$2" + ;; windowscodecs-TGA_Decoder) enable_windowscodecs_TGA_Decoder="$2" ;; @@ -2919,6 +2923,36 @@ if test "$enable_user32_WndProc" -eq 1; then ) >> "$patchlist" fi +# Patchset vcomp-Stub_Functions +# | +# | This patchset fixes the following Wine bugs: +# | * [#31640] Implement additional stubs for vcomp dlls +# | +# | Modified files: +# | * configure.ac, dlls/vcomp/Makefile.in, dlls/vcomp/fork.c, dlls/vcomp/main.c, dlls/vcomp/tests/Makefile.in, +# | dlls/vcomp/tests/fork.c, dlls/vcomp/tests/vcomp.manifest, dlls/vcomp/tests/vcomp.rc, dlls/vcomp/tests/work.c, +# | dlls/vcomp/vcomp.spec, dlls/vcomp/vcomp_private.h, dlls/vcomp/work.c, dlls/vcomp100/vcomp100.spec, +# | dlls/vcomp90/vcomp90.spec +# | +if test "$enable_vcomp_Stub_Functions" -eq 1; then + patch_apply vcomp-Stub_Functions/0001-vcomp-single-threaded-implementation-of-_vcomp_fork.patch + patch_apply vcomp-Stub_Functions/0002-vcomp-better-stubs-for-_vcomp_for_static_simple_init.patch + patch_apply vcomp-Stub_Functions/0003-vcomp-better-stub-for-_vcomp_for_static_init.patch + patch_apply vcomp-Stub_Functions/0004-vcomp-implement-omp_in_parallel.patch + patch_apply vcomp-Stub_Functions/0005-vcomp-better-stubs-for-_vcomp_for_dynamic_init-_vcom.patch + patch_apply vcomp-Stub_Functions/0006-vcomp-better-stubs-for-_vcomp_sections_init-_vcomp_s.patch + patch_apply vcomp-Stub_Functions/0007-vcomp-Add-a-warning-that-multithreading-is-not-yet-s.patch + ( + echo '+ { "Dan Kegel", "vcomp: single-threaded implementation of _vcomp_fork.", 1 },'; + echo '+ { "Dan Kegel", "vcomp: better stubs for _vcomp_for_static_simple_init, _vcomp_for_static_end.", 1 },'; + echo '+ { "Dan Kegel", "vcomp: better stub for _vcomp_for_static_init.", 1 },'; + echo '+ { "Dan Kegel", "vcomp: implement omp_in_parallel.", 1 },'; + echo '+ { "Dan Kegel", "vcomp: better stubs for _vcomp_for_dynamic_init, _vcomp_for_dynamic_next.", 1 },'; + echo '+ { "Dan Kegel", "vcomp: better stubs for _vcomp_sections_init, _vcomp_sections_next.", 1 },'; + echo '+ { "Sebastian Lackner", "vcomp: Add a warning that multithreading is not yet supported.", 1 },'; + ) >> "$patchlist" +fi + # Patchset windowscodecs-TGA_Decoder # | # | Modified files: diff --git a/patches/vcomp-Stub_Functions/0001-vcomp-single-threaded-implementation-of-_vcomp_fork.patch b/patches/vcomp-Stub_Functions/0001-vcomp-single-threaded-implementation-of-_vcomp_fork.patch new file mode 100644 index 00000000..29c63217 --- /dev/null +++ b/patches/vcomp-Stub_Functions/0001-vcomp-single-threaded-implementation-of-_vcomp_fork.patch @@ -0,0 +1,484 @@ +From 90156f8a04061c7d0629f46dd640c09bccb0122c Mon Sep 17 00:00:00 2001 +From: Dan Kegel +Date: Fri, 12 Oct 2012 22:31:39 -0700 +Subject: vcomp: single-threaded implementation of _vcomp_fork + +--- + configure.ac | 3 +- + dlls/vcomp/Makefile.in | 1 + + dlls/vcomp/fork.c | 161 ++++++++++++++++++++++++++++++++++++++++ + dlls/vcomp/tests/Makefile.in | 8 ++ + dlls/vcomp/tests/fork.c | 153 ++++++++++++++++++++++++++++++++++++++ + dlls/vcomp/tests/vcomp.manifest | 21 ++++++ + dlls/vcomp/tests/vcomp.rc | 22 ++++++ + dlls/vcomp/vcomp.spec | 2 +- + dlls/vcomp100/vcomp100.spec | 2 +- + dlls/vcomp90/vcomp90.spec | 2 +- + 10 files changed, 371 insertions(+), 4 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 a931730..8c51410 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -3290,7 +3290,8 @@ WINE_CONFIG_DLL(uxtheme,,[implib]) + WINE_CONFIG_TEST(dlls/uxtheme/tests) + WINE_CONFIG_DLL(vbscript,,[clean]) + WINE_CONFIG_TEST(dlls/vbscript/tests,[clean]) +-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 a54a86f..5bd0074 100644 +--- a/dlls/vcomp/Makefile.in ++++ b/dlls/vcomp/Makefile.in +@@ -1,4 +1,5 @@ + MODULE = vcomp.dll + + C_SRCS = \ ++ fork.c \ + main.c +diff --git a/dlls/vcomp/fork.c b/dlls/vcomp/fork.c +new file mode 100644 +index 0000000..13a7b56 +--- /dev/null ++++ b/dlls/vcomp/fork.c +@@ -0,0 +1,161 @@ ++/* ++ * 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 ++ ++#include "windef.h" ++#include "winbase.h" ++#include "wine/debug.h" ++ ++WINE_DEFAULT_DEBUG_CHANNEL(vcomp); ++ ++void CDECL _vcomp_fork_call_wrapper(void *wrapper, int nargs, __ms_va_list args); ++ ++/* When Visual C encounters a '#pragma omp parallel' directive, ++ * it wraps the next statement in a function, and passes the address ++ * of the wrapper function to _vcomp_fork, which calls that function-- ++ * possibly after spawning extra copies on new threads. ++ * ++ * If the directive has an if() clause, the value passed to the if clause ++ * is passed as the first argument to _vcomp_fork; if it is false, ++ * or if OMP_NUM_THREADS is 1, or omp_set_num_threads(1) has been called, ++ * or if too many threads are already in use, native _vcomp_fork doesn't spawn ++ * any extra threads, it just calls the wrapper function. ++ * ++ * The OpenMP standard allows implementations to fall back to executing ++ * everything on a single thread, so that's what we'll do for now; ++ * our _vcomp_fork will simply call the wrapper function. ++ * That's enough to make many, but not all, apps run correctly. ++ * ++ * If the statement being wrapped refers to variables from an outer scope, ++ * Visual C passes them to _vcomp_fork and thence the wrapper as follows: ++ * - Unchanging ints are always passed by value ++ * - Unchanging floats are passed by value on i386, but by reference on amd64 ++ * - Everything else is passed by reference ++ * ++ * The call to _vcomp_fork is synthesized by the compiler; ++ * user code isn't even aware that a call is being made. And the callee ++ * (_vcomp_fork) is also under Visual C's control. Thus the compiler ++ * is free to use a nonstandard ABI for this call. And it does, in that ++ * float arguments are not promoted to double. (Some apps ++ * that use floats would probably be very annoyed if they were silently ++ * promoted to doubles by "#pragma omp parallel".) ++ * ++ * The call from _vcomp_fork to the wrapper function also doesn't quite ++ * follow the normal win32/win64 calling conventions: ++ * 1) Since Visual C never passes floats or doubles by value to the ++ * wrapper on amd64, native vcomp.dll does not copy floating point parameters ++ * to registers, contrary to the win64 ABI. Manual tests confirm this. ++ * 2) Since the wrapper itself doesn't use varargs at all, _vcomp_fork can't ++ * just pass an __ms_va_list; it has to push the arguments onto the stack again. ++ * This can't be done in C, so we use assembly in _vcomp_fork_call_wrapper. ++ * (That function is a close copy of call_method in oleaut32/typelib.c, ++ * with unneeded instructions removed.) ++ */ ++ ++void WINAPIV _vcomp_fork(BOOL ifval, int nargs, void *wrapper, ...) ++{ ++ __ms_va_list valist; ++ TRACE("(%d, %d, %p, ...)\n", ifval, nargs, wrapper); ++ __ms_va_start(valist, wrapper); ++ _vcomp_fork_call_wrapper(wrapper, nargs, valist); ++ __ms_va_end(valist); ++} ++ ++#if defined(__i386__) ++__ASM_GLOBAL_FUNC( _vcomp_fork_call_wrapper, ++ "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" ++ "movl %esp,%edi\n\t" ++ "shll $2,%edx\n\t" ++ "jz 1f\n\t" ++ "subl %edx,%edi\n\t" ++ "andl $~15,%edi\n\t" ++ "movl %edi,%esp\n\t" ++ "movl 12(%ebp),%ecx\n\t" ++ "movl 16(%ebp),%esi\n\t" ++ "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" ) ++ ++#elif defined(__x86_64__) ++ ++__ASM_GLOBAL_FUNC( _vcomp_fork_call_wrapper, ++ "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") ++#else ++ ++void CDECL _vcomp_fork_call_wrapper(void *wrapper, int nargs, __ms_va_list args) ++{ ++ ERR("Not implemented for this architecture\n"); ++} ++ ++#endif +diff --git a/dlls/vcomp/tests/Makefile.in b/dlls/vcomp/tests/Makefile.in +new file mode 100644 +index 0000000..81430a3 +--- /dev/null ++++ b/dlls/vcomp/tests/Makefile.in +@@ -0,0 +1,8 @@ ++TESTDLL = vcomp.dll ++IMPORTS = vcomp ++ ++C_SRCS = \ ++ fork.c ++ ++RC_SRCS = \ ++ vcomp.rc +diff --git a/dlls/vcomp/tests/fork.c b/dlls/vcomp/tests/fork.c +new file mode 100644 +index 0000000..a6f176c +--- /dev/null ++++ b/dlls/vcomp/tests/fork.c +@@ -0,0 +1,153 @@ ++/* ++ * 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 const int is_win64 = (sizeof(void *) > sizeof(int)); ++ ++static void WINAPIV (*p_vcomp_fork)(BOOL ifval, int nargs, void *wrapper, ...); ++static int CDECL (*pomp_get_max_threads)(void); ++ ++#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); ++ GETFUNC(omp_get_max_threads); ++ ++ return TRUE; ++} ++ ++/* Test whether a variety of types are passed correctly. ++ * Pass five of each because the first four parameters are ++ * handled differently on amd64, and we want to test both ++ * ways. ++ */ ++ ++static void CDECL _test_vcomp_fork_ptr_worker(LONG volatile *a, LONG volatile *b, LONG volatile *c, LONG volatile *d, LONG volatile *e) ++{ ++ InterlockedIncrement(a); ++ InterlockedIncrement(b); ++ InterlockedIncrement(c); ++ InterlockedIncrement(d); ++ InterlockedIncrement(e); ++} ++ ++static void test_vcomp_fork_ptr(void) ++{ ++ LONG volatile a, b, c, d, e; ++ int n; ++ ++ /* #pragma omp parallel if(FALSE) shared(a, b, c, d, e) ++ * { InterlockedIncrement(&a); ... InterlockedIncrement(&e); } ++ */ ++ a=0; b=1; c=2; d=3; e=4; ++ p_vcomp_fork(FALSE, 5, _test_vcomp_fork_ptr_worker, &a, &b, &c, &d, &e); ++ ok(a == 1, "a == 1\n"); ++ ok(b == 2, "a == 2\n"); ++ ok(c == 3, "a == 3\n"); ++ ok(d == 4, "a == 4\n"); ++ ok(e == 5, "a == 5\n"); ++ ++ /* #pragma omp parallel if(TRUE) shared(a, b, c, d, e) ++ * { InterlockedIncrement(&a); ... InterlockedIncrement(&e); } ++ */ ++ a=0; b=1; c=2; d=3; e=4; ++ n = pomp_get_max_threads(); ++ p_vcomp_fork(TRUE, 5, _test_vcomp_fork_ptr_worker, &a, &b, &c, &d, &e); ++ ok(a > 0 && a <= (n+0), "a > 0 && a <= (n+0)\n"); ++ ok(b > 1 && b <= (n+1), "b > 1 && b <= (n+1)\n"); ++ ok(c > 2 && c <= (n+2), "c > 2 && c <= (n+2)\n"); ++ ok(d > 3 && d <= (n+3), "d > 3 && d <= (n+3)\n"); ++ ok(e > 4 && e <= (n+4), "e > 4 && e <= (n+4)\n"); ++} ++ ++static void CDECL _test_vcomp_fork_uintptr_worker(UINT_PTR a, UINT_PTR b, UINT_PTR c, UINT_PTR d, UINT_PTR e) ++{ ++ ok(a == 1, "expected a == 1\n"); ++ ok(b == MAXUINT_PTR-2, "expected b == MAXUINT_PTR-2\n"); ++ ok(c == 3, "expected c == 3\n"); ++ ok(d == MAXUINT_PTR-4, "expected d == MAXUINT_PTR-4\n"); ++ ok(e == 5, "expected e == 5\n"); ++} ++ ++static void test_vcomp_fork_uintptr(void) ++{ ++ /* test_vcomp_fork_ptr ought to have been enough, but probably ++ * didn't vary all the bits of the high word, so do that here. ++ */ ++ p_vcomp_fork(TRUE, 5, _test_vcomp_fork_uintptr_worker, \ ++ (UINT_PTR)1, (UINT_PTR)(MAXUINT_PTR-2), \ ++ (UINT_PTR)3, (UINT_PTR)(MAXUINT_PTR)-4, (UINT_PTR) 5); ++} ++ ++static void CDECL _test_vcomp_fork_float_worker(float a, float b, float c, float d, float e) ++{ ++ ok(1.4999 < a && a < 1.5001, "expected a == 1.5, got %f\n", a); ++ ok(2.4999 < b && b < 2.5001, "expected b == 2.5, got %f\n", b); ++ ok(3.4999 < c && c < 3.5001, "expected c == 3.5, got %f\n", c); ++ ok(4.4999 < d && d < 4.5001, "expected d == 4.5, got %f\n", d); ++ ok(5.4999 < e && e < 5.5001, "expected e == 5.5, got %f\n", e); ++} ++ ++static void test_vcomp_fork_float(void) ++{ ++ static void CDECL (*p_vcomp_fork_f5)(BOOL, int, void *, float, float, float, float, float); ++ ++ if (is_win64) ++ { ++ skip("Skipping float test on x86_64.\n"); ++ return; ++ } ++ ++ /* ++ * 32 bit Visual C sometimes passes 32 bit floats by value to ++ * the wrapper, so verify that here. ++ * ++ * x86-64 Visual C has not yet been observed passing 32 bit floats by ++ * value to the wrapper, and indeed _vcomp_fork does not even copy the ++ * first four args to floating point registers, so this test fails ++ * on x86-64 for the first four arguments even on native. ++ * Therefore don't run it. (It's hard to write a reliable test to show ++ * this, since the floating point registers might just happen ++ * to have the right values once in a blue moon.) ++ */ ++ ++ /* Avoid float promotion by using a prototype tailored for this call */ ++ p_vcomp_fork_f5 = (void *)p_vcomp_fork; ++ p_vcomp_fork_f5(TRUE, 5, _test_vcomp_fork_float_worker, 1.5f, 2.5f, 3.5f, 4.5f, 5.5f); ++} ++ ++START_TEST(fork) ++{ ++ if (!init()) ++ return; ++ ++ test_vcomp_fork_ptr(); ++ test_vcomp_fork_uintptr(); ++ test_vcomp_fork_float(); ++} +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 @@ ++ ++ ++ ++Wine vcomp test suite ++ ++ ++ ++ ++ ++ +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 306dd15..d446574 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 +diff --git a/dlls/vcomp100/vcomp100.spec b/dlls/vcomp100/vcomp100.spec +index 39cf91c..2c04e91 100644 +--- a/dlls/vcomp100/vcomp100.spec ++++ b/dlls/vcomp100/vcomp100.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) vcomp._vcomp_fork + @ stub _vcomp_get_thread_num + @ stub _vcomp_leave_critsect + @ stub _vcomp_master_barrier +diff --git a/dlls/vcomp90/vcomp90.spec b/dlls/vcomp90/vcomp90.spec +index 39cf91c..2c04e91 100644 +--- a/dlls/vcomp90/vcomp90.spec ++++ b/dlls/vcomp90/vcomp90.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) vcomp._vcomp_fork + @ stub _vcomp_get_thread_num + @ stub _vcomp_leave_critsect + @ stub _vcomp_master_barrier +-- +2.2.1 + diff --git a/patches/vcomp-Stub_Functions/0002-vcomp-better-stubs-for-_vcomp_for_static_simple_init.patch b/patches/vcomp-Stub_Functions/0002-vcomp-better-stubs-for-_vcomp_for_static_simple_init.patch new file mode 100644 index 00000000..a977684f --- /dev/null +++ b/patches/vcomp-Stub_Functions/0002-vcomp-better-stubs-for-_vcomp_for_static_simple_init.patch @@ -0,0 +1,233 @@ +From c0369b34efc51c992be270a9e4eaef33b3cbf3d5 Mon Sep 17 00:00:00 2001 +From: Dan Kegel +Date: Sun, 14 Oct 2012 20:40:31 -0700 +Subject: vcomp: better stubs for _vcomp_for_static_simple_init, + _vcomp_for_static_end + +--- + dlls/vcomp/Makefile.in | 3 +- + dlls/vcomp/tests/Makefile.in | 3 +- + dlls/vcomp/tests/work.c | 83 ++++++++++++++++++++++++++++++++++++++++++++ + dlls/vcomp/vcomp.spec | 4 +-- + dlls/vcomp/work.c | 41 ++++++++++++++++++++++ + dlls/vcomp100/vcomp100.spec | 4 +-- + dlls/vcomp90/vcomp90.spec | 4 +-- + 7 files changed, 134 insertions(+), 8 deletions(-) + create mode 100644 dlls/vcomp/tests/work.c + create mode 100644 dlls/vcomp/work.c + +diff --git a/dlls/vcomp/Makefile.in b/dlls/vcomp/Makefile.in +index 5bd0074..dfff21a 100644 +--- a/dlls/vcomp/Makefile.in ++++ b/dlls/vcomp/Makefile.in +@@ -2,4 +2,5 @@ MODULE = vcomp.dll + + C_SRCS = \ + fork.c \ +- main.c ++ main.c \ ++ work.c +diff --git a/dlls/vcomp/tests/Makefile.in b/dlls/vcomp/tests/Makefile.in +index 81430a3..f1479ab 100644 +--- a/dlls/vcomp/tests/Makefile.in ++++ b/dlls/vcomp/tests/Makefile.in +@@ -2,7 +2,8 @@ TESTDLL = vcomp.dll + IMPORTS = vcomp + + C_SRCS = \ +- fork.c ++ fork.c \ ++ work.c + + RC_SRCS = \ + vcomp.rc +diff --git a/dlls/vcomp/tests/work.c b/dlls/vcomp/tests/work.c +new file mode 100644 +index 0000000..e8d3f2c +--- /dev/null ++++ b/dlls/vcomp/tests/work.c +@@ -0,0 +1,83 @@ ++/* ++ * Unit test suite for vcomp work-sharing 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, ...); ++static void CDECL (*p_vcomp_for_static_end)(void); ++static void CDECL (*p_vcomp_for_static_simple_init)(int first, int last, int mystep, int step, int *pfirst, int *plast); ++ ++#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); ++ GETFUNC(_vcomp_for_static_end); ++ GETFUNC(_vcomp_for_static_simple_init); ++ ++ return TRUE; ++} ++ ++static LONG volatile ncalls; ++static LONG volatile nsum; ++ ++static void CDECL _test_vcomp_for_static_simple_init_worker(void) ++{ ++ int i, my_limit; ++ ++ InterlockedIncrement(&ncalls); ++ ++ /* for (i=0; i<=12; i++) */ ++ p_vcomp_for_static_simple_init(0, 12, 1, 1, &i, &my_limit); ++ ++ while (i <= my_limit) ++ { ++ int j; ++ for (j=0; j= 1, "expected >= 1 call, got %d\n", ncalls); ++ ok(nsum == 6*13, "expected sum 6*13, got %d\n", nsum); ++} ++ ++START_TEST(work) ++{ ++ if (!init()) ++ return; ++ ++ test_vcomp_for_static_simple_init(); ++} +diff --git a/dlls/vcomp/vcomp.spec b/dlls/vcomp/vcomp.spec +index d446574..b14edca 100644 +--- a/dlls/vcomp/vcomp.spec ++++ b/dlls/vcomp/vcomp.spec +@@ -59,10 +59,10 @@ + @ stub _vcomp_for_dynamic_init_i8 + @ stub _vcomp_for_dynamic_next + @ stub _vcomp_for_dynamic_next_i8 +-@ stub _vcomp_for_static_end ++@ cdecl _vcomp_for_static_end() + @ stub _vcomp_for_static_init + @ stub _vcomp_for_static_init_i8 +-@ stub _vcomp_for_static_simple_init ++@ cdecl _vcomp_for_static_simple_init(long long long long ptr ptr) + @ stub _vcomp_for_static_simple_init_i8 + @ varargs _vcomp_fork(long long ptr) + @ stub _vcomp_get_thread_num +diff --git a/dlls/vcomp/work.c b/dlls/vcomp/work.c +new file mode 100644 +index 0000000..0f9ff78 +--- /dev/null ++++ b/dlls/vcomp/work.c +@@ -0,0 +1,41 @@ ++/* ++ * vcomp work-sharing 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 ++ ++#include "windef.h" ++#include "winbase.h" ++#include "wine/debug.h" ++ ++WINE_DEFAULT_DEBUG_CHANNEL(vcomp); ++ ++void CDECL _vcomp_for_static_simple_init(int first, int last, int mystep, int step, int *pfirst, int *plast) ++{ ++ TRACE("(%d, %d, %d, %d, %p, %p): stub\n", first, last, mystep, step, pfirst, plast); ++ *pfirst = first; ++ *plast = last; ++} ++ ++void CDECL _vcomp_for_static_end(void) ++{ ++ TRACE("stub\n"); ++} +diff --git a/dlls/vcomp100/vcomp100.spec b/dlls/vcomp100/vcomp100.spec +index 2c04e91..89e0972 100644 +--- a/dlls/vcomp100/vcomp100.spec ++++ b/dlls/vcomp100/vcomp100.spec +@@ -59,10 +59,10 @@ + @ stub _vcomp_for_dynamic_init_i8 + @ stub _vcomp_for_dynamic_next + @ stub _vcomp_for_dynamic_next_i8 +-@ stub _vcomp_for_static_end ++@ cdecl _vcomp_for_static_end() vcomp._vcomp_for_static_end + @ stub _vcomp_for_static_init + @ stub _vcomp_for_static_init_i8 +-@ stub _vcomp_for_static_simple_init ++@ cdecl _vcomp_for_static_simple_init(long long long long ptr ptr) vcomp._vcomp_for_static_simple_init + @ stub _vcomp_for_static_simple_init_i8 + @ varargs _vcomp_fork(long long ptr) vcomp._vcomp_fork + @ stub _vcomp_get_thread_num +diff --git a/dlls/vcomp90/vcomp90.spec b/dlls/vcomp90/vcomp90.spec +index 2c04e91..89e0972 100644 +--- a/dlls/vcomp90/vcomp90.spec ++++ b/dlls/vcomp90/vcomp90.spec +@@ -59,10 +59,10 @@ + @ stub _vcomp_for_dynamic_init_i8 + @ stub _vcomp_for_dynamic_next + @ stub _vcomp_for_dynamic_next_i8 +-@ stub _vcomp_for_static_end ++@ cdecl _vcomp_for_static_end() vcomp._vcomp_for_static_end + @ stub _vcomp_for_static_init + @ stub _vcomp_for_static_init_i8 +-@ stub _vcomp_for_static_simple_init ++@ cdecl _vcomp_for_static_simple_init(long long long long ptr ptr) vcomp._vcomp_for_static_simple_init + @ stub _vcomp_for_static_simple_init_i8 + @ varargs _vcomp_fork(long long ptr) vcomp._vcomp_fork + @ stub _vcomp_get_thread_num +-- +2.2.1 + diff --git a/patches/vcomp-Stub_Functions/0003-vcomp-better-stub-for-_vcomp_for_static_init.patch b/patches/vcomp-Stub_Functions/0003-vcomp-better-stub-for-_vcomp_for_static_init.patch new file mode 100644 index 00000000..b71574d3 --- /dev/null +++ b/patches/vcomp-Stub_Functions/0003-vcomp-better-stub-for-_vcomp_for_static_init.patch @@ -0,0 +1,153 @@ +From fadfe0d8a2483066f6f0137b2fb6d6efa3090db8 Mon Sep 17 00:00:00 2001 +From: Dan Kegel +Date: Sun, 14 Oct 2012 20:42:35 -0700 +Subject: vcomp: better stub for _vcomp_for_static_init + +--- + dlls/vcomp/tests/work.c | 45 +++++++++++++++++++++++++++++++++++++++++++++ + dlls/vcomp/vcomp.spec | 2 +- + dlls/vcomp/work.c | 11 +++++++++++ + dlls/vcomp100/vcomp100.spec | 2 +- + dlls/vcomp90/vcomp90.spec | 2 +- + 5 files changed, 59 insertions(+), 3 deletions(-) + +diff --git a/dlls/vcomp/tests/work.c b/dlls/vcomp/tests/work.c +index e8d3f2c..2a76227 100644 +--- a/dlls/vcomp/tests/work.c ++++ b/dlls/vcomp/tests/work.c +@@ -22,6 +22,7 @@ + + static void WINAPIV (*p_vcomp_fork)(DWORD parallel, int nargs, void *helper, ...); + static void CDECL (*p_vcomp_for_static_end)(void); ++static void CDECL (*p_vcomp_for_static_init)(int first, int last, int mystep, int chunksize, int *pnloops, int *pfirst, int *plast, int *pchunksize, int *pfinalchunkstart); + static void CDECL (*p_vcomp_for_static_simple_init)(int first, int last, int mystep, int step, int *pfirst, int *plast); + + #define GETFUNC(x) do { p##x = (void*)GetProcAddress(vcomp, #x); ok(p##x != NULL, "Export '%s' not found\n", #x); } while(0) +@@ -37,6 +38,7 @@ static BOOL init(void) + + GETFUNC(_vcomp_fork); + GETFUNC(_vcomp_for_static_end); ++ GETFUNC(_vcomp_for_static_init); + GETFUNC(_vcomp_for_static_simple_init); + + return TRUE; +@@ -45,6 +47,48 @@ static BOOL init(void) + static LONG volatile ncalls; + static LONG volatile nsum; + ++static void CDECL _test_vcomp_for_static_init_worker(void) ++{ ++ const int my_start = 0; ++ const int my_end = 12; ++ const int my_incr = 1; ++ const int my_chunksize = 1; ++ int nloops, chunkstart, chunkend, chunksize, finalchunkstart; ++ ++ InterlockedIncrement(&ncalls); ++ ++ /* for (i=0; i<=12; i++) */ ++ p_vcomp_for_static_init(my_start, my_end, my_incr, my_chunksize, ++ &nloops, &chunkstart, &chunkend, &chunksize, &finalchunkstart); ++ ++ do ++ { ++ int i; ++ if (chunkstart == finalchunkstart) chunkend = my_end; ++ ++ for (i=chunkstart; i <= chunkend; i += my_incr) ++ { ++ int j; ++ for (j=0; j 0); ++ ++ p_vcomp_for_static_end(); ++} ++ ++static void test_vcomp_for_static_init(void) ++{ ++ ncalls = 0; ++ nsum = 0; ++ p_vcomp_fork(1, 0, _test_vcomp_for_static_init_worker); ++ ok(ncalls >= 1, "expected >= 1 call, got %d\n", ncalls); ++ ok(nsum == 6*13, "expected sum 6*13, got %d\n", nsum); ++} ++ + static void CDECL _test_vcomp_for_static_simple_init_worker(void) + { + int i, my_limit; +@@ -79,5 +123,6 @@ START_TEST(work) + if (!init()) + return; + ++ test_vcomp_for_static_init(); + test_vcomp_for_static_simple_init(); + } +diff --git a/dlls/vcomp/vcomp.spec b/dlls/vcomp/vcomp.spec +index b14edca..8bc66e8 100644 +--- a/dlls/vcomp/vcomp.spec ++++ b/dlls/vcomp/vcomp.spec +@@ -60,7 +60,7 @@ + @ stub _vcomp_for_dynamic_next + @ stub _vcomp_for_dynamic_next_i8 + @ cdecl _vcomp_for_static_end() +-@ stub _vcomp_for_static_init ++@ cdecl _vcomp_for_static_init(long long long long ptr ptr ptr ptr ptr) + @ stub _vcomp_for_static_init_i8 + @ cdecl _vcomp_for_static_simple_init(long long long long ptr ptr) + @ stub _vcomp_for_static_simple_init_i8 +diff --git a/dlls/vcomp/work.c b/dlls/vcomp/work.c +index 0f9ff78..82df26e 100644 +--- a/dlls/vcomp/work.c ++++ b/dlls/vcomp/work.c +@@ -28,6 +28,17 @@ + + WINE_DEFAULT_DEBUG_CHANNEL(vcomp); + ++void CDECL _vcomp_for_static_init(int first, int last, int mystep, int chunksize, int *pnloops, int *pfirst, int *plast, int *pchunksize, int *pfinalchunkstart) ++{ ++ TRACE("(%d, %d, %d, %d, %p, %p, %p, %p, %p): stub\n", ++ first, last, mystep, chunksize, pnloops, pfirst, plast, pchunksize, pfinalchunkstart); ++ *pfirst = first; ++ *plast = last; ++ *pfinalchunkstart = last; ++ *pnloops = 1; ++ *pchunksize = 0; /* moot, since nloops=1 */ ++} ++ + void CDECL _vcomp_for_static_simple_init(int first, int last, int mystep, int step, int *pfirst, int *plast) + { + TRACE("(%d, %d, %d, %d, %p, %p): stub\n", first, last, mystep, step, pfirst, plast); +diff --git a/dlls/vcomp100/vcomp100.spec b/dlls/vcomp100/vcomp100.spec +index 89e0972..f008e2e 100644 +--- a/dlls/vcomp100/vcomp100.spec ++++ b/dlls/vcomp100/vcomp100.spec +@@ -60,7 +60,7 @@ + @ stub _vcomp_for_dynamic_next + @ stub _vcomp_for_dynamic_next_i8 + @ cdecl _vcomp_for_static_end() vcomp._vcomp_for_static_end +-@ stub _vcomp_for_static_init ++@ cdecl _vcomp_for_static_init(long long long long ptr ptr ptr ptr ptr) vcomp._vcomp_for_static_init + @ stub _vcomp_for_static_init_i8 + @ cdecl _vcomp_for_static_simple_init(long long long long ptr ptr) vcomp._vcomp_for_static_simple_init + @ stub _vcomp_for_static_simple_init_i8 +diff --git a/dlls/vcomp90/vcomp90.spec b/dlls/vcomp90/vcomp90.spec +index 89e0972..f008e2e 100644 +--- a/dlls/vcomp90/vcomp90.spec ++++ b/dlls/vcomp90/vcomp90.spec +@@ -60,7 +60,7 @@ + @ stub _vcomp_for_dynamic_next + @ stub _vcomp_for_dynamic_next_i8 + @ cdecl _vcomp_for_static_end() vcomp._vcomp_for_static_end +-@ stub _vcomp_for_static_init ++@ cdecl _vcomp_for_static_init(long long long long ptr ptr ptr ptr ptr) vcomp._vcomp_for_static_init + @ stub _vcomp_for_static_init_i8 + @ cdecl _vcomp_for_static_simple_init(long long long long ptr ptr) vcomp._vcomp_for_static_simple_init + @ stub _vcomp_for_static_simple_init_i8 +-- +2.2.1 + diff --git a/patches/vcomp-Stub_Functions/0004-vcomp-implement-omp_in_parallel.patch b/patches/vcomp-Stub_Functions/0004-vcomp-implement-omp_in_parallel.patch new file mode 100644 index 00000000..9539d196 --- /dev/null +++ b/patches/vcomp-Stub_Functions/0004-vcomp-implement-omp_in_parallel.patch @@ -0,0 +1,254 @@ +From 659f7394d0c3e4c969e0b0f66689433fd133febd Mon Sep 17 00:00:00 2001 +From: Dan Kegel +Date: Wed, 17 Oct 2012 09:15:06 -0700 +Subject: vcomp: implement omp_in_parallel + +--- + dlls/vcomp/fork.c | 32 +++++++++++++++++++++++++++++ + dlls/vcomp/main.c | 12 +++++++++++ + dlls/vcomp/tests/fork.c | 50 +++++++++++++++++++++++++++++++++++++++++++++ + dlls/vcomp/vcomp.spec | 2 +- + dlls/vcomp/vcomp_private.h | 19 +++++++++++++++++ + dlls/vcomp100/vcomp100.spec | 2 +- + dlls/vcomp90/vcomp90.spec | 2 +- + 7 files changed, 116 insertions(+), 3 deletions(-) + create mode 100644 dlls/vcomp/vcomp_private.h + +diff --git a/dlls/vcomp/fork.c b/dlls/vcomp/fork.c +index 13a7b56..49399c6 100644 +--- a/dlls/vcomp/fork.c ++++ b/dlls/vcomp/fork.c +@@ -25,6 +25,22 @@ + #include "windef.h" + #include "winbase.h" + #include "wine/debug.h" ++#include "vcomp_private.h" ++ ++struct vcomp_team ++{ ++ struct vcomp_team *parent; ++}; ++ ++static inline struct vcomp_team *vcomp_get_team(void) ++{ ++ return (struct vcomp_team *)TlsGetValue(vcomp_context_tls); ++} ++ ++static inline void vcomp_set_team(struct vcomp_team *team) ++{ ++ TlsSetValue(vcomp_context_tls, team); ++} + + WINE_DEFAULT_DEBUG_CHANNEL(vcomp); + +@@ -75,10 +91,18 @@ 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 = vcomp_get_team(); ++ vcomp_set_team(&team); ++ + __ms_va_start(valist, wrapper); + _vcomp_fork_call_wrapper(wrapper, nargs, valist); + __ms_va_end(valist); ++ ++ vcomp_set_team(team.parent); + } + + #if defined(__i386__) +@@ -159,3 +183,11 @@ 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 ab2a372..e37cf16 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; ++ + int CDECL omp_get_dynamic(void) + { + TRACE("stub\n"); +@@ -117,6 +120,15 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) + return FALSE; /* prefer native version */ + case DLL_PROCESS_ATTACH: + DisableThreadLibraryCalls(hinstDLL); ++ ++ if ((vcomp_context_tls = TlsAlloc()) == TLS_OUT_OF_INDEXES) ++ { ++ ERR("Failed to allocate TLS index\n"); ++ return FALSE; ++ } ++ break; ++ case DLL_PROCESS_DETACH: ++ TlsFree(vcomp_context_tls); + break; + } + +diff --git a/dlls/vcomp/tests/fork.c b/dlls/vcomp/tests/fork.c +index a6f176c..3d11504 100644 +--- a/dlls/vcomp/tests/fork.c ++++ b/dlls/vcomp/tests/fork.c +@@ -24,6 +24,9 @@ static const int is_win64 = (sizeof(void *) > sizeof(int)); + + 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) + +@@ -36,6 +39,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); + +@@ -142,6 +148,49 @@ 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 +Date: Mon, 15 Oct 2012 21:01:30 -0700 +Subject: vcomp: better stubs for _vcomp_for_dynamic_init, + _vcomp_for_dynamic_next + +--- + dlls/vcomp/fork.c | 15 ----------- + dlls/vcomp/tests/work.c | 66 +++++++++++++++++++++++++++++++++++++++++++++ + dlls/vcomp/vcomp.spec | 4 +-- + dlls/vcomp/vcomp_private.h | 37 +++++++++++++++++++++++++ + dlls/vcomp/work.c | 47 ++++++++++++++++++++++++++++++++ + dlls/vcomp100/vcomp100.spec | 4 +-- + dlls/vcomp90/vcomp90.spec | 4 +-- + 7 files changed, 156 insertions(+), 21 deletions(-) + +diff --git a/dlls/vcomp/fork.c b/dlls/vcomp/fork.c +index 49399c6..5af2021 100644 +--- a/dlls/vcomp/fork.c ++++ b/dlls/vcomp/fork.c +@@ -27,21 +27,6 @@ + #include "wine/debug.h" + #include "vcomp_private.h" + +-struct vcomp_team +-{ +- struct vcomp_team *parent; +-}; +- +-static inline struct vcomp_team *vcomp_get_team(void) +-{ +- return (struct vcomp_team *)TlsGetValue(vcomp_context_tls); +-} +- +-static inline void vcomp_set_team(struct vcomp_team *team) +-{ +- TlsSetValue(vcomp_context_tls, team); +-} +- + WINE_DEFAULT_DEBUG_CHANNEL(vcomp); + + void CDECL _vcomp_fork_call_wrapper(void *wrapper, int nargs, __ms_va_list args); +diff --git a/dlls/vcomp/tests/work.c b/dlls/vcomp/tests/work.c +index 2a76227..5abe0e1 100644 +--- a/dlls/vcomp/tests/work.c ++++ b/dlls/vcomp/tests/work.c +@@ -21,12 +21,18 @@ + #include "wine/test.h" + + static void WINAPIV (*p_vcomp_fork)(DWORD parallel, int nargs, void *helper, ...); ++static void CDECL (*p_vcomp_for_dynamic_init)(int flags, int first, int last, int mystep, int chunksize); ++static int CDECL (*p_vcomp_for_dynamic_next)(int *pcounter, int *pchunklimit); + static void CDECL (*p_vcomp_for_static_end)(void); + static void CDECL (*p_vcomp_for_static_init)(int first, int last, int mystep, int chunksize, int *pnloops, int *pfirst, int *plast, int *pchunksize, int *pfinalchunkstart); + static void CDECL (*p_vcomp_for_static_simple_init)(int first, int last, int mystep, int step, int *pfirst, int *plast); + + #define GETFUNC(x) do { p##x = (void*)GetProcAddress(vcomp, #x); ok(p##x != NULL, "Export '%s' not found\n", #x); } while(0) + ++/* Matches definitions in ../vcomp_private.h */ ++#define VCOMP_DYNAMIC_FOR_FLAGS_DOWN 0x0 ++#define VCOMP_DYNAMIC_FOR_FLAGS_UP 0x40 ++ + static BOOL init(void) + { + HMODULE vcomp = LoadLibraryA("vcomp.dll"); +@@ -37,6 +43,8 @@ static BOOL init(void) + } + + GETFUNC(_vcomp_fork); ++ GETFUNC(_vcomp_for_dynamic_init); ++ GETFUNC(_vcomp_for_dynamic_next); + GETFUNC(_vcomp_for_static_end); + GETFUNC(_vcomp_for_static_init); + GETFUNC(_vcomp_for_static_simple_init); +@@ -47,6 +55,63 @@ static BOOL init(void) + static LONG volatile ncalls; + static LONG volatile nsum; + ++static void CDECL _test_vcomp_for_dynamic_worker_up(void) ++{ ++ int i, limit; ++ ++ InterlockedIncrement(&ncalls); ++ ++ /* pragma omp schedule(dynamic,16) */ ++ /* for (i=0; i<=17; i++) */ ++ p_vcomp_for_dynamic_init(VCOMP_DYNAMIC_FOR_FLAGS_UP, 0, 17, 1, 16); ++ while (p_vcomp_for_dynamic_next(&i, &limit)) ++ { ++ for (; i<=limit; i++) ++ { ++ int j; ++ for (j=0; j=0; i--) */ ++ p_vcomp_for_dynamic_init(VCOMP_DYNAMIC_FOR_FLAGS_DOWN, 17, 0, 1, 16); ++ while (p_vcomp_for_dynamic_next(&i, &limit)) ++ { ++ for (; i>=limit; i--) ++ { ++ int j; ++ for (j=0; j= 1, "expected >= 1 call, got %d\n", ncalls); ++ ok(nsum == 9*17, "expected sum 9*17, got %d\n", nsum); ++ ++ /* for (i=17; i>=0; i--) nsum += i; */ ++ ncalls = 0; ++ nsum = 0; ++ p_vcomp_fork(1, 0, _test_vcomp_for_dynamic_worker_down); ++ ok(ncalls >= 1, "expected >= 1 call, got %d\n", ncalls); ++ ok(nsum == 9*17, "expected sum 9*17, got %d\n", nsum); ++} ++ + static void CDECL _test_vcomp_for_static_init_worker(void) + { + const int my_start = 0; +@@ -123,6 +188,7 @@ START_TEST(work) + if (!init()) + return; + ++ test_vcomp_for_dynamic(); + test_vcomp_for_static_init(); + test_vcomp_for_static_simple_init(); + } +diff --git a/dlls/vcomp/vcomp.spec b/dlls/vcomp/vcomp.spec +index 156233f..f603660 100644 +--- a/dlls/vcomp/vcomp.spec ++++ b/dlls/vcomp/vcomp.spec +@@ -55,9 +55,9 @@ + @ stub _vcomp_copyprivate_receive + @ stub _vcomp_enter_critsect + @ stub _vcomp_flush +-@ stub _vcomp_for_dynamic_init ++@ cdecl _vcomp_for_dynamic_init(long long long long long) + @ stub _vcomp_for_dynamic_init_i8 +-@ stub _vcomp_for_dynamic_next ++@ cdecl _vcomp_for_dynamic_next(ptr ptr) + @ stub _vcomp_for_dynamic_next_i8 + @ cdecl _vcomp_for_static_end() + @ cdecl _vcomp_for_static_init(long long long long ptr ptr ptr ptr ptr) +diff --git a/dlls/vcomp/vcomp_private.h b/dlls/vcomp/vcomp_private.h +index 50c4643..d3a7005 100644 +--- a/dlls/vcomp/vcomp_private.h ++++ b/dlls/vcomp/vcomp_private.h +@@ -1,4 +1,7 @@ + /* ++ * vcmp wine internal private include file ++ * ++ * Copyright 2012 Dan Kegel + * Copyright 2015 Sebastian Lackner + * + * This library is free software; you can redistribute it and/or +@@ -16,4 +19,38 @@ + * 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; ++ union ++ { ++ struct ++ { ++ int counter; ++ int step; ++ int iterations_remaining; ++ int chunksize; ++ int flags; ++ } dyn_for; ++ } work; ++}; ++ + extern DWORD vcomp_context_tls DECLSPEC_HIDDEN; ++ ++static inline struct vcomp_team *vcomp_get_team(void) ++{ ++ return (struct vcomp_team *)TlsGetValue(vcomp_context_tls); ++} ++ ++static inline void vcomp_set_team(struct vcomp_team *team) ++{ ++ TlsSetValue(vcomp_context_tls, team); ++} ++ ++#define VCOMP_DYNAMIC_FOR_FLAGS_DOWN 0x0 ++#define VCOMP_DYNAMIC_FOR_FLAGS_UP 0x40 ++ ++#endif +diff --git a/dlls/vcomp/work.c b/dlls/vcomp/work.c +index 82df26e..87bce93 100644 +--- a/dlls/vcomp/work.c ++++ b/dlls/vcomp/work.c +@@ -25,9 +25,56 @@ + #include "windef.h" + #include "winbase.h" + #include "wine/debug.h" ++#include "vcomp_private.h" + + WINE_DEFAULT_DEBUG_CHANNEL(vcomp); + ++void CDECL _vcomp_for_dynamic_init(int flags, int first, int last, int mystep, int chunksize) ++{ ++ struct vcomp_team *pt = vcomp_get_team(); ++ ++ TRACE("(%d, %d, %d, %d, %d): stub\n", flags, first, last, mystep, chunksize); ++ ++ pt->work.dyn_for.counter = first; ++ pt->work.dyn_for.chunksize = chunksize; ++ pt->work.dyn_for.flags = flags; ++ pt->work.dyn_for.step = mystep; ++ if (flags & VCOMP_DYNAMIC_FOR_FLAGS_UP) ++ pt->work.dyn_for.iterations_remaining = 1 + (last - first) / mystep; ++ else ++ pt->work.dyn_for.iterations_remaining = 1 + (first - last) / mystep; ++} ++ ++int CDECL _vcomp_for_dynamic_next(int *pcounter, int *pchunklimit) ++{ ++ struct vcomp_team *pt = vcomp_get_team(); ++ int n; ++ ++ TRACE("(%p, %p): stub.\n", pcounter, pchunklimit); ++ ++ n = pt->work.dyn_for.chunksize; ++ if (n > pt->work.dyn_for.iterations_remaining) ++ n = pt->work.dyn_for.iterations_remaining; ++ ++ *pcounter = pt->work.dyn_for.counter; ++ ++ if (pt->work.dyn_for.flags & VCOMP_DYNAMIC_FOR_FLAGS_UP) ++ { ++ pt->work.dyn_for.counter += pt->work.dyn_for.step * n; ++ *pchunklimit = pt->work.dyn_for.counter - 1; ++ } ++ else ++ { ++ pt->work.dyn_for.counter -= pt->work.dyn_for.step * n; ++ *pchunklimit = pt->work.dyn_for.counter + 1; ++ } ++ pt->work.dyn_for.iterations_remaining -= n; ++ ++ TRACE("counter %d, iterations_remaining %d, n %d, returning %d\n", ++ pt->work.dyn_for.counter, pt->work.dyn_for.iterations_remaining, n, (n > 0)); ++ return (n > 0); ++} ++ + void CDECL _vcomp_for_static_init(int first, int last, int mystep, int chunksize, int *pnloops, int *pfirst, int *plast, int *pchunksize, int *pfinalchunkstart) + { + TRACE("(%d, %d, %d, %d, %p, %p, %p, %p, %p): stub\n", +diff --git a/dlls/vcomp100/vcomp100.spec b/dlls/vcomp100/vcomp100.spec +index dd276d0..48d5e3f 100644 +--- a/dlls/vcomp100/vcomp100.spec ++++ b/dlls/vcomp100/vcomp100.spec +@@ -55,9 +55,9 @@ + @ stub _vcomp_copyprivate_receive + @ stub _vcomp_enter_critsect + @ stub _vcomp_flush +-@ stub _vcomp_for_dynamic_init ++@ cdecl _vcomp_for_dynamic_init(long long long long long) vcomp._vcomp_for_dynamic_init + @ stub _vcomp_for_dynamic_init_i8 +-@ stub _vcomp_for_dynamic_next ++@ cdecl _vcomp_for_dynamic_next(ptr ptr) vcomp._vcomp_for_dynamic_next + @ stub _vcomp_for_dynamic_next_i8 + @ cdecl _vcomp_for_static_end() vcomp._vcomp_for_static_end + @ cdecl _vcomp_for_static_init(long long long long ptr ptr ptr ptr ptr) vcomp._vcomp_for_static_init +diff --git a/dlls/vcomp90/vcomp90.spec b/dlls/vcomp90/vcomp90.spec +index dd276d0..48d5e3f 100644 +--- a/dlls/vcomp90/vcomp90.spec ++++ b/dlls/vcomp90/vcomp90.spec +@@ -55,9 +55,9 @@ + @ stub _vcomp_copyprivate_receive + @ stub _vcomp_enter_critsect + @ stub _vcomp_flush +-@ stub _vcomp_for_dynamic_init ++@ cdecl _vcomp_for_dynamic_init(long long long long long) vcomp._vcomp_for_dynamic_init + @ stub _vcomp_for_dynamic_init_i8 +-@ stub _vcomp_for_dynamic_next ++@ cdecl _vcomp_for_dynamic_next(ptr ptr) vcomp._vcomp_for_dynamic_next + @ stub _vcomp_for_dynamic_next_i8 + @ cdecl _vcomp_for_static_end() vcomp._vcomp_for_static_end + @ cdecl _vcomp_for_static_init(long long long long ptr ptr ptr ptr ptr) vcomp._vcomp_for_static_init +-- +2.2.1 + diff --git a/patches/vcomp-Stub_Functions/0006-vcomp-better-stubs-for-_vcomp_sections_init-_vcomp_s.patch b/patches/vcomp-Stub_Functions/0006-vcomp-better-stubs-for-_vcomp_sections_init-_vcomp_s.patch new file mode 100644 index 00000000..6cebf0e7 --- /dev/null +++ b/patches/vcomp-Stub_Functions/0006-vcomp-better-stubs-for-_vcomp_sections_init-_vcomp_s.patch @@ -0,0 +1,180 @@ +From 8069c24409570d48c59bb103539d1ea1fd835c36 Mon Sep 17 00:00:00 2001 +From: Dan Kegel +Date: Mon, 15 Oct 2012 21:09:56 -0700 +Subject: vcomp: better stubs for _vcomp_sections_init, _vcomp_sections_next + +--- + dlls/vcomp/tests/work.c | 34 ++++++++++++++++++++++++++++++++++ + dlls/vcomp/vcomp.spec | 4 ++-- + dlls/vcomp/vcomp_private.h | 5 +++++ + dlls/vcomp/work.c | 18 ++++++++++++++++++ + dlls/vcomp100/vcomp100.spec | 4 ++-- + dlls/vcomp90/vcomp90.spec | 4 ++-- + 6 files changed, 63 insertions(+), 6 deletions(-) + +diff --git a/dlls/vcomp/tests/work.c b/dlls/vcomp/tests/work.c +index 5abe0e1..981f741 100644 +--- a/dlls/vcomp/tests/work.c ++++ b/dlls/vcomp/tests/work.c +@@ -20,12 +20,15 @@ + + #include "wine/test.h" + ++static void WINAPIV (*p_vcomp_barrier)(void); + static void WINAPIV (*p_vcomp_fork)(DWORD parallel, int nargs, void *helper, ...); + static void CDECL (*p_vcomp_for_dynamic_init)(int flags, int first, int last, int mystep, int chunksize); + static int CDECL (*p_vcomp_for_dynamic_next)(int *pcounter, int *pchunklimit); + static void CDECL (*p_vcomp_for_static_end)(void); + static void CDECL (*p_vcomp_for_static_init)(int first, int last, int mystep, int chunksize, int *pnloops, int *pfirst, int *plast, int *pchunksize, int *pfinalchunkstart); + static void CDECL (*p_vcomp_for_static_simple_init)(int first, int last, int mystep, int step, int *pfirst, int *plast); ++static void CDECL (*p_vcomp_sections_init)(int n); ++static int CDECL (*p_vcomp_sections_next)(void); + + #define GETFUNC(x) do { p##x = (void*)GetProcAddress(vcomp, #x); ok(p##x != NULL, "Export '%s' not found\n", #x); } while(0) + +@@ -42,12 +45,15 @@ static BOOL init(void) + return FALSE; + } + ++ GETFUNC(_vcomp_barrier); + GETFUNC(_vcomp_fork); + GETFUNC(_vcomp_for_dynamic_init); + GETFUNC(_vcomp_for_dynamic_next); + GETFUNC(_vcomp_for_static_end); + GETFUNC(_vcomp_for_static_init); + GETFUNC(_vcomp_for_static_simple_init); ++ GETFUNC(_vcomp_sections_init); ++ GETFUNC(_vcomp_sections_next); + + return TRUE; + } +@@ -183,6 +189,33 @@ static void test_vcomp_for_static_simple_init(void) + ok(nsum == 6*13, "expected sum 6*13, got %d\n", nsum); + } + ++int section_calls[3]; ++ ++static void CDECL _test_vcomp_sections_worker(void) ++{ ++ p_vcomp_sections_init(3); ++ ++ for (;;) ++ { ++ int i = p_vcomp_sections_next(); ++ if (i < 0 || i >= 3) break; ++ section_calls[i]++; ++ } ++ ++ p_vcomp_barrier(); ++} ++ ++static void test_vcomp_sections(void) ++{ ++ section_calls[0] = 0; ++ section_calls[1] = 0; ++ section_calls[2] = 0; ++ p_vcomp_fork(1, 0, _test_vcomp_sections_worker); ++ ok(section_calls[0] == 1, "section 0 not called once\n"); ++ ok(section_calls[1] == 1, "section 1 not called once\n"); ++ ok(section_calls[2] == 1, "section 2 not called once\n"); ++} ++ + START_TEST(work) + { + if (!init()) +@@ -191,4 +224,5 @@ START_TEST(work) + test_vcomp_for_dynamic(); + test_vcomp_for_static_init(); + test_vcomp_for_static_simple_init(); ++ test_vcomp_sections(); + } +diff --git a/dlls/vcomp/vcomp.spec b/dlls/vcomp/vcomp.spec +index f603660..1b02a65 100644 +--- a/dlls/vcomp/vcomp.spec ++++ b/dlls/vcomp/vcomp.spec +@@ -83,8 +83,8 @@ + @ stub _vcomp_reduction_u2 + @ stub _vcomp_reduction_u4 + @ stub _vcomp_reduction_u8 +-@ stub _vcomp_sections_init +-@ stub _vcomp_sections_next ++@ cdecl _vcomp_sections_init(long) ++@ cdecl _vcomp_sections_next() + @ cdecl _vcomp_set_num_threads(long) + @ cdecl _vcomp_single_begin(long) + @ cdecl _vcomp_single_end() +diff --git a/dlls/vcomp/vcomp_private.h b/dlls/vcomp/vcomp_private.h +index d3a7005..3d6c22b 100644 +--- a/dlls/vcomp/vcomp_private.h ++++ b/dlls/vcomp/vcomp_private.h +@@ -35,6 +35,11 @@ struct vcomp_team + int chunksize; + int flags; + } dyn_for; ++ struct ++ { ++ int counter; ++ int nsect; ++ } sections; + } work; + }; + +diff --git a/dlls/vcomp/work.c b/dlls/vcomp/work.c +index 87bce93..4370ec5 100644 +--- a/dlls/vcomp/work.c ++++ b/dlls/vcomp/work.c +@@ -97,3 +97,21 @@ void CDECL _vcomp_for_static_end(void) + { + TRACE("stub\n"); + } ++ ++void CDECL _vcomp_sections_init(int n) ++{ ++ struct vcomp_team *pt = vcomp_get_team(); ++ TRACE("(%d): stub\n", n); ++ pt->work.sections.counter = 0; ++ pt->work.sections.nsect = n; ++} ++ ++int CDECL _vcomp_sections_next(void) ++{ ++ struct vcomp_team *pt = vcomp_get_team(); ++ int i = pt->work.sections.counter++; ++ if (i >= pt->work.sections.nsect) ++ i = -1; ++ TRACE("stub; returning %d\n", i); ++ return i; ++} +diff --git a/dlls/vcomp100/vcomp100.spec b/dlls/vcomp100/vcomp100.spec +index 48d5e3f..ab93ec2 100644 +--- a/dlls/vcomp100/vcomp100.spec ++++ b/dlls/vcomp100/vcomp100.spec +@@ -83,8 +83,8 @@ + @ stub _vcomp_reduction_u2 + @ stub _vcomp_reduction_u4 + @ stub _vcomp_reduction_u8 +-@ stub _vcomp_sections_init +-@ stub _vcomp_sections_next ++@ cdecl _vcomp_sections_init(long) vcomp._vcomp_sections_init ++@ cdecl _vcomp_sections_next() vcomp._vcomp_sections_next + @ cdecl _vcomp_set_num_threads(long) vcomp._vcomp_set_num_threads + @ cdecl _vcomp_single_begin(long) vcomp._vcomp_single_begin + @ cdecl _vcomp_single_end() vcomp._vcomp_single_end +diff --git a/dlls/vcomp90/vcomp90.spec b/dlls/vcomp90/vcomp90.spec +index 48d5e3f..ab93ec2 100644 +--- a/dlls/vcomp90/vcomp90.spec ++++ b/dlls/vcomp90/vcomp90.spec +@@ -83,8 +83,8 @@ + @ stub _vcomp_reduction_u2 + @ stub _vcomp_reduction_u4 + @ stub _vcomp_reduction_u8 +-@ stub _vcomp_sections_init +-@ stub _vcomp_sections_next ++@ cdecl _vcomp_sections_init(long) vcomp._vcomp_sections_init ++@ cdecl _vcomp_sections_next() vcomp._vcomp_sections_next + @ cdecl _vcomp_set_num_threads(long) vcomp._vcomp_set_num_threads + @ cdecl _vcomp_single_begin(long) vcomp._vcomp_single_begin + @ cdecl _vcomp_single_end() vcomp._vcomp_single_end +-- +2.2.1 + diff --git a/patches/vcomp-Stub_Functions/0007-vcomp-Add-a-warning-that-multithreading-is-not-yet-s.patch b/patches/vcomp-Stub_Functions/0007-vcomp-Add-a-warning-that-multithreading-is-not-yet-s.patch new file mode 100644 index 00000000..8ac2a8df --- /dev/null +++ b/patches/vcomp-Stub_Functions/0007-vcomp-Add-a-warning-that-multithreading-is-not-yet-s.patch @@ -0,0 +1,25 @@ +From 5748aa15dd5e619714e9a04a033b30bd1fdae7d7 Mon Sep 17 00:00:00 2001 +From: Sebastian Lackner +Date: Thu, 29 Jan 2015 00:18:47 +0100 +Subject: vcomp: Add a warning that multithreading is not yet supported. + +--- + dlls/vcomp/main.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/dlls/vcomp/main.c b/dlls/vcomp/main.c +index e37cf16..1dd57dd 100644 +--- a/dlls/vcomp/main.c ++++ b/dlls/vcomp/main.c +@@ -126,6 +126,8 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) + ERR("Failed to allocate TLS index\n"); + return FALSE; + } ++ ++ FIXME("Builtin vcomp doesn't support multithreading, use native library for better performance.\n"); + break; + case DLL_PROCESS_DETACH: + TlsFree(vcomp_context_tls); +-- +2.2.1 + diff --git a/patches/vcomp-Stub_Functions/definition b/patches/vcomp-Stub_Functions/definition new file mode 100644 index 00000000..f2bb3c1a --- /dev/null +++ b/patches/vcomp-Stub_Functions/definition @@ -0,0 +1 @@ +Fixes: [31640] Implement additional stubs for vcomp dlls