mirror of
https://github.com/Gericom/teak-llvm.git
synced 2025-06-26 23:09:03 -04:00

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
79 lines
2.0 KiB
C++
79 lines
2.0 KiB
C++
//===- unittests/Threading.cpp - Thread tests -----------------------------===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "llvm/Support/Threading.h"
|
|
#include "llvm/Support/thread.h"
|
|
#include "gtest/gtest.h"
|
|
|
|
#include <atomic>
|
|
#include <condition_variable>
|
|
|
|
using namespace llvm;
|
|
|
|
namespace {
|
|
|
|
TEST(Threading, PhysicalConcurrency) {
|
|
auto Num = heavyweight_hardware_concurrency();
|
|
// Since Num is unsigned this will also catch us trying to
|
|
// return -1.
|
|
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
|