Commit f80ac265 authored by Arkadiusz Hiler's avatar Arkadiusz Hiler Committed by Alexandre Julliard

ucrtbase: Add tests for _beginthread[ex]().

parent 7435ca85
......@@ -2,9 +2,12 @@ TESTDLL = ucrtbase.dll
IMPORTS = ucrtbase
EXTRADEFS = -fno-builtin
C_SRCS = \
SOURCES = \
cpp.c \
misc.c \
printf.c \
scanf.c \
string.c
string.c \
thread.c \
threaddll.c \
threaddll.spec
/*
* 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 = WaitForSingleObject(args.confirm_running, 200);
ok(ret == WAIT_OBJECT_0, "Event was not signaled, ret: %u, err: %u\n", ret, GetLastError());
ok(FreeLibrary(dll), "Failed to free the library: %u\n", GetLastError());
ret = WaitForSingleObject(detach_event, 0);
ok(ret == WAIT_TIMEOUT, "Thread detach happened unexpectedly signaling an event, ret: %d, err: %u\n", ret, GetLastError());
ok(SetEvent(args.past_free), "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);
}
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", GetLastError());
}
/*
* 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 <windows.h>
#include "threaddll.h"
static HANDLE detach_event;
void CDECL _endthread(void);
void CDECL _endthreadex(unsigned int);
void WINAPI set_detach_event(HANDLE event)
{
detach_event = event;
}
static unsigned internal_thread_proc(void *param)
{
struct threaddll_args *args = param;
SetEvent(args->confirm_running);
WaitForSingleObject(args->past_free, INFINITE);
if (args->exit_method == thread_exit_endthread)
_endthread();
else if (args->exit_method == thread_exit_endthreadex)
_endthreadex(0);
return 0;
}
unsigned WINAPI stdcall_thread_proc(void *param)
{
return internal_thread_proc(param);
}
void CDECL cdecl_thread_proc(void *param)
{
internal_thread_proc(param);
}
BOOL WINAPI DllMain(HINSTANCE instance_new, DWORD reason, LPVOID reserved)
{
switch (reason)
{
case DLL_PROCESS_DETACH:
if (detach_event) SetEvent(detach_event);
break;
}
return TRUE;
}
/*
* 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
*/
enum thread_exit_method {
thread_exit_return,
thread_exit_endthread,
thread_exit_endthreadex
};
struct threaddll_args
{
HANDLE confirm_running;
HANDLE past_free;
enum thread_exit_method exit_method;
};
@ stdcall set_detach_event(ptr)
@ stdcall stdcall_thread_proc(ptr)
@ cdecl cdecl_thread_proc(ptr)
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment