Reactos
at master 187 lines 6.9 kB view raw
1/* 2 * Copyright 2021 Arkadiusz Hiler for CodeWeavers 3 * 4 * This library is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU Lesser General Public 6 * License as published by the Free Software Foundation; either 7 * version 2.1 of the License, or (at your option) any later version. 8 * 9 * This library is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 * Lesser General Public License for more details. 13 * 14 * You should have received a copy of the GNU Lesser General Public 15 * License along with this library; if not, write to the Free Software 16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 17 */ 18 19#include <errno.h> 20#include <stdarg.h> 21#include <process.h> 22 23#include <windef.h> 24#include <winbase.h> 25#include "wine/test.h" 26 27#include "threaddll.h" 28 29typedef void (__cdecl *_beginthread_start_routine_t)(void *); 30typedef unsigned int (__stdcall *_beginthreadex_start_routine_t)(void *); 31 32enum beginthread_method 33{ 34 use_beginthread, 35 use_beginthreadex 36}; 37 38static char *get_thread_dll_path(void) 39{ 40 static char path[MAX_PATH]; 41 const char dll_name[] = "threaddll.dll"; 42 DWORD written; 43 HANDLE file; 44 HRSRC res; 45 void *ptr; 46 47 GetTempPathA(ARRAY_SIZE(path), path); 48 strcat(path, dll_name); 49 50 file = CreateFileA(path, GENERIC_READ|GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, 0); 51 ok(file != INVALID_HANDLE_VALUE, "Failed to create file %s: %lu.\n", 52 debugstr_a(path), GetLastError()); 53 54 res = FindResourceA(NULL, dll_name, "TESTDLL"); 55 ok(!!res, "Failed to load resource: %lu\n", GetLastError()); 56 ptr = LockResource(LoadResource(GetModuleHandleA(NULL), res)); 57 WriteFile(file, ptr, SizeofResource( GetModuleHandleA(NULL), res), &written, NULL); 58 ok(written == SizeofResource(GetModuleHandleA(NULL), res), "Failed to write resource\n"); 59 CloseHandle(file); 60 61 return path; 62} 63 64static void set_thead_dll_detach_event(HANDLE dll, HANDLE event) 65{ 66 void (WINAPI *_set_detach_event)(HANDLE event); 67 _set_detach_event = (void*) GetProcAddress(dll, "set_detach_event"); 68 ok(_set_detach_event != NULL, "Failed to get set_detach_event: %lu\n", GetLastError()); 69 _set_detach_event(event); 70} 71 72static void test_thread_library_reference(char *thread_dll, 73 enum beginthread_method beginthread_method, 74 enum thread_exit_method exit_method) 75{ 76 HANDLE detach_event; 77 HMODULE dll; 78 DWORD ret; 79 uintptr_t thread_handle; 80 struct threaddll_args args; 81 82 args.exit_method = exit_method; 83 84 detach_event = CreateEventA(NULL, FALSE, FALSE, NULL); 85 ok(detach_event != NULL, "Failed to create an event: %lu\n", GetLastError()); 86 args.confirm_running = CreateEventA(NULL, FALSE, FALSE, NULL); 87 ok(args.confirm_running != NULL, "Failed to create an event: %lu\n", GetLastError()); 88 args.past_free = CreateEventA(NULL, FALSE, FALSE, NULL); 89 ok(args.past_free != NULL, "Failed to create an event: %lu\n", GetLastError()); 90 91 dll = LoadLibraryA(thread_dll); 92 ok(dll != NULL, "Failed to load the test dll: %lu\n", GetLastError()); 93 94 set_thead_dll_detach_event(dll, detach_event); 95 96 if (beginthread_method == use_beginthreadex) 97 { 98 _beginthreadex_start_routine_t proc = (void*) GetProcAddress(dll, "stdcall_thread_proc"); 99 ok(proc != NULL, "Failed to get stdcall_thread_proc: %lu\n", GetLastError()); 100 thread_handle = _beginthreadex(NULL, 0, proc, &args, 0, NULL); 101 } 102 else 103 { 104 _beginthread_start_routine_t proc = (void*) GetProcAddress(dll, "cdecl_thread_proc"); 105 ok(proc != NULL, "Failed to get stdcall_thread_proc: %lu\n", GetLastError()); 106 thread_handle = _beginthread(proc, 0, &args); 107 } 108 109 ok(thread_handle != -1 && thread_handle != 0, "Failed to begin thread: %u\n", errno); 110 111 ret = FreeLibrary(dll); 112 ok(ret, "Failed to free the library: %lu\n", GetLastError()); 113 114 ret = WaitForSingleObject(args.confirm_running, 200); 115 ok(ret == WAIT_OBJECT_0, "Event was not signaled, ret: %lu, err: %lu\n", ret, GetLastError()); 116 117 ret = WaitForSingleObject(detach_event, 0); 118 ok(ret == WAIT_TIMEOUT, "Thread detach happened unexpectedly signaling an event, ret: %ld, err: %lu\n", ret, GetLastError()); 119 120 ret = SetEvent(args.past_free); 121 ok(ret, "Failed to signal event: %ld\n", GetLastError()); 122 123 if (beginthread_method == use_beginthreadex) 124 { 125 ret = WaitForSingleObject((HANDLE)thread_handle, 200); 126 ok(ret == WAIT_OBJECT_0, "Thread has not exited, ret: %ld, err: %lu\n", ret, GetLastError()); 127 } 128 129 ret = WaitForSingleObject(detach_event, 200); 130 ok(ret == WAIT_OBJECT_0, "Detach event was not signaled, ret: %ld, err: %lu\n", ret, GetLastError()); 131 132 if (beginthread_method == use_beginthreadex) 133 CloseHandle((HANDLE)thread_handle); 134 135 CloseHandle(args.past_free); 136 CloseHandle(args.confirm_running); 137 CloseHandle(detach_event); 138} 139 140static BOOL handler_called; 141 142void CDECL test_invalid_parameter_handler(const wchar_t *expression, 143 const wchar_t *function_name, 144 const wchar_t *file_name, 145 unsigned line_number, 146 uintptr_t reserved) 147{ 148 handler_called = TRUE; 149} 150 151static void test_thread_invalid_params(void) 152{ 153 uintptr_t hThread; 154 _invalid_parameter_handler old = _set_invalid_parameter_handler(test_invalid_parameter_handler); 155 156 errno = 0; 157 handler_called = FALSE; 158 hThread = _beginthreadex(NULL, 0, NULL, NULL, 0, NULL); 159 ok(hThread == 0, "_beginthreadex unexpected ret: %Iu\n", hThread); 160 ok(errno == EINVAL, "_beginthreadex unexpected errno: %d\n", errno); 161 ok(handler_called, "Expected invalid_parameter_handler to be called\n"); 162 163 errno = 0; 164 handler_called = FALSE; 165 hThread = _beginthread(NULL, 0, NULL); 166 ok(hThread == -1, "_beginthread unexpected ret: %Iu\n", hThread); 167 ok(errno == EINVAL, "_beginthread unexpected errno: %d\n", errno); 168 ok(handler_called, "Expected invalid_parameter_handler to be called\n"); 169 170 _set_invalid_parameter_handler(old); 171} 172 173START_TEST(thread) 174{ 175 BOOL ret; 176 char *thread_dll = get_thread_dll_path(); 177 178 test_thread_library_reference(thread_dll, use_beginthread, thread_exit_return); 179 test_thread_library_reference(thread_dll, use_beginthread, thread_exit_endthread); 180 test_thread_library_reference(thread_dll, use_beginthreadex, thread_exit_return); 181 test_thread_library_reference(thread_dll, use_beginthreadex, thread_exit_endthreadex); 182 183 ret = DeleteFileA(thread_dll); 184 ok(ret, "Failed to remove the test dll, err: %lu\n", GetLastError()); 185 186 test_thread_invalid_params(); 187}