Sweden-Number/dlls/ucrtbase/tests/thread.c

185 lines
6.6 KiB
C

/*
* 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"
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: %u.\n",
debugstr_a(path), GetLastError());
res = FindResourceA(NULL, dll_name, "TESTDLL");
ok(!!res, "Failed to load resource: %u\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: %u\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: %u\n", GetLastError());
args.confirm_running = CreateEventA(NULL, FALSE, FALSE, NULL);
ok(args.confirm_running != NULL, "Failed to create an event: %u\n", GetLastError());
args.past_free = CreateEventA(NULL, FALSE, FALSE, NULL);
ok(args.past_free != NULL, "Failed to create an event: %u\n", GetLastError());
dll = LoadLibraryA(thread_dll);
ok(dll != NULL, "Failed to load the test dll: %u\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: %u\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: %u\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: %u\n", GetLastError());
ret = WaitForSingleObject(args.confirm_running, 200);
ok(ret == WAIT_OBJECT_0, "Event was not signaled, ret: %u, err: %u\n", ret, GetLastError());
ret = WaitForSingleObject(detach_event, 0);
ok(ret == WAIT_TIMEOUT, "Thread detach happened unexpectedly signaling an event, ret: %d, err: %u\n", ret, GetLastError());
ret = SetEvent(args.past_free);
ok(ret, "Failed to signal event: %d\n", GetLastError());
if (beginthread_method == use_beginthreadex)
{
ret = WaitForSingleObject((HANDLE)thread_handle, 200);
ok(ret == WAIT_OBJECT_0, "Thread has not exited, ret: %d, err: %u\n", ret, GetLastError());
}
ret = WaitForSingleObject(detach_event, 200);
ok(ret == WAIT_OBJECT_0, "Detach event was not signaled, ret: %d, err: %u\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: %d\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: %d\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: %u\n", GetLastError());
test_thread_invalid_params();
}