diff options
author | Sam McCall <sammccall@google.com> | 2019-10-23 12:36:36 +0200 |
---|---|---|
committer | Sam McCall <sammccall@google.com> | 2019-10-23 12:48:38 +0200 |
commit | 40668abca4d307e02b33345cfdb7271549ff48d0 (patch) | |
tree | 8a5fcbf77abeb5a2d362182cef542215e742c0d4 /llvm/unittests/Support | |
parent | 4b63ca1379a8a6399c3d29560623ee832c818919 (diff) | |
download | bcm5719-llvm-40668abca4d307e02b33345cfdb7271549ff48d0.tar.gz bcm5719-llvm-40668abca4d307e02b33345cfdb7271549ff48d0.zip |
[Support] Add a way to run a function on a detached thread
This roughly mimics `std::thread(...).detach()` except it allows to
customize the stack size. Required for https://reviews.llvm.org/D50993.
I've decided against reusing the existing `llvm_execute_on_thread` because
it's not obvious what to do with the ownership of the passed
function/arguments:
1. If we pass possibly owning functions data to `llvm_execute_on_thread`,
we'll lose the ability to pass small non-owning non-allocating functions
for the joining case (as it's used now). Is it important enough?
2. If we use the non-owning interface in the new use case, we'll force
clients to transfer ownership to the spawned thread manually, but
similar code would still have to exist inside
`llvm_execute_on_thread(_async)` anyway (as we can't just pass the same
non-owning pointer to pthreads and Windows implementations, and would be
forced to wrap it in some structure, and deal with its ownership.
Patch by Dmitry Kozhevnikov!
Differential Revision: https://reviews.llvm.org/D51103
Diffstat (limited to 'llvm/unittests/Support')
-rw-r--r-- | llvm/unittests/Support/Threading.cpp | 54 |
1 files changed, 54 insertions, 0 deletions
diff --git a/llvm/unittests/Support/Threading.cpp b/llvm/unittests/Support/Threading.cpp index 01f1c513448..21baa55ef44 100644 --- a/llvm/unittests/Support/Threading.cpp +++ b/llvm/unittests/Support/Threading.cpp @@ -10,6 +10,9 @@ #include "llvm/Support/thread.h" #include "gtest/gtest.h" +#include <atomic> +#include <condition_variable> + using namespace llvm; namespace { @@ -21,4 +24,55 @@ TEST(Threading, PhysicalConcurrency) { ASSERT_LE(Num, thread::hardware_concurrency()); } +#if LLVM_ENABLE_THREADS + +class Notification { +public: + void notify() { + { + std::lock_guard<std::mutex> Lock(M); + Notified = true; + } + CV.notify_all(); + } + + bool wait() { + std::unique_lock<std::mutex> Lock(M); + using steady_clock = std::chrono::steady_clock; + auto Deadline = steady_clock::now() + + std::chrono::duration_cast<steady_clock::duration>( + std::chrono::duration<double>(5)); + return CV.wait_until(Lock, Deadline, [this] { return Notified; }); + } + +private: + bool Notified = false; + mutable std::condition_variable CV; + mutable std::mutex M; +}; + +TEST(Threading, RunOnThreadSyncAsync) { + Notification ThreadStarted, ThreadAdvanced, ThreadFinished; + + auto ThreadFunc = [&] { + ThreadStarted.notify(); + ASSERT_TRUE(ThreadAdvanced.wait()); + ThreadFinished.notify(); + }; + + llvm::llvm_execute_on_thread_async(ThreadFunc); + ASSERT_TRUE(ThreadStarted.wait()); + ThreadAdvanced.notify(); + ASSERT_TRUE(ThreadFinished.wait()); +} + +TEST(Threading, RunOnThreadSync) { + std::atomic_bool Executed(false); + llvm::llvm_execute_on_thread( + [](void *Arg) { *static_cast<std::atomic_bool *>(Arg) = true; }, + &Executed); + ASSERT_EQ(Executed, true); +} +#endif + } // end anon namespace |