111 lines · cpp
1//===-- ThreadPoolTaskDispatcherTest.cpp ----------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "orc-rt/ThreadPoolTaskDispatcher.h"10#include "gtest/gtest.h"11 12#include <atomic>13#include <future>14#include <thread>15#include <vector>16 17using namespace orc_rt;18 19namespace {20 21TEST(ThreadPoolTaskDispatcherTest, NoTasks) {22 // Check that immediate shutdown works as expected.23 ThreadPoolTaskDispatcher Dispatcher(1);24 Dispatcher.shutdown();25}26 27TEST(ThreadPoolTaskDispatcherTest, BasicTaskExecution) {28 // Smoke test: Check that we can run a single task on a single-threaded pool.29 ThreadPoolTaskDispatcher Dispatcher(1);30 std::atomic<bool> TaskRan = false;31 32 Dispatcher.dispatch(makeGenericTask([&]() { TaskRan = true; }));33 34 Dispatcher.shutdown();35 36 EXPECT_TRUE(TaskRan);37}38 39TEST(ThreadPoolTaskDispatcherTest, SingleThreadMultipleTasks) {40 // Check that multiple tasks in a single threaded pool run as expected.41 ThreadPoolTaskDispatcher Dispatcher(1);42 size_t NumTasksToRun = 10;43 std::atomic<size_t> TasksRun = 0;44 45 for (size_t I = 0; I != NumTasksToRun; ++I)46 Dispatcher.dispatch(makeGenericTask([&]() { ++TasksRun; }));47 48 Dispatcher.shutdown();49 50 EXPECT_EQ(TasksRun, NumTasksToRun);51}52 53TEST(ThreadPoolTaskDispatcherTest, ConcurrentTasks) {54 // Check that tasks are run concurrently when multiple workers are available.55 // Adds two tasks that communicate a value back and forth using futures.56 // Neither task should be able to complete without the other having started.57 ThreadPoolTaskDispatcher Dispatcher(2);58 59 std::promise<int> PInit;60 std::future<int> FInit = PInit.get_future();61 std::promise<int> P1;62 std::future<int> F1 = P1.get_future();63 std::promise<int> P2;64 std::future<int> F2 = P2.get_future();65 std::promise<int> PResult;66 std::future<int> FResult = PResult.get_future();67 68 // Task A gets the initial value, sends it via P1, waits for response on F2.69 Dispatcher.dispatch(makeGenericTask([&]() {70 P1.set_value(FInit.get());71 PResult.set_value(F2.get());72 }));73 74 // Task B gets value from F1, sends it back on P2.75 Dispatcher.dispatch(makeGenericTask([&]() { P2.set_value(F1.get()); }));76 77 int ExpectedValue = 42;78 PInit.set_value(ExpectedValue);79 80 Dispatcher.shutdown();81 82 EXPECT_EQ(FResult.get(), ExpectedValue);83}84 85TEST(ThreadPoolTaskDispatcherTest, TasksRejectedAfterShutdown) {86 class TaskToReject : public Task {87 public:88 TaskToReject(bool &BodyRun, bool &DestructorRun)89 : BodyRun(BodyRun), DestructorRun(DestructorRun) {}90 ~TaskToReject() { DestructorRun = true; }91 void run() override { BodyRun = true; }92 93 private:94 bool &BodyRun;95 bool &DestructorRun;96 };97 98 ThreadPoolTaskDispatcher Dispatcher(1);99 Dispatcher.shutdown();100 101 bool BodyRun = false;102 bool DestructorRun = false;103 104 Dispatcher.dispatch(std::make_unique<TaskToReject>(BodyRun, DestructorRun));105 106 EXPECT_FALSE(BodyRun);107 EXPECT_TRUE(DestructorRun);108}109 110} // end anonymous namespace111