diff --git a/.idea/vcs.xml b/.idea/vcs.xml index f0f41f0..94a25f7 100644 --- a/.idea/vcs.xml +++ b/.idea/vcs.xml @@ -2,6 +2,5 @@ - \ No newline at end of file diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index d0afa78..e572dbb 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -7,7 +7,6 @@ add_executable(mach_detours_tests test_threads.cpp test_transaction.cpp ) -target_compile_options(mach_detours_tests PRIVATE "-O0") # The target function must be in a shared library because otherwise it might be in the same code page as the test.cpp functions. # Between attach and commit the target function's code page is not executable, which can mean our test driver code would not @@ -16,11 +15,10 @@ add_library(mach_detours_tests_lib SHARED lib_function.c lib_function.h ) -target_compile_options(mach_detours_tests_lib PRIVATE "-O0") target_link_libraries(mach_detours_tests PRIVATE mach_detours Catch2::Catch2WithMain mach_detours_tests_lib -) +) \ No newline at end of file diff --git a/tests/test_local_function.cpp b/tests/test_local_function.cpp index 2f29e06..49b2d60 100644 --- a/tests/test_local_function.cpp +++ b/tests/test_local_function.cpp @@ -4,9 +4,6 @@ #include -// Note that this file must be compiled without optimizations (or at least without inlining) -// else localFunction() calls below are likely going to be inlined at the call site, and detours will not work. - static int localFunctionCounter = 0; int localFunction() { diff --git a/tests/test_threads.cpp b/tests/test_threads.cpp index f6d109f..11af631 100644 --- a/tests/test_threads.cpp +++ b/tests/test_threads.cpp @@ -1,6 +1,5 @@ // Copyright (c) Lysann Tranvouez. All rights reserved. -#include #include #include @@ -30,62 +29,33 @@ static const char* localFunctionDetour() } static const char* (*realLocalFunction)() = localFunction; -struct threadData -{ - std::atomic loopCounter; - bool cancel = false; -}; - static void* threadFunc(void* pUserArg) { - auto& data = *static_cast(pUserArg); - while (!data.cancel) { + const bool* pCancel = static_cast(pUserArg); + while (!*pCancel) { localFunction(); localFunction(); localFunction(); localFunction(); localFunction(); - ++data.loopCounter; } return nullptr; } -template -bool resetLoopCountersAndWaitForLoop(std::array& threadDatas, std::optional timeout = std::nullopt) -{ - for (auto i = 0; i < numThreads; i++) { - threadDatas[i].loopCounter = 0; - } - - const auto endTime = timeout ? std::make_optional(std::chrono::steady_clock::now() + *timeout) : std::nullopt; - while (true) { - // we check for >= 2 to be sure we did a full loop - we don't want to execute just the line incrementing the counter! - const bool anyLooped = std::ranges::any_of(threadDatas, [](const threadData& data){ return data.loopCounter >= 2; }); - if (anyLooped) { - return true; - } - if (endTime && std::chrono::steady_clock::now() > *endTime) { - return false; - } - usleep( 100 ); - } -} - TEST_CASE( "Handling other threads", "[attach][local][threads]" ) { - using namespace std::chrono_literals; + bool cancelThreads = false; constexpr auto numThreads = 150; pthread_t threads[numThreads]; - std::array threadDatas{}; for (auto i = 0; i < numThreads; i++) { - pthread_create(&threads[i], nullptr, threadFunc, (void*)&threadDatas[i]); + pthread_create(&threads[i], nullptr, threadFunc, (void*)&cancelThreads); } SECTION( "running threads modify a value" ) { const int saved_b = g_b; - resetLoopCountersAndWaitForLoop(threadDatas); + usleep( 1000 ); // let the threads update g_b a bit CHECK( saved_b != g_b ); } @@ -109,13 +79,13 @@ TEST_CASE( "Handling other threads", "[attach][local][threads]" ) } int saved_b = g_b; - resetLoopCountersAndWaitForLoop(threadDatas, 1s); + usleep( 1000 ); // let any running thread update g_b a bit CHECK( saved_b == g_b ); CHECK( detour_transaction_commit() == err_none ); saved_b = g_b; - resetLoopCountersAndWaitForLoop(threadDatas); + usleep( 1000 ); // let the threads update g_b a bit CHECK( saved_b != g_b ); } @@ -125,7 +95,7 @@ TEST_CASE( "Handling other threads", "[attach][local][threads]" ) CHECK( detour_transaction_abort() == err_none ); const int saved_b = g_b; - resetLoopCountersAndWaitForLoop(threadDatas); + usleep( 1000 ); // let the threads update g_b a bit CHECK( saved_b != g_b ); } @@ -138,17 +108,15 @@ TEST_CASE( "Handling other threads", "[attach][local][threads]" ) CHECK( detour_attach_and_commit(reinterpret_cast(&realLocalFunction), reinterpret_cast(localFunctionDetour)) == err_none ); const int saved_b = g_b; - resetLoopCountersAndWaitForLoop(threadDatas); - CHECK( saved_b == g_b ); + usleep( 1000 ); // let the threads update g_b a bit + CHECK( saved_b != g_b ); // clean up CHECK( detour_transaction_begin_managed() == err_none ); CHECK( detour_detach_and_commit(reinterpret_cast(&realLocalFunction), reinterpret_cast(localFunctionDetour)) == err_none ); } - for (auto i = 0; i < numThreads; i++) { - threadDatas[i].cancel = true; - } + cancelThreads = true; for (auto i = 0; i < numThreads; i++) { pthread_join(threads[i], nullptr); }