From 7cb92a662b8eb0fdc179797a76c3be0aa64e4203 Mon Sep 17 00:00:00 2001 From: Elias Bachaalany Date: Wed, 26 Nov 2025 17:30:43 -0800 Subject: [PATCH 1/3] test: add Windows API threads test Add test_threads_winapi() that creates threads using CreateThread and WaitForMultipleObjects to complement the existing std::thread based test, verifying Windows threading API emulation works correctly. --- src/samples/test-sample/test.cpp | 49 ++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/src/samples/test-sample/test.cpp b/src/samples/test-sample/test.cpp index 2b405820..868c54a0 100644 --- a/src/samples/test-sample/test.cpp +++ b/src/samples/test-sample/test.cpp @@ -87,6 +87,54 @@ namespace return counter == (thread_count * 3ULL); } + bool test_threads_winapi() + { + struct ctx_t + { + int iterations; + int result; + }; + + static LPTHREAD_START_ROUTINE thread_proc = [](LPVOID lpParameter) -> DWORD { + ctx_t& c = *static_cast(lpParameter); + c.result = 0; + for (int i = 1; i <= c.iterations; i++) + { + ++c.result; + } + return 0; + }; + + constexpr int thread_count = 5; + HANDLE threads[thread_count] = {nullptr}; + ctx_t* ctxs[thread_count] = {nullptr}; + + for (int i = 0; i < thread_count; i++) + { + ctx_t* ctx = ctxs[i] = new ctx_t{5 * (i + 1), i - 2}; + threads[i] = CreateThread(nullptr, 0, thread_proc, ctx, 0, nullptr); + if (!threads[i]) + { + return false; + } + } + + WaitForMultipleObjects(thread_count, threads, TRUE, INFINITE); + + const int expected_results[thread_count] = {5, 10, 15, 20, 25}; + for (int i = 0; i < thread_count; i++) + { + if (ctxs[i]->result != expected_results[i]) + { + return false; + } + CloseHandle(threads[i]); + delete ctxs[i]; + } + + return true; + } + bool test_tls() { std::atomic_bool kill{false}; @@ -863,6 +911,7 @@ int main(const int argc, const char* argv[]) RUN_TEST(test_system_info, "System Info") RUN_TEST(test_time_zone, "Time Zone") RUN_TEST(test_threads, "Threads") + RUN_TEST(test_threads_winapi, "Threads WinAPI") RUN_TEST(test_env, "Environment") RUN_TEST(test_exceptions, "Exceptions") #ifndef __MINGW64__ From 4a905d562a4dc6a464bc05d9e0df94f29ea28fec Mon Sep 17 00:00:00 2001 From: Elias Bachaalany Date: Tue, 2 Dec 2025 15:44:21 -0800 Subject: [PATCH 2/3] Update src/samples/test-sample/test.cpp Co-authored-by: Maurice Heumann --- src/samples/test-sample/test.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/samples/test-sample/test.cpp b/src/samples/test-sample/test.cpp index 868c54a0..641b46a7 100644 --- a/src/samples/test-sample/test.cpp +++ b/src/samples/test-sample/test.cpp @@ -107,7 +107,7 @@ namespace constexpr int thread_count = 5; HANDLE threads[thread_count] = {nullptr}; - ctx_t* ctxs[thread_count] = {nullptr}; + ctx_t ctxs[thread_count] = {}; for (int i = 0; i < thread_count; i++) { From 651c020b87175abe5ec848306884037f986fa0b3 Mon Sep 17 00:00:00 2001 From: Elias Bachaalany Date: Tue, 2 Dec 2025 15:53:37 -0800 Subject: [PATCH 3/3] Use stack-allocated ctx_t array instead of heap allocation - Initialize ctxs[i] directly with aggregate initialization - Pass address of stack object to CreateThread - Use dot notation instead of arrow for member access - Remove delete calls since no heap allocation Co-authored-by: Maurice Heumann --- src/samples/test-sample/test.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/samples/test-sample/test.cpp b/src/samples/test-sample/test.cpp index 641b46a7..ef7bbdd9 100644 --- a/src/samples/test-sample/test.cpp +++ b/src/samples/test-sample/test.cpp @@ -111,8 +111,8 @@ namespace for (int i = 0; i < thread_count; i++) { - ctx_t* ctx = ctxs[i] = new ctx_t{5 * (i + 1), i - 2}; - threads[i] = CreateThread(nullptr, 0, thread_proc, ctx, 0, nullptr); + ctxs[i] = {5 * (i + 1), 0}; + threads[i] = CreateThread(nullptr, 0, thread_proc, &ctxs[i], 0, nullptr); if (!threads[i]) { return false; @@ -124,12 +124,11 @@ namespace const int expected_results[thread_count] = {5, 10, 15, 20, 25}; for (int i = 0; i < thread_count; i++) { - if (ctxs[i]->result != expected_results[i]) + if (ctxs[i].result != expected_results[i]) { return false; } CloseHandle(threads[i]); - delete ctxs[i]; } return true;