Something went wrong. Try again.
Reactos
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188/* * Copyright 2021 Arkadiusz Hiler for CodeWeavers * * 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 <errno.h>#include <stdarg.h>#include <process.h>
#include <windef.h>#include <winbase.h>#include "wine/test.h"
#include "threaddll.h"
typedef void (__cdecl *_beginthread_start_routine_t)(void *);typedef unsigned int (__stdcall *_beginthreadex_start_routine_t)(void *);
enum beginthread_method{ use_beginthread, use_beginthreadex};
static char *get_thread_dll_path(void){ static char path[MAX_PATH]; const char dll_name[] = "threaddll.dll"; DWORD written; HANDLE file; HRSRC res; void *ptr;
GetTempPathA(ARRAY_SIZE(path), path); strcat(path, dll_name);
file = CreateFileA(path, GENERIC_READ|GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, 0); ok(file != INVALID_HANDLE_VALUE, "Failed to create file %s: %lu.\n", debugstr_a(path), GetLastError());
res = FindResourceA(NULL, dll_name, "TESTDLL"); ok(!!res, "Failed to load resource: %lu\n", GetLastError()); ptr = LockResource(LoadResource(GetModuleHandleA(NULL), res)); WriteFile(file, ptr, SizeofResource( GetModuleHandleA(NULL), res), &written, NULL); ok(written == SizeofResource(GetModuleHandleA(NULL), res), "Failed to write resource\n"); CloseHandle(file);
return path;}
static void set_thead_dll_detach_event(HANDLE dll, HANDLE event){ void (WINAPI *_set_detach_event)(HANDLE event); _set_detach_event = (void*) GetProcAddress(dll, "set_detach_event"); ok(_set_detach_event != NULL, "Failed to get set_detach_event: %lu\n", GetLastError()); _set_detach_event(event);}
static void test_thread_library_reference(char *thread_dll, enum beginthread_method beginthread_method, enum thread_exit_method exit_method){ HANDLE detach_event; HMODULE dll; DWORD ret; uintptr_t thread_handle; struct threaddll_args args;
args.exit_method = exit_method;
detach_event = CreateEventA(NULL, FALSE, FALSE, NULL); ok(detach_event != NULL, "Failed to create an event: %lu\n", GetLastError()); args.confirm_running = CreateEventA(NULL, FALSE, FALSE, NULL); ok(args.confirm_running != NULL, "Failed to create an event: %lu\n", GetLastError()); args.past_free = CreateEventA(NULL, FALSE, FALSE, NULL); ok(args.past_free != NULL, "Failed to create an event: %lu\n", GetLastError());
dll = LoadLibraryA(thread_dll); ok(dll != NULL, "Failed to load the test dll: %lu\n", GetLastError());
set_thead_dll_detach_event(dll, detach_event);
if (beginthread_method == use_beginthreadex) { _beginthreadex_start_routine_t proc = (void*) GetProcAddress(dll, "stdcall_thread_proc"); ok(proc != NULL, "Failed to get stdcall_thread_proc: %lu\n", GetLastError()); thread_handle = _beginthreadex(NULL, 0, proc, &args, 0, NULL); } else { _beginthread_start_routine_t proc = (void*) GetProcAddress(dll, "cdecl_thread_proc"); ok(proc != NULL, "Failed to get stdcall_thread_proc: %lu\n", GetLastError()); thread_handle = _beginthread(proc, 0, &args); }
ok(thread_handle != -1 && thread_handle != 0, "Failed to begin thread: %u\n", errno);
ret = FreeLibrary(dll); ok(ret, "Failed to free the library: %lu\n", GetLastError());
ret = WaitForSingleObject(args.confirm_running, 200); ok(ret == WAIT_OBJECT_0, "Event was not signaled, ret: %lu, err: %lu\n", ret, GetLastError());
ret = WaitForSingleObject(detach_event, 0); ok(ret == WAIT_TIMEOUT, "Thread detach happened unexpectedly signaling an event, ret: %ld, err: %lu\n", ret, GetLastError());
ret = SetEvent(args.past_free); ok(ret, "Failed to signal event: %ld\n", GetLastError());
if (beginthread_method == use_beginthreadex) { ret = WaitForSingleObject((HANDLE)thread_handle, 200); ok(ret == WAIT_OBJECT_0, "Thread has not exited, ret: %ld, err: %lu\n", ret, GetLastError()); }
ret = WaitForSingleObject(detach_event, 200); ok(ret == WAIT_OBJECT_0, "Detach event was not signaled, ret: %ld, err: %lu\n", ret, GetLastError());
if (beginthread_method == use_beginthreadex) CloseHandle((HANDLE)thread_handle);
CloseHandle(args.past_free); CloseHandle(args.confirm_running); CloseHandle(detach_event);}
static BOOL handler_called;
void CDECL test_invalid_parameter_handler(const wchar_t *expression, const wchar_t *function_name, const wchar_t *file_name, unsigned line_number, uintptr_t reserved){ handler_called = TRUE;}
static void test_thread_invalid_params(void){ uintptr_t hThread; _invalid_parameter_handler old = _set_invalid_parameter_handler(test_invalid_parameter_handler);
errno = 0; handler_called = FALSE; hThread = _beginthreadex(NULL, 0, NULL, NULL, 0, NULL); ok(hThread == 0, "_beginthreadex unexpected ret: %Iu\n", hThread); ok(errno == EINVAL, "_beginthreadex unexpected errno: %d\n", errno); ok(handler_called, "Expected invalid_parameter_handler to be called\n");
errno = 0; handler_called = FALSE; hThread = _beginthread(NULL, 0, NULL); ok(hThread == -1, "_beginthread unexpected ret: %Iu\n", hThread); ok(errno == EINVAL, "_beginthread unexpected errno: %d\n", errno); ok(handler_called, "Expected invalid_parameter_handler to be called\n");
_set_invalid_parameter_handler(old);}
START_TEST(thread){ BOOL ret; char *thread_dll = get_thread_dll_path();
test_thread_library_reference(thread_dll, use_beginthread, thread_exit_return); test_thread_library_reference(thread_dll, use_beginthread, thread_exit_endthread); test_thread_library_reference(thread_dll, use_beginthreadex, thread_exit_return); test_thread_library_reference(thread_dll, use_beginthreadex, thread_exit_endthreadex);
ret = DeleteFileA(thread_dll); ok(ret, "Failed to remove the test dll, err: %lu\n", GetLastError());
test_thread_invalid_params();}