diff --git a/configure b/configure index 0472c80dccc..b0ac5962a41 100755 --- a/configure +++ b/configure @@ -17719,6 +17719,7 @@ wine_fn_config_test dlls/uxtheme/tests uxtheme_test wine_fn_config_dll vbscript enable_vbscript clean wine_fn_config_test dlls/vbscript/tests vbscript_test clean wine_fn_config_dll vcomp enable_vcomp +wine_fn_config_test dlls/vcomp/tests vcomp_test wine_fn_config_dll vcomp100 enable_vcomp100 wine_fn_config_dll vcomp90 enable_vcomp90 wine_fn_config_dll vdhcp.vxd enable_win16 diff --git a/configure.ac b/configure.ac index 9aab130228c..45b8fdba5a4 100644 --- a/configure.ac +++ b/configure.ac @@ -3322,6 +3322,7 @@ WINE_CONFIG_TEST(dlls/uxtheme/tests) WINE_CONFIG_DLL(vbscript,,[clean]) WINE_CONFIG_TEST(dlls/vbscript/tests,[clean]) WINE_CONFIG_DLL(vcomp) +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/tests/Makefile.in b/dlls/vcomp/tests/Makefile.in new file mode 100644 index 00000000000..d1b7b1291bd --- /dev/null +++ b/dlls/vcomp/tests/Makefile.in @@ -0,0 +1,4 @@ +TESTDLL = vcomp.dll + +C_SRCS = \ + vcomp.c diff --git a/dlls/vcomp/tests/vcomp.c b/dlls/vcomp/tests/vcomp.c new file mode 100644 index 00000000000..b084791894a --- /dev/null +++ b/dlls/vcomp/tests/vcomp.c @@ -0,0 +1,290 @@ +/* + * Unit test suite for vcomp + * + * Copyright 2015 Sebastian Lackner + * + * 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 char vcomp_manifest_file[MAX_PATH]; +static HANDLE vcomp_actctx_hctx; +static ULONG_PTR vcomp_actctx_cookie; +static HMODULE vcomp_handle; + +static HANDLE (WINAPI *pCreateActCtxA)(ACTCTXA*); +static BOOL (WINAPI *pActivateActCtx)(HANDLE, ULONG_PTR*); +static BOOL (WINAPI *pDeactivateActCtx)(DWORD, ULONG_PTR); +static VOID (WINAPI *pReleaseActCtx)(HANDLE); + +static void (CDECL *p_vcomp_barrier)(void); +static void (WINAPIV *p_vcomp_fork)(BOOL ifval, int nargs, void *wrapper, ...); +static void (CDECL *p_vcomp_set_num_threads)(int num_threads); +static int (CDECL *pomp_get_max_threads)(void); +static int (CDECL *pomp_get_nested)(void); +static int (CDECL *pomp_get_num_threads)(void); +static int (CDECL *pomp_get_thread_num)(void); +static void (CDECL *pomp_set_nested)(int nested); +static void (CDECL *pomp_set_num_threads)(int num_threads); + +#ifdef __i386__ +#define ARCH "x86" +#elif defined(__x86_64__) +#define ARCH "amd64" +#else +#define ARCH "none" +#endif + +static const char vcomp_manifest[] = + "\n" + "\n" + " \n" + "Wine vcomp test suite\n" + "\n" + " \n" + " \n" + " \n" + "\n" + "\n"; + +#undef ARCH + +static void create_vcomp_manifest(void) +{ + char temp_path[MAX_PATH]; + HMODULE kernel32; + DWORD written; + ACTCTXA ctx; + HANDLE file; + + kernel32 = GetModuleHandleA("kernel32.dll"); + pCreateActCtxA = (void *)GetProcAddress(kernel32, "CreateActCtxA"); + pActivateActCtx = (void *)GetProcAddress(kernel32, "ActivateActCtx"); + pDeactivateActCtx = (void *)GetProcAddress(kernel32, "DeactivateActCtx"); + pReleaseActCtx = (void *)GetProcAddress(kernel32, "ReleaseActCtx"); + if (!pCreateActCtxA) return; + + if (!GetTempPathA(sizeof(temp_path), temp_path) || + !GetTempFileNameA(temp_path, "vcomp", 0, vcomp_manifest_file)) + { + ok(0, "failed to create manifest file\n"); + return; + } + + file = CreateFileA(vcomp_manifest_file, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL); + if (file == INVALID_HANDLE_VALUE) + { + ok(0, "failed to open manifest file\n"); + return; + } + + if (!WriteFile(file, vcomp_manifest, sizeof(vcomp_manifest) - 1, &written, NULL)) + written = 0; + CloseHandle(file); + + if (written != sizeof(vcomp_manifest) - 1) + { + ok(0, "failed to write manifest file\n"); + DeleteFileA(vcomp_manifest_file); + return; + } + + memset(&ctx, 0, sizeof(ctx)); + ctx.cbSize = sizeof(ctx); + ctx.lpSource = vcomp_manifest_file; + vcomp_actctx_hctx = pCreateActCtxA(&ctx); + if (!vcomp_actctx_hctx) + { + ok(0, "failed to create activation context\n"); + DeleteFileA(vcomp_manifest_file); + return; + } + + if (!pActivateActCtx(vcomp_actctx_hctx, &vcomp_actctx_cookie)) + { + win_skip("failed to activate context\n"); + pReleaseActCtx(vcomp_actctx_hctx); + DeleteFileA(vcomp_manifest_file); + vcomp_actctx_hctx = NULL; + } +} + +static void release_vcomp(void) +{ + if (vcomp_handle) + FreeLibrary(vcomp_handle); + + if (vcomp_actctx_hctx) + { + pDeactivateActCtx(0, vcomp_actctx_cookie); + pReleaseActCtx(vcomp_actctx_hctx); + DeleteFileA(vcomp_manifest_file); + } +} + +#define VCOMP_GET_PROC(func) \ + do \ + { \ + p ## func = (void *)GetProcAddress(vcomp_handle, #func); \ + if (!p ## func) trace("Failed to get address for %s\n", #func); \ + } \ + while (0) + +static BOOL init_vcomp(void) +{ + create_vcomp_manifest(); + + vcomp_handle = LoadLibraryA("vcomp.dll"); + if (!vcomp_handle) + { + win_skip("vcomp.dll not installed\n"); + release_vcomp(); + return FALSE; + } + + VCOMP_GET_PROC(_vcomp_barrier); + VCOMP_GET_PROC(_vcomp_fork); + VCOMP_GET_PROC(_vcomp_set_num_threads); + VCOMP_GET_PROC(omp_get_max_threads); + VCOMP_GET_PROC(omp_get_nested); + VCOMP_GET_PROC(omp_get_num_threads); + VCOMP_GET_PROC(omp_get_thread_num); + VCOMP_GET_PROC(omp_set_nested); + VCOMP_GET_PROC(omp_set_num_threads); + + return TRUE; +} + +#undef VCOMP_GET_PROC + +static void CDECL num_threads_cb2(LONG *count) +{ + InterlockedIncrement(count); +} + +static void CDECL num_threads_cb(BOOL nested, int nested_threads, LONG *count) +{ + int num_threads, thread_num; + LONG thread_count; + + InterlockedIncrement(count); + p_vcomp_barrier(); + + num_threads = pomp_get_num_threads(); + ok(num_threads == *count, "expected num_threads == %d, got %d\n", *count, num_threads); + thread_num = pomp_get_thread_num(); + ok(thread_num >= 0 && thread_num < num_threads, + "expected thread_num in range [0, %d], got %d\n", num_threads - 1, thread_num); + + thread_count = 0; + p_vcomp_fork(TRUE, 1, num_threads_cb2, &thread_count); + if (nested) + ok(thread_count == nested_threads, "expected %d thread, got %d\n", nested_threads, thread_count); + else + ok(thread_count == 1, "expected 1 thread, got %d\n", thread_count); + + p_vcomp_set_num_threads(4); + thread_count = 0; + p_vcomp_fork(TRUE, 1, num_threads_cb2, &thread_count); + if (nested) + ok(thread_count == 4 , "expected 4 thread, got %d\n", thread_count); + else + ok(thread_count == 1 , "expected 1 thread, got %d\n", thread_count); +} + +static void test_omp_get_num_threads(BOOL nested) +{ + int is_nested, max_threads, num_threads, thread_num; + LONG thread_count; + + pomp_set_nested(nested); + is_nested = pomp_get_nested(); + ok(is_nested == nested, "expected %d, got %d\n", nested, is_nested); + + max_threads = pomp_get_max_threads(); + ok(max_threads >= 1, "expected max_threads >= 1, got %d\n", max_threads); + thread_num = pomp_get_thread_num(); + ok(thread_num == 0, "expected thread_num == 0, got %d\n", thread_num); + + num_threads = pomp_get_num_threads(); + ok(num_threads == 1, "expected num_threads == 1, got %d\n", num_threads); + thread_count = 0; + p_vcomp_fork(TRUE, 3, num_threads_cb, nested, max_threads, &thread_count); + ok(thread_count == max_threads, "expected %d threads, got %d\n", max_threads, thread_count); + + pomp_set_num_threads(2); + num_threads = pomp_get_num_threads(); + ok(num_threads == 1, "expected num_threads == 1, got %d\n", num_threads); + thread_count = 0; + p_vcomp_fork(TRUE, 3, num_threads_cb, nested, 2, &thread_count); + ok(thread_count == 2, "expected 2 threads, got %d\n", thread_count); + + pomp_set_num_threads(4); + num_threads = pomp_get_num_threads(); + ok(num_threads == 1, "expected num_threads == 1, got %d\n", num_threads); + thread_count = 0; + p_vcomp_fork(TRUE, 3, num_threads_cb, nested, 4, &thread_count); + ok(thread_count == 4, "expected 4 threads, got %d\n", thread_count); + + p_vcomp_set_num_threads(8); + num_threads = pomp_get_num_threads(); + ok(num_threads == 1, "expected num_threads == 1, got %d\n", num_threads); + thread_count = 0; + p_vcomp_fork(TRUE, 3, num_threads_cb, nested, 4, &thread_count); + ok(thread_count == 8, "expected 8 threads, got %d\n", thread_count); + thread_count = 0; + p_vcomp_fork(TRUE, 3, num_threads_cb, nested, 4, &thread_count); + ok(thread_count == 4, "expected 4 threads, got %d\n", thread_count); + + p_vcomp_set_num_threads(0); + num_threads = pomp_get_num_threads(); + ok(num_threads == 1, "expected num_threads == 1, got %d\n", num_threads); + thread_count = 0; + p_vcomp_fork(TRUE, 3, num_threads_cb, nested, 4, &thread_count); + ok(thread_count == 4, "expected 4 threads, got %d\n", thread_count); + + pomp_set_num_threads(0); + num_threads = pomp_get_num_threads(); + ok(num_threads == 1, "expected num_threads == 1, got %d\n", num_threads); + thread_count = 0; + p_vcomp_fork(TRUE, 3, num_threads_cb, nested, 4, &thread_count); + ok(thread_count == 4, "expected 4 threads, got %d\n", thread_count); + + pomp_set_num_threads(max_threads); + pomp_set_nested(FALSE); +} + +START_TEST(vcomp) +{ + if (!init_vcomp()) + return; + + test_omp_get_num_threads(FALSE); + test_omp_get_num_threads(TRUE); + + release_vcomp(); +}