mirror of
https://github.com/decompals/wibo.git
synced 2025-10-16 07:05:11 +00:00
Tests for handleapi, synchapi, processes
This commit is contained in:
parent
166b9036fd
commit
f52ca2803f
@ -210,6 +210,39 @@ if(BUILD_TESTING)
|
|||||||
${CMAKE_CURRENT_SOURCE_DIR}/test/test_threading.c
|
${CMAKE_CURRENT_SOURCE_DIR}/test/test_threading.c
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/test/test_assert.h)
|
${CMAKE_CURRENT_SOURCE_DIR}/test/test_assert.h)
|
||||||
|
|
||||||
|
add_custom_command(
|
||||||
|
OUTPUT ${WIBO_TEST_BIN_DIR}/test_handleapi.exe
|
||||||
|
COMMAND ${WIBO_MINGW_CC} -Wall -Wextra -O2
|
||||||
|
-I${CMAKE_CURRENT_SOURCE_DIR}/test
|
||||||
|
-o test_handleapi.exe
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/test/test_handleapi.c
|
||||||
|
WORKING_DIRECTORY ${WIBO_TEST_BIN_DIR}
|
||||||
|
DEPENDS
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/test/test_handleapi.c
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/test/test_assert.h)
|
||||||
|
|
||||||
|
add_custom_command(
|
||||||
|
OUTPUT ${WIBO_TEST_BIN_DIR}/test_synchapi.exe
|
||||||
|
COMMAND ${WIBO_MINGW_CC} -Wall -Wextra -O2
|
||||||
|
-I${CMAKE_CURRENT_SOURCE_DIR}/test
|
||||||
|
-o test_synchapi.exe
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/test/test_synchapi.c
|
||||||
|
WORKING_DIRECTORY ${WIBO_TEST_BIN_DIR}
|
||||||
|
DEPENDS
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/test/test_synchapi.c
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/test/test_assert.h)
|
||||||
|
|
||||||
|
add_custom_command(
|
||||||
|
OUTPUT ${WIBO_TEST_BIN_DIR}/test_processes.exe
|
||||||
|
COMMAND ${WIBO_MINGW_CC} -Wall -Wextra -O2
|
||||||
|
-I${CMAKE_CURRENT_SOURCE_DIR}/test
|
||||||
|
-o test_processes.exe
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/test/test_processes.c
|
||||||
|
WORKING_DIRECTORY ${WIBO_TEST_BIN_DIR}
|
||||||
|
DEPENDS
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/test/test_processes.c
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/test/test_assert.h)
|
||||||
|
|
||||||
add_custom_command(
|
add_custom_command(
|
||||||
OUTPUT ${WIBO_TEST_BIN_DIR}/test_heap.exe
|
OUTPUT ${WIBO_TEST_BIN_DIR}/test_heap.exe
|
||||||
COMMAND ${WIBO_MINGW_CC} -Wall -Wextra -O2
|
COMMAND ${WIBO_MINGW_CC} -Wall -Wextra -O2
|
||||||
@ -342,6 +375,9 @@ if(BUILD_TESTING)
|
|||||||
${WIBO_TEST_BIN_DIR}/test_bcrypt.exe
|
${WIBO_TEST_BIN_DIR}/test_bcrypt.exe
|
||||||
${WIBO_TEST_BIN_DIR}/test_resources.exe
|
${WIBO_TEST_BIN_DIR}/test_resources.exe
|
||||||
${WIBO_TEST_BIN_DIR}/test_threading.exe
|
${WIBO_TEST_BIN_DIR}/test_threading.exe
|
||||||
|
${WIBO_TEST_BIN_DIR}/test_handleapi.exe
|
||||||
|
${WIBO_TEST_BIN_DIR}/test_synchapi.exe
|
||||||
|
${WIBO_TEST_BIN_DIR}/test_processes.exe
|
||||||
${WIBO_TEST_BIN_DIR}/test_heap.exe
|
${WIBO_TEST_BIN_DIR}/test_heap.exe
|
||||||
${WIBO_TEST_BIN_DIR}/test_actctx.exe
|
${WIBO_TEST_BIN_DIR}/test_actctx.exe
|
||||||
${WIBO_TEST_BIN_DIR}/test_overlapped_io.exe
|
${WIBO_TEST_BIN_DIR}/test_overlapped_io.exe
|
||||||
@ -388,6 +424,24 @@ if(BUILD_TESTING)
|
|||||||
WORKING_DIRECTORY ${WIBO_TEST_BIN_DIR}
|
WORKING_DIRECTORY ${WIBO_TEST_BIN_DIR}
|
||||||
DEPENDS wibo.build_fixtures)
|
DEPENDS wibo.build_fixtures)
|
||||||
|
|
||||||
|
add_test(NAME wibo.test_handleapi
|
||||||
|
COMMAND $<TARGET_FILE:wibo> ${WIBO_TEST_BIN_DIR}/test_handleapi.exe)
|
||||||
|
set_tests_properties(wibo.test_handleapi PROPERTIES
|
||||||
|
WORKING_DIRECTORY ${WIBO_TEST_BIN_DIR}
|
||||||
|
DEPENDS wibo.build_fixtures)
|
||||||
|
|
||||||
|
add_test(NAME wibo.test_synchapi
|
||||||
|
COMMAND $<TARGET_FILE:wibo> ${WIBO_TEST_BIN_DIR}/test_synchapi.exe)
|
||||||
|
set_tests_properties(wibo.test_synchapi PROPERTIES
|
||||||
|
WORKING_DIRECTORY ${WIBO_TEST_BIN_DIR}
|
||||||
|
DEPENDS wibo.build_fixtures)
|
||||||
|
|
||||||
|
add_test(NAME wibo.test_processes
|
||||||
|
COMMAND $<TARGET_FILE:wibo> ${WIBO_TEST_BIN_DIR}/test_processes.exe)
|
||||||
|
set_tests_properties(wibo.test_processes PROPERTIES
|
||||||
|
WORKING_DIRECTORY ${WIBO_TEST_BIN_DIR}
|
||||||
|
DEPENDS wibo.build_fixtures)
|
||||||
|
|
||||||
add_test(NAME wibo.test_heap
|
add_test(NAME wibo.test_heap
|
||||||
COMMAND $<TARGET_FILE:wibo> ${WIBO_TEST_BIN_DIR}/test_heap.exe)
|
COMMAND $<TARGET_FILE:wibo> ${WIBO_TEST_BIN_DIR}/test_heap.exe)
|
||||||
set_tests_properties(wibo.test_heap PROPERTIES
|
set_tests_properties(wibo.test_heap PROPERTIES
|
||||||
|
@ -189,7 +189,7 @@ HANDLE WIN_FUNC CreateSemaphoreA(LPSECURITY_ATTRIBUTES lpSemaphoreAttributes, LO
|
|||||||
BOOL WIN_FUNC ReleaseSemaphore(HANDLE hSemaphore, LONG lReleaseCount, PLONG lpPreviousCount) {
|
BOOL WIN_FUNC ReleaseSemaphore(HANDLE hSemaphore, LONG lReleaseCount, PLONG lpPreviousCount) {
|
||||||
HOST_CONTEXT_GUARD();
|
HOST_CONTEXT_GUARD();
|
||||||
DEBUG_LOG("ReleaseSemaphore(%p, %ld, %p)\n", hSemaphore, lReleaseCount, lpPreviousCount);
|
DEBUG_LOG("ReleaseSemaphore(%p, %ld, %p)\n", hSemaphore, lReleaseCount, lpPreviousCount);
|
||||||
if (lReleaseCount <= 0) {
|
if (lReleaseCount < 0) {
|
||||||
wibo::lastError = ERROR_INVALID_PARAMETER;
|
wibo::lastError = ERROR_INVALID_PARAMETER;
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
@ -330,9 +330,8 @@ DWORD WIN_FUNC WaitForSingleObject(HANDLE hHandle, DWORD dwMilliseconds) {
|
|||||||
pthread_t self = pthread_self();
|
pthread_t self = pthread_self();
|
||||||
std::unique_lock lk(th->m);
|
std::unique_lock lk(th->m);
|
||||||
if (pthread_equal(th->thread, self)) {
|
if (pthread_equal(th->thread, self)) {
|
||||||
// Cannot wait on self
|
// Windows actually allows you to wait on your own thread, but why bother?
|
||||||
wibo::lastError = ERROR_INVALID_HANDLE;
|
return WAIT_TIMEOUT;
|
||||||
return WAIT_FAILED;
|
|
||||||
}
|
}
|
||||||
bool ok = doWait(lk, th->cv, [&] { return th->signaled.load(std::memory_order_acquire); });
|
bool ok = doWait(lk, th->cv, [&] { return th->signaled.load(std::memory_order_acquire); });
|
||||||
return ok ? WAIT_OBJECT_0 : WAIT_TIMEOUT;
|
return ok ? WAIT_OBJECT_0 : WAIT_TIMEOUT;
|
||||||
@ -341,9 +340,8 @@ DWORD WIN_FUNC WaitForSingleObject(HANDLE hHandle, DWORD dwMilliseconds) {
|
|||||||
auto po = std::move(obj).downcast<ProcessObject>();
|
auto po = std::move(obj).downcast<ProcessObject>();
|
||||||
std::unique_lock lk(po->m);
|
std::unique_lock lk(po->m);
|
||||||
if (po->pidfd == -1) {
|
if (po->pidfd == -1) {
|
||||||
// Cannot wait on self
|
// Windows actually allows you to wait on your own process, but why bother?
|
||||||
wibo::lastError = ERROR_INVALID_HANDLE;
|
return WAIT_TIMEOUT;
|
||||||
return WAIT_FAILED;
|
|
||||||
}
|
}
|
||||||
bool ok = doWait(lk, po->cv, [&] { return po->signaled.load(std::memory_order_acquire); });
|
bool ok = doWait(lk, po->cv, [&] { return po->signaled.load(std::memory_order_acquire); });
|
||||||
return ok ? WAIT_OBJECT_0 : WAIT_TIMEOUT;
|
return ok ? WAIT_OBJECT_0 : WAIT_TIMEOUT;
|
||||||
|
@ -186,6 +186,13 @@ bool Handles::duplicateTo(HANDLE src, Handles &dst, HANDLE &out, uint32_t desire
|
|||||||
|
|
||||||
uint32_t effAccess = (options & DUPLICATE_SAME_ACCESS) ? meta.grantedAccess : (desiredAccess & meta.grantedAccess);
|
uint32_t effAccess = (options & DUPLICATE_SAME_ACCESS) ? meta.grantedAccess : (desiredAccess & meta.grantedAccess);
|
||||||
const uint32_t flags = (inherit ? HANDLE_FLAG_INHERIT : 0);
|
const uint32_t flags = (inherit ? HANDLE_FLAG_INHERIT : 0);
|
||||||
|
|
||||||
|
// Reuse the same handle if duplicating within the same table and no changes
|
||||||
|
if (&dst == this && closeSource && effAccess == meta.grantedAccess && flags == meta.flags) {
|
||||||
|
out = src;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
out = dst.alloc(std::move(obj), effAccess, flags);
|
out = dst.alloc(std::move(obj), effAccess, flags);
|
||||||
|
|
||||||
if (closeSource) {
|
if (closeSource) {
|
||||||
|
@ -51,22 +51,21 @@ static void check_invalid_parameters(void) {
|
|||||||
data.cbSize = sizeof(data);
|
data.cbSize = sizeof(data);
|
||||||
GUID fakeGuid = {0};
|
GUID fakeGuid = {0};
|
||||||
SetLastError(0);
|
SetLastError(0);
|
||||||
BOOL ok = FindActCtxSectionStringW(0, &fakeGuid, ACTIVATION_CONTEXT_SECTION_DLL_REDIRECTION, L"msvcr80.dll", &data);
|
TEST_CHECK(
|
||||||
TEST_CHECK(!ok);
|
!FindActCtxSectionStringW(0, &fakeGuid, ACTIVATION_CONTEXT_SECTION_DLL_REDIRECTION, L"msvcr80.dll", &data));
|
||||||
TEST_CHECK_EQ(ERROR_INVALID_PARAMETER, GetLastError());
|
TEST_CHECK_EQ(ERROR_INVALID_PARAMETER, GetLastError());
|
||||||
|
|
||||||
ACTCTX_SECTION_KEYED_DATA sized = {0};
|
ACTCTX_SECTION_KEYED_DATA sized = {0};
|
||||||
sized.cbSize = sizeof(data) - 4;
|
sized.cbSize = sizeof(data) - 4;
|
||||||
SetLastError(0);
|
SetLastError(0);
|
||||||
ok = FindActCtxSectionStringW(0, NULL, ACTIVATION_CONTEXT_SECTION_DLL_REDIRECTION, L"msvcr80.dll", &sized);
|
TEST_CHECK(!FindActCtxSectionStringW(0, NULL, ACTIVATION_CONTEXT_SECTION_DLL_REDIRECTION, L"msvcr80.dll", &sized));
|
||||||
TEST_CHECK(!ok);
|
|
||||||
TEST_CHECK_EQ(ERROR_INSUFFICIENT_BUFFER, GetLastError());
|
TEST_CHECK_EQ(ERROR_INSUFFICIENT_BUFFER, GetLastError());
|
||||||
|
|
||||||
ACTCTX_SECTION_KEYED_DATA flags = {0};
|
ACTCTX_SECTION_KEYED_DATA flags = {0};
|
||||||
flags.cbSize = sizeof(flags);
|
flags.cbSize = sizeof(flags);
|
||||||
SetLastError(0);
|
SetLastError(0);
|
||||||
ok = FindActCtxSectionStringW(0x2, NULL, ACTIVATION_CONTEXT_SECTION_DLL_REDIRECTION, L"msvcr80.dll", &flags);
|
TEST_CHECK(
|
||||||
TEST_CHECK(!ok);
|
!FindActCtxSectionStringW(0x2, NULL, ACTIVATION_CONTEXT_SECTION_DLL_REDIRECTION, L"msvcr80.dll", &flags));
|
||||||
TEST_CHECK_EQ(ERROR_INVALID_PARAMETER, GetLastError());
|
TEST_CHECK_EQ(ERROR_INVALID_PARAMETER, GetLastError());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -74,17 +73,15 @@ static void check_missing_entries(void) {
|
|||||||
ACTCTX_SECTION_KEYED_DATA data = {0};
|
ACTCTX_SECTION_KEYED_DATA data = {0};
|
||||||
data.cbSize = sizeof(data);
|
data.cbSize = sizeof(data);
|
||||||
SetLastError(0);
|
SetLastError(0);
|
||||||
BOOL ok =
|
TEST_CHECK(
|
||||||
FindActCtxSectionStringW(0, NULL, ACTIVATION_CONTEXT_SECTION_DLL_REDIRECTION, L"totally_missing.dll", &data);
|
!FindActCtxSectionStringW(0, NULL, ACTIVATION_CONTEXT_SECTION_DLL_REDIRECTION, L"totally_missing.dll", &data));
|
||||||
TEST_CHECK(!ok);
|
|
||||||
TEST_CHECK_EQ(ERROR_SXS_KEY_NOT_FOUND, GetLastError());
|
TEST_CHECK_EQ(ERROR_SXS_KEY_NOT_FOUND, GetLastError());
|
||||||
|
|
||||||
ACTCTX_SECTION_KEYED_DATA wrongSection = {0};
|
ACTCTX_SECTION_KEYED_DATA wrongSection = {0};
|
||||||
wrongSection.cbSize = sizeof(wrongSection);
|
wrongSection.cbSize = sizeof(wrongSection);
|
||||||
SetLastError(0);
|
SetLastError(0);
|
||||||
ok = FindActCtxSectionStringW(0, NULL, ACTIVATION_CONTEXT_SECTION_ASSEMBLY_INFORMATION, L"msvcr80.dll",
|
TEST_CHECK(!FindActCtxSectionStringW(0, NULL, ACTIVATION_CONTEXT_SECTION_ASSEMBLY_INFORMATION, L"msvcr80.dll",
|
||||||
&wrongSection);
|
&wrongSection));
|
||||||
TEST_CHECK(!ok);
|
|
||||||
TEST_CHECK_EQ(ERROR_SXS_KEY_NOT_FOUND, GetLastError());
|
TEST_CHECK_EQ(ERROR_SXS_KEY_NOT_FOUND, GetLastError());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
101
test/test_handleapi.c
Normal file
101
test/test_handleapi.c
Normal file
@ -0,0 +1,101 @@
|
|||||||
|
#include "test_assert.h"
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <windows.h>
|
||||||
|
|
||||||
|
static void test_duplicate_handle_basic(void) {
|
||||||
|
HANDLE evt = CreateEventA(NULL, TRUE, FALSE, NULL);
|
||||||
|
TEST_CHECK(evt != NULL);
|
||||||
|
|
||||||
|
HANDLE dup = NULL;
|
||||||
|
BOOL ok = DuplicateHandle(GetCurrentProcess(), evt, GetCurrentProcess(), &dup, 0, FALSE, DUPLICATE_SAME_ACCESS);
|
||||||
|
TEST_CHECK(ok);
|
||||||
|
TEST_CHECK(dup != NULL);
|
||||||
|
TEST_CHECK(dup != evt);
|
||||||
|
|
||||||
|
TEST_CHECK(SetEvent(evt));
|
||||||
|
DWORD waitResult = WaitForSingleObject(dup, 0);
|
||||||
|
TEST_CHECK_EQ(WAIT_OBJECT_0, waitResult);
|
||||||
|
TEST_CHECK(ResetEvent(evt));
|
||||||
|
|
||||||
|
TEST_CHECK(CloseHandle(dup));
|
||||||
|
TEST_CHECK(CloseHandle(evt));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_duplicate_handle_close_source(void) {
|
||||||
|
HANDLE evt = CreateEventA(NULL, FALSE, FALSE, NULL);
|
||||||
|
TEST_CHECK(evt != NULL);
|
||||||
|
|
||||||
|
HANDLE dup = NULL;
|
||||||
|
BOOL ok = DuplicateHandle(GetCurrentProcess(), evt, GetCurrentProcess(), &dup, 0, FALSE,
|
||||||
|
DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE);
|
||||||
|
TEST_CHECK(ok);
|
||||||
|
TEST_CHECK(dup != NULL);
|
||||||
|
|
||||||
|
// Since we're duplicating within the same process with DUPLICATE_CLOSE_SOURCE,
|
||||||
|
// we should get back the same handle value
|
||||||
|
TEST_CHECK(dup == evt);
|
||||||
|
|
||||||
|
TEST_CHECK(SetEvent(dup));
|
||||||
|
TEST_CHECK_EQ(WAIT_OBJECT_0, WaitForSingleObject(dup, 0));
|
||||||
|
TEST_CHECK(CloseHandle(dup));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_duplicate_handle_invalid_source(void) {
|
||||||
|
HANDLE bogus = (HANDLE)(uintptr_t)0x1234;
|
||||||
|
HANDLE out = NULL;
|
||||||
|
SetLastError(0);
|
||||||
|
TEST_CHECK(
|
||||||
|
!DuplicateHandle(GetCurrentProcess(), bogus, GetCurrentProcess(), &out, 0, FALSE, DUPLICATE_SAME_ACCESS));
|
||||||
|
TEST_CHECK_EQ(ERROR_INVALID_HANDLE, GetLastError());
|
||||||
|
TEST_CHECK(out == NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_duplicate_handle_invalid_target_process(void) {
|
||||||
|
HANDLE evt = CreateEventA(NULL, TRUE, FALSE, NULL);
|
||||||
|
TEST_CHECK(evt != NULL);
|
||||||
|
|
||||||
|
HANDLE dup = NULL;
|
||||||
|
SetLastError(0xDEADBEEF);
|
||||||
|
TEST_CHECK(!DuplicateHandle(GetCurrentProcess(), evt, NULL, &dup, 0, FALSE, DUPLICATE_SAME_ACCESS));
|
||||||
|
TEST_CHECK_EQ(ERROR_INVALID_HANDLE, GetLastError());
|
||||||
|
TEST_CHECK(dup == NULL);
|
||||||
|
|
||||||
|
TEST_CHECK(CloseHandle(evt));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_duplicate_pseudo_process_handle(void) {
|
||||||
|
HANDLE pseudo = GetCurrentProcess();
|
||||||
|
HANDLE procHandle = NULL;
|
||||||
|
BOOL ok = DuplicateHandle(pseudo, pseudo, pseudo, &procHandle, 0, FALSE, DUPLICATE_SAME_ACCESS);
|
||||||
|
TEST_CHECK(ok);
|
||||||
|
TEST_CHECK(procHandle != NULL);
|
||||||
|
TEST_CHECK(procHandle != pseudo);
|
||||||
|
|
||||||
|
TEST_CHECK_EQ(WAIT_TIMEOUT, WaitForSingleObject(procHandle, 0));
|
||||||
|
|
||||||
|
TEST_CHECK(CloseHandle(procHandle));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_duplicate_handle_after_close(void) {
|
||||||
|
HANDLE evt = CreateEventA(NULL, TRUE, FALSE, NULL);
|
||||||
|
TEST_CHECK(evt != NULL);
|
||||||
|
|
||||||
|
TEST_CHECK(CloseHandle(evt));
|
||||||
|
|
||||||
|
HANDLE dup = NULL;
|
||||||
|
SetLastError(0);
|
||||||
|
TEST_CHECK(!DuplicateHandle(GetCurrentProcess(), evt, GetCurrentProcess(), &dup, 0, FALSE, DUPLICATE_SAME_ACCESS));
|
||||||
|
TEST_CHECK_EQ(ERROR_INVALID_HANDLE, GetLastError());
|
||||||
|
TEST_CHECK(dup == NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(void) {
|
||||||
|
test_duplicate_handle_basic();
|
||||||
|
test_duplicate_handle_close_source();
|
||||||
|
test_duplicate_handle_invalid_source();
|
||||||
|
test_duplicate_handle_invalid_target_process();
|
||||||
|
test_duplicate_pseudo_process_handle();
|
||||||
|
test_duplicate_handle_after_close();
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
@ -63,7 +63,7 @@ static void test_overlapped_read_with_event(void) {
|
|||||||
TEST_CHECK_EQ(ERROR_IO_PENDING, GetLastError());
|
TEST_CHECK_EQ(ERROR_IO_PENDING, GetLastError());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CHECK(WaitForSingleObject(ov.hEvent, INFINITE) == WAIT_OBJECT_0);
|
TEST_CHECK(WaitForSingleObject(ov.hEvent, 1000) == WAIT_OBJECT_0);
|
||||||
|
|
||||||
DWORD transferred = 0;
|
DWORD transferred = 0;
|
||||||
TEST_CHECK(GetOverlappedResult(file, &ov, &transferred, FALSE));
|
TEST_CHECK(GetOverlappedResult(file, &ov, &transferred, FALSE));
|
||||||
@ -91,7 +91,7 @@ static void test_overlapped_eof(void) {
|
|||||||
TEST_CHECK_EQ(ERROR_IO_PENDING, GetLastError());
|
TEST_CHECK_EQ(ERROR_IO_PENDING, GetLastError());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CHECK(WaitForSingleObject(ov.hEvent, INFINITE) == WAIT_OBJECT_0);
|
TEST_CHECK(WaitForSingleObject(ov.hEvent, 1000) == WAIT_OBJECT_0);
|
||||||
|
|
||||||
DWORD transferred = 1234;
|
DWORD transferred = 1234;
|
||||||
TEST_CHECK(!GetOverlappedResult(file, &ov, &transferred, FALSE));
|
TEST_CHECK(!GetOverlappedResult(file, &ov, &transferred, FALSE));
|
||||||
@ -127,7 +127,7 @@ static void test_overlapped_write(void) {
|
|||||||
if (!issued) {
|
if (!issued) {
|
||||||
TEST_CHECK_EQ(ERROR_IO_PENDING, GetLastError());
|
TEST_CHECK_EQ(ERROR_IO_PENDING, GetLastError());
|
||||||
}
|
}
|
||||||
TEST_CHECK(WaitForSingleObject(ov.hEvent, INFINITE) == WAIT_OBJECT_0);
|
TEST_CHECK(WaitForSingleObject(ov.hEvent, 1000) == WAIT_OBJECT_0);
|
||||||
|
|
||||||
DWORD transferred = 0;
|
DWORD transferred = 0;
|
||||||
TEST_CHECK(GetOverlappedResult(file, &ov, &transferred, FALSE));
|
TEST_CHECK(GetOverlappedResult(file, &ov, &transferred, FALSE));
|
||||||
|
@ -75,8 +75,7 @@ int main(void) {
|
|||||||
|
|
||||||
bytesRead = 123;
|
bytesRead = 123;
|
||||||
SetLastError(ERROR_GEN_FAILURE);
|
SetLastError(ERROR_GEN_FAILURE);
|
||||||
BOOL ok = ReadFile(readPipe, buffer, sizeof(buffer), &bytesRead, NULL);
|
TEST_CHECK(!ReadFile(readPipe, buffer, sizeof(buffer), &bytesRead, NULL));
|
||||||
TEST_CHECK(!ok);
|
|
||||||
TEST_CHECK_EQ(0u, (unsigned int)bytesRead);
|
TEST_CHECK_EQ(0u, (unsigned int)bytesRead);
|
||||||
TEST_CHECK_EQ(ERROR_BROKEN_PIPE, GetLastError());
|
TEST_CHECK_EQ(ERROR_BROKEN_PIPE, GetLastError());
|
||||||
TEST_CHECK(ResetEvent(event));
|
TEST_CHECK(ResetEvent(event));
|
||||||
|
116
test/test_processes.c
Normal file
116
test/test_processes.c
Normal file
@ -0,0 +1,116 @@
|
|||||||
|
#include "test_assert.h"
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <windows.h>
|
||||||
|
|
||||||
|
static DWORD parse_exit_code(const char *value) {
|
||||||
|
TEST_CHECK(value != NULL);
|
||||||
|
DWORD result = 0;
|
||||||
|
for (const char *p = value; *p; ++p) {
|
||||||
|
TEST_CHECK(*p >= '0' && *p <= '9');
|
||||||
|
result = result * 10u + (DWORD)(*p - '0');
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int child_main(int argc, char **argv) {
|
||||||
|
TEST_CHECK(argc >= 2);
|
||||||
|
(void)argv;
|
||||||
|
|
||||||
|
char exitBuffer[16];
|
||||||
|
DWORD exitLen = GetEnvironmentVariableA("WIBO_TEST_PROC_EXIT", exitBuffer, sizeof(exitBuffer));
|
||||||
|
TEST_CHECK(exitLen > 0 && exitLen < sizeof(exitBuffer));
|
||||||
|
DWORD desiredExit = parse_exit_code(exitBuffer);
|
||||||
|
|
||||||
|
Sleep(200);
|
||||||
|
return (int)desiredExit;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_createprocess_failure(void) {
|
||||||
|
STARTUPINFOA si;
|
||||||
|
PROCESS_INFORMATION pi;
|
||||||
|
ZeroMemory(&si, sizeof(si));
|
||||||
|
si.cb = sizeof(si);
|
||||||
|
ZeroMemory(&pi, sizeof(pi));
|
||||||
|
|
||||||
|
SetLastError(0);
|
||||||
|
char bogusCommandLine[] = "child";
|
||||||
|
TEST_CHECK(
|
||||||
|
!CreateProcessA("Z:/definitely/missing.exe", bogusCommandLine, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi));
|
||||||
|
DWORD error = GetLastError();
|
||||||
|
TEST_CHECK_MSG(error == ERROR_FILE_NOT_FOUND || error == ERROR_PATH_NOT_FOUND, "CreateProcessA missing file -> %lu",
|
||||||
|
(unsigned long)error);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int parent_main(void) {
|
||||||
|
test_createprocess_failure();
|
||||||
|
|
||||||
|
char modulePath[MAX_PATH];
|
||||||
|
DWORD pathLen = GetModuleFileNameA(NULL, modulePath, (DWORD)sizeof(modulePath));
|
||||||
|
TEST_CHECK(pathLen > 0 && pathLen < sizeof(modulePath));
|
||||||
|
|
||||||
|
const DWORD childExitCode = 0x24u;
|
||||||
|
char commandLine[256];
|
||||||
|
snprintf(commandLine, sizeof(commandLine), "child placeholder %lu", (unsigned long)childExitCode);
|
||||||
|
|
||||||
|
char exitEnv[16];
|
||||||
|
snprintf(exitEnv, sizeof(exitEnv), "%lu", (unsigned long)childExitCode);
|
||||||
|
TEST_CHECK(SetEnvironmentVariableA("WIBO_TEST_PROC_EXIT", exitEnv));
|
||||||
|
TEST_CHECK(SetEnvironmentVariableA("WIBO_TEST_PROC_ROLE", "child"));
|
||||||
|
|
||||||
|
STARTUPINFOA si;
|
||||||
|
PROCESS_INFORMATION pi;
|
||||||
|
ZeroMemory(&si, sizeof(si));
|
||||||
|
si.cb = sizeof(si);
|
||||||
|
GetStartupInfoA(&si);
|
||||||
|
ZeroMemory(&pi, sizeof(pi));
|
||||||
|
|
||||||
|
TEST_CHECK(CreateProcessA(modulePath, commandLine, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi));
|
||||||
|
TEST_CHECK(pi.hProcess != NULL);
|
||||||
|
SetEnvironmentVariableA("WIBO_TEST_PROC_EXIT", NULL);
|
||||||
|
SetEnvironmentVariableA("WIBO_TEST_PROC_ROLE", NULL);
|
||||||
|
|
||||||
|
HANDLE processHandle = NULL;
|
||||||
|
TEST_CHECK(DuplicateHandle(GetCurrentProcess(), pi.hProcess, GetCurrentProcess(), &processHandle, 0, FALSE,
|
||||||
|
DUPLICATE_SAME_ACCESS));
|
||||||
|
TEST_CHECK(processHandle != NULL);
|
||||||
|
TEST_CHECK(processHandle != pi.hProcess);
|
||||||
|
|
||||||
|
TEST_CHECK(CloseHandle(pi.hProcess));
|
||||||
|
TEST_CHECK_EQ(WAIT_FAILED, WaitForSingleObject(pi.hProcess, 0));
|
||||||
|
pi.hProcess = NULL;
|
||||||
|
|
||||||
|
Sleep(50);
|
||||||
|
|
||||||
|
TEST_CHECK_EQ(WAIT_TIMEOUT, WaitForSingleObject(processHandle, 0));
|
||||||
|
|
||||||
|
DWORD exitCode = 0;
|
||||||
|
TEST_CHECK(GetExitCodeProcess(processHandle, &exitCode));
|
||||||
|
TEST_CHECK_EQ(STILL_ACTIVE, exitCode);
|
||||||
|
|
||||||
|
TEST_CHECK_EQ(WAIT_TIMEOUT, WaitForSingleObject(processHandle, 10));
|
||||||
|
TEST_CHECK_EQ(WAIT_OBJECT_0, WaitForSingleObject(processHandle, 5000));
|
||||||
|
|
||||||
|
TEST_CHECK(GetExitCodeProcess(processHandle, &exitCode));
|
||||||
|
TEST_CHECK_EQ(childExitCode, exitCode);
|
||||||
|
|
||||||
|
TEST_CHECK(CloseHandle(processHandle));
|
||||||
|
if (pi.hThread) {
|
||||||
|
TEST_CHECK(CloseHandle(pi.hThread));
|
||||||
|
}
|
||||||
|
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char **argv) {
|
||||||
|
char role[16];
|
||||||
|
DWORD roleLen = GetEnvironmentVariableA("WIBO_TEST_PROC_ROLE", role, sizeof(role));
|
||||||
|
if (roleLen > 0 && roleLen < sizeof(role) && strcmp(role, "child") == 0) {
|
||||||
|
return child_main(argc, argv);
|
||||||
|
}
|
||||||
|
if (argc > 1 && strcmp(argv[1], "child") == 0) {
|
||||||
|
return child_main(argc, argv);
|
||||||
|
}
|
||||||
|
return parent_main();
|
||||||
|
}
|
142
test/test_synchapi.c
Normal file
142
test/test_synchapi.c
Normal file
@ -0,0 +1,142 @@
|
|||||||
|
#include "test_assert.h"
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <windows.h>
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
HANDLE mutex;
|
||||||
|
HANDLE acquiredEvent;
|
||||||
|
HANDLE releaseEvent;
|
||||||
|
HANDLE doneEvent;
|
||||||
|
} MutexWorkerContext;
|
||||||
|
|
||||||
|
static DWORD WINAPI mutex_worker(LPVOID param) {
|
||||||
|
MutexWorkerContext *ctx = (MutexWorkerContext *)param;
|
||||||
|
DWORD wait = WaitForSingleObject(ctx->mutex, 1000);
|
||||||
|
TEST_CHECK_EQ(WAIT_OBJECT_0, wait);
|
||||||
|
TEST_CHECK(SetEvent(ctx->acquiredEvent));
|
||||||
|
|
||||||
|
wait = WaitForSingleObject(ctx->releaseEvent, 1000);
|
||||||
|
TEST_CHECK_EQ(WAIT_OBJECT_0, wait);
|
||||||
|
TEST_CHECK(ReleaseMutex(ctx->mutex));
|
||||||
|
TEST_CHECK(SetEvent(ctx->doneEvent));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
HANDLE semaphore;
|
||||||
|
HANDLE ackEvent;
|
||||||
|
HANDLE doneEvent;
|
||||||
|
int iterations;
|
||||||
|
} SemaphoreWorkerContext;
|
||||||
|
|
||||||
|
static DWORD WINAPI semaphore_worker(LPVOID param) {
|
||||||
|
SemaphoreWorkerContext *ctx = (SemaphoreWorkerContext *)param;
|
||||||
|
for (int i = 0; i < ctx->iterations; ++i) {
|
||||||
|
DWORD wait = WaitForSingleObject(ctx->semaphore, 1000);
|
||||||
|
TEST_CHECK_EQ(WAIT_OBJECT_0, wait);
|
||||||
|
TEST_CHECK(SetEvent(ctx->ackEvent));
|
||||||
|
}
|
||||||
|
TEST_CHECK(SetEvent(ctx->doneEvent));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_mutex_contention(void) {
|
||||||
|
HANDLE mutex = CreateMutexA(NULL, FALSE, NULL);
|
||||||
|
TEST_CHECK(mutex != NULL);
|
||||||
|
|
||||||
|
HANDLE acquired = CreateEventA(NULL, FALSE, FALSE, NULL);
|
||||||
|
HANDLE releaseSignal = CreateEventA(NULL, FALSE, FALSE, NULL);
|
||||||
|
HANDLE done = CreateEventA(NULL, FALSE, FALSE, NULL);
|
||||||
|
TEST_CHECK(acquired != NULL && releaseSignal != NULL && done != NULL);
|
||||||
|
|
||||||
|
MutexWorkerContext ctx = {
|
||||||
|
.mutex = mutex,
|
||||||
|
.acquiredEvent = acquired,
|
||||||
|
.releaseEvent = releaseSignal,
|
||||||
|
.doneEvent = done,
|
||||||
|
};
|
||||||
|
|
||||||
|
HANDLE thread = CreateThread(NULL, 0, mutex_worker, &ctx, 0, NULL);
|
||||||
|
TEST_CHECK(thread != NULL);
|
||||||
|
|
||||||
|
DWORD wait = WaitForSingleObject(acquired, 1000);
|
||||||
|
TEST_CHECK_EQ(WAIT_OBJECT_0, wait);
|
||||||
|
|
||||||
|
wait = WaitForSingleObject(mutex, 10);
|
||||||
|
TEST_CHECK_EQ(WAIT_TIMEOUT, wait);
|
||||||
|
|
||||||
|
TEST_CHECK(SetEvent(releaseSignal));
|
||||||
|
|
||||||
|
wait = WaitForSingleObject(done, 1000);
|
||||||
|
TEST_CHECK_EQ(WAIT_OBJECT_0, wait);
|
||||||
|
|
||||||
|
wait = WaitForSingleObject(mutex, 1000);
|
||||||
|
TEST_CHECK_EQ(WAIT_OBJECT_0, wait);
|
||||||
|
|
||||||
|
wait = WaitForSingleObject(mutex, 0);
|
||||||
|
TEST_CHECK_EQ(WAIT_OBJECT_0, wait);
|
||||||
|
|
||||||
|
TEST_CHECK(ReleaseMutex(mutex));
|
||||||
|
TEST_CHECK(ReleaseMutex(mutex));
|
||||||
|
|
||||||
|
TEST_CHECK(CloseHandle(thread));
|
||||||
|
TEST_CHECK(CloseHandle(acquired));
|
||||||
|
TEST_CHECK(CloseHandle(releaseSignal));
|
||||||
|
TEST_CHECK(CloseHandle(done));
|
||||||
|
TEST_CHECK(CloseHandle(mutex));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_semaphore_waits(void) {
|
||||||
|
HANDLE semaphore = CreateSemaphoreA(NULL, 0, 3, NULL);
|
||||||
|
TEST_CHECK(semaphore != NULL);
|
||||||
|
|
||||||
|
DWORD wait = WaitForSingleObject(semaphore, 10);
|
||||||
|
TEST_CHECK_EQ(WAIT_TIMEOUT, wait);
|
||||||
|
|
||||||
|
HANDLE ack = CreateEventA(NULL, FALSE, FALSE, NULL);
|
||||||
|
HANDLE done = CreateEventA(NULL, FALSE, FALSE, NULL);
|
||||||
|
TEST_CHECK(ack != NULL && done != NULL);
|
||||||
|
|
||||||
|
SemaphoreWorkerContext ctx = {
|
||||||
|
.semaphore = semaphore,
|
||||||
|
.ackEvent = ack,
|
||||||
|
.doneEvent = done,
|
||||||
|
.iterations = 3,
|
||||||
|
};
|
||||||
|
|
||||||
|
HANDLE thread = CreateThread(NULL, 0, semaphore_worker, &ctx, 0, NULL);
|
||||||
|
TEST_CHECK(thread != NULL);
|
||||||
|
|
||||||
|
for (int i = 0; i < ctx.iterations; ++i) {
|
||||||
|
LONG previous = -1;
|
||||||
|
BOOL ok = ReleaseSemaphore(semaphore, 1, &previous);
|
||||||
|
TEST_CHECK(ok);
|
||||||
|
TEST_CHECK_EQ(0, previous);
|
||||||
|
DWORD ackWait = WaitForSingleObject(ack, 1000);
|
||||||
|
TEST_CHECK_EQ(WAIT_OBJECT_0, ackWait);
|
||||||
|
}
|
||||||
|
|
||||||
|
DWORD doneWait = WaitForSingleObject(done, 1000);
|
||||||
|
TEST_CHECK_EQ(WAIT_OBJECT_0, doneWait);
|
||||||
|
|
||||||
|
// lReleaseCount = 0 permitted; no effect
|
||||||
|
TEST_CHECK(ReleaseSemaphore(semaphore, 0, NULL));
|
||||||
|
|
||||||
|
HANDLE limited = CreateSemaphoreA(NULL, 1, 1, NULL);
|
||||||
|
TEST_CHECK(limited != NULL);
|
||||||
|
SetLastError(0);
|
||||||
|
TEST_CHECK(!ReleaseSemaphore(limited, 1, NULL));
|
||||||
|
TEST_CHECK_EQ(ERROR_TOO_MANY_POSTS, GetLastError());
|
||||||
|
|
||||||
|
TEST_CHECK(CloseHandle(thread));
|
||||||
|
TEST_CHECK(CloseHandle(ack));
|
||||||
|
TEST_CHECK(CloseHandle(done));
|
||||||
|
TEST_CHECK(CloseHandle(semaphore));
|
||||||
|
TEST_CHECK(CloseHandle(limited));
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(void) {
|
||||||
|
test_mutex_contention();
|
||||||
|
test_semaphore_waits();
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
@ -52,9 +52,9 @@ int main(void) {
|
|||||||
|
|
||||||
HANDLE thread = CreateThread(NULL, 0, workerProc, NULL, 0, NULL);
|
HANDLE thread = CreateThread(NULL, 0, workerProc, NULL, 0, NULL);
|
||||||
TEST_CHECK_MSG(thread != NULL, "CreateThread failed: %lu", (unsigned long)GetLastError());
|
TEST_CHECK_MSG(thread != NULL, "CreateThread failed: %lu", (unsigned long)GetLastError());
|
||||||
DWORD wait_result = WaitForSingleObject(thread, INFINITE);
|
DWORD wait_result = WaitForSingleObject(thread, 1000);
|
||||||
TEST_CHECK_EQ(WAIT_OBJECT_0, wait_result);
|
TEST_CHECK_EQ(WAIT_OBJECT_0, wait_result);
|
||||||
TEST_CHECK_MSG(CloseHandle(thread) != 0, "CloseHandle(thread) failed: %lu", (unsigned long)GetLastError());
|
TEST_CHECK(CloseHandle(thread));
|
||||||
|
|
||||||
TEST_CHECK_EQ(1, getAttach());
|
TEST_CHECK_EQ(1, getAttach());
|
||||||
TEST_CHECK_EQ(1, getDetach());
|
TEST_CHECK_EQ(1, getDetach());
|
||||||
@ -68,9 +68,9 @@ int main(void) {
|
|||||||
|
|
||||||
thread = CreateThread(NULL, 0, workerProc, NULL, 0, NULL);
|
thread = CreateThread(NULL, 0, workerProc, NULL, 0, NULL);
|
||||||
TEST_CHECK_MSG(thread != NULL, "CreateThread after disable failed: %lu", (unsigned long)GetLastError());
|
TEST_CHECK_MSG(thread != NULL, "CreateThread after disable failed: %lu", (unsigned long)GetLastError());
|
||||||
wait_result = WaitForSingleObject(thread, INFINITE);
|
wait_result = WaitForSingleObject(thread, 1000);
|
||||||
TEST_CHECK_EQ(WAIT_OBJECT_0, wait_result);
|
TEST_CHECK_EQ(WAIT_OBJECT_0, wait_result);
|
||||||
TEST_CHECK_MSG(CloseHandle(thread) != 0, "CloseHandle(second thread) failed: %lu", (unsigned long)GetLastError());
|
TEST_CHECK(CloseHandle(thread));
|
||||||
|
|
||||||
if (!isRunningUnderWine()) {
|
if (!isRunningUnderWine()) {
|
||||||
TEST_CHECK_EQ(0, getAttach());
|
TEST_CHECK_EQ(0, getAttach());
|
||||||
@ -80,7 +80,7 @@ int main(void) {
|
|||||||
LONG final_attach = getAttach();
|
LONG final_attach = getAttach();
|
||||||
LONG final_detach = getDetach();
|
LONG final_detach = getDetach();
|
||||||
|
|
||||||
TEST_CHECK_MSG(FreeLibrary(mod) != 0, "FreeLibrary failed: %lu", (unsigned long)GetLastError());
|
TEST_CHECK(FreeLibrary(mod));
|
||||||
|
|
||||||
printf("thread_notifications: attach=%ld detach=%ld\n", (long)final_attach, (long)final_detach);
|
printf("thread_notifications: attach=%ld detach=%ld\n", (long)final_attach, (long)final_detach);
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
|
@ -11,7 +11,7 @@ typedef struct {
|
|||||||
static DWORD WINAPI worker_main(LPVOID param) {
|
static DWORD WINAPI worker_main(LPVOID param) {
|
||||||
WorkerContext *ctx = (WorkerContext *)param;
|
WorkerContext *ctx = (WorkerContext *)param;
|
||||||
TEST_CHECK(SetEvent(ctx->readyEvent));
|
TEST_CHECK(SetEvent(ctx->readyEvent));
|
||||||
DWORD waitResult = WaitForSingleObject(ctx->goEvent, INFINITE);
|
DWORD waitResult = WaitForSingleObject(ctx->goEvent, 1000);
|
||||||
TEST_CHECK_EQ(WAIT_OBJECT_0, waitResult);
|
TEST_CHECK_EQ(WAIT_OBJECT_0, waitResult);
|
||||||
return ctx->exitCode;
|
return ctx->exitCode;
|
||||||
}
|
}
|
||||||
@ -37,14 +37,14 @@ int main(void) {
|
|||||||
HANDLE thread = CreateThread(NULL, 0, worker_main, &ctx, 0, NULL);
|
HANDLE thread = CreateThread(NULL, 0, worker_main, &ctx, 0, NULL);
|
||||||
TEST_CHECK(thread != NULL);
|
TEST_CHECK(thread != NULL);
|
||||||
|
|
||||||
DWORD waitResult = WaitForSingleObject(readyEvent, INFINITE);
|
DWORD waitResult = WaitForSingleObject(readyEvent, 1000);
|
||||||
TEST_CHECK_EQ(WAIT_OBJECT_0, waitResult);
|
TEST_CHECK_EQ(WAIT_OBJECT_0, waitResult);
|
||||||
|
|
||||||
TEST_CHECK(ResetEvent(readyEvent));
|
TEST_CHECK(ResetEvent(readyEvent));
|
||||||
|
|
||||||
TEST_CHECK(SetEvent(goEvent));
|
TEST_CHECK(SetEvent(goEvent));
|
||||||
|
|
||||||
waitResult = WaitForSingleObject(thread, INFINITE);
|
waitResult = WaitForSingleObject(thread, 1000);
|
||||||
TEST_CHECK_EQ(WAIT_OBJECT_0, waitResult);
|
TEST_CHECK_EQ(WAIT_OBJECT_0, waitResult);
|
||||||
|
|
||||||
DWORD exitCode = 0;
|
DWORD exitCode = 0;
|
||||||
@ -56,21 +56,21 @@ int main(void) {
|
|||||||
HANDLE autoEvent = CreateEventA(NULL, FALSE, FALSE, NULL);
|
HANDLE autoEvent = CreateEventA(NULL, FALSE, FALSE, NULL);
|
||||||
TEST_CHECK(autoEvent != NULL);
|
TEST_CHECK(autoEvent != NULL);
|
||||||
TEST_CHECK(SetEvent(autoEvent));
|
TEST_CHECK(SetEvent(autoEvent));
|
||||||
waitResult = WaitForSingleObject(autoEvent, INFINITE);
|
waitResult = WaitForSingleObject(autoEvent, 0);
|
||||||
TEST_CHECK_EQ(WAIT_OBJECT_0, waitResult);
|
TEST_CHECK_EQ(WAIT_OBJECT_0, waitResult);
|
||||||
TEST_CHECK(SetEvent(autoEvent));
|
TEST_CHECK(SetEvent(autoEvent));
|
||||||
waitResult = WaitForSingleObject(autoEvent, INFINITE);
|
waitResult = WaitForSingleObject(autoEvent, 0);
|
||||||
TEST_CHECK_EQ(WAIT_OBJECT_0, waitResult);
|
TEST_CHECK_EQ(WAIT_OBJECT_0, waitResult);
|
||||||
TEST_CHECK(CloseHandle(autoEvent));
|
TEST_CHECK(CloseHandle(autoEvent));
|
||||||
|
|
||||||
HANDLE manualEvent = CreateEventA(NULL, TRUE, FALSE, NULL);
|
HANDLE manualEvent = CreateEventA(NULL, TRUE, FALSE, NULL);
|
||||||
TEST_CHECK(manualEvent != NULL);
|
TEST_CHECK(manualEvent != NULL);
|
||||||
TEST_CHECK(SetEvent(manualEvent));
|
TEST_CHECK(SetEvent(manualEvent));
|
||||||
waitResult = WaitForSingleObject(manualEvent, INFINITE);
|
waitResult = WaitForSingleObject(manualEvent, 0);
|
||||||
TEST_CHECK_EQ(WAIT_OBJECT_0, waitResult);
|
TEST_CHECK_EQ(WAIT_OBJECT_0, waitResult);
|
||||||
TEST_CHECK(ResetEvent(manualEvent));
|
TEST_CHECK(ResetEvent(manualEvent));
|
||||||
TEST_CHECK(SetEvent(manualEvent));
|
TEST_CHECK(SetEvent(manualEvent));
|
||||||
waitResult = WaitForSingleObject(manualEvent, INFINITE);
|
waitResult = WaitForSingleObject(manualEvent, 0);
|
||||||
TEST_CHECK_EQ(WAIT_OBJECT_0, waitResult);
|
TEST_CHECK_EQ(WAIT_OBJECT_0, waitResult);
|
||||||
TEST_CHECK(CloseHandle(manualEvent));
|
TEST_CHECK(CloseHandle(manualEvent));
|
||||||
|
|
||||||
@ -80,7 +80,7 @@ int main(void) {
|
|||||||
|
|
||||||
HANDLE mutex = CreateMutexA(NULL, FALSE, NULL);
|
HANDLE mutex = CreateMutexA(NULL, FALSE, NULL);
|
||||||
TEST_CHECK(mutex != NULL);
|
TEST_CHECK(mutex != NULL);
|
||||||
waitResult = WaitForSingleObject(mutex, INFINITE);
|
waitResult = WaitForSingleObject(mutex, 0);
|
||||||
TEST_CHECK_EQ(WAIT_OBJECT_0, waitResult);
|
TEST_CHECK_EQ(WAIT_OBJECT_0, waitResult);
|
||||||
TEST_CHECK(ReleaseMutex(mutex));
|
TEST_CHECK(ReleaseMutex(mutex));
|
||||||
TEST_CHECK(CloseHandle(mutex));
|
TEST_CHECK(CloseHandle(mutex));
|
||||||
@ -88,7 +88,7 @@ int main(void) {
|
|||||||
DWORD secondExitCode = 0x55AA;
|
DWORD secondExitCode = 0x55AA;
|
||||||
HANDLE exitThread = CreateThread(NULL, 0, exit_thread_worker, &secondExitCode, 0, NULL);
|
HANDLE exitThread = CreateThread(NULL, 0, exit_thread_worker, &secondExitCode, 0, NULL);
|
||||||
TEST_CHECK(exitThread != NULL);
|
TEST_CHECK(exitThread != NULL);
|
||||||
waitResult = WaitForSingleObject(exitThread, INFINITE);
|
waitResult = WaitForSingleObject(exitThread, 1000);
|
||||||
TEST_CHECK_EQ(WAIT_OBJECT_0, waitResult);
|
TEST_CHECK_EQ(WAIT_OBJECT_0, waitResult);
|
||||||
exitCode = 0;
|
exitCode = 0;
|
||||||
TEST_CHECK(GetExitCodeThread(exitThread, &exitCode));
|
TEST_CHECK(GetExitCodeThread(exitThread, &exitCode));
|
||||||
|
Loading…
x
Reference in New Issue
Block a user