clang-tools  16.0.0git
CancellationTests.cpp
Go to the documentation of this file.
1 #include "support/Cancellation.h"
2 #include "support/Context.h"
3 #include "support/Threading.h"
4 #include "gmock/gmock.h"
5 #include "gtest/gtest.h"
6 #include <atomic>
7 #include <memory>
8 #include <thread>
9 
10 namespace clang {
11 namespace clangd {
12 namespace {
13 
14 TEST(CancellationTest, CancellationTest) {
15  auto Task = cancelableTask();
16  WithContext ContextWithCancellation(std::move(Task.first));
17  EXPECT_FALSE(isCancelled());
18  Task.second();
19  EXPECT_TRUE(isCancelled());
20 }
21 
22 TEST(CancellationTest, CancelerDiesContextLives) {
23  llvm::Optional<WithContext> ContextWithCancellation;
24  {
25  auto Task = cancelableTask();
26  ContextWithCancellation.emplace(std::move(Task.first));
27  EXPECT_FALSE(isCancelled());
28  Task.second();
29  EXPECT_TRUE(isCancelled());
30  }
31  EXPECT_TRUE(isCancelled());
32 }
33 
34 TEST(CancellationTest, TaskContextDiesHandleLives) {
35  auto Task = cancelableTask();
36  {
37  WithContext ContextWithCancellation(std::move(Task.first));
38  EXPECT_FALSE(isCancelled());
39  Task.second();
40  EXPECT_TRUE(isCancelled());
41  }
42  // Still should be able to cancel without any problems.
43  Task.second();
44 }
45 
46 struct NestedTasks {
47  enum { OuterReason = 1, InnerReason = 2 };
48  std::pair<Context, Canceler> Outer, Inner;
49  NestedTasks() {
50  Outer = cancelableTask(OuterReason);
51  {
52  WithContext WithOuter(Outer.first.clone());
53  Inner = cancelableTask(InnerReason);
54  }
55  }
56 };
57 
58 TEST(CancellationTest, Nested) {
59  // Cancelling inner task works but leaves outer task unaffected.
60  NestedTasks CancelInner;
61  CancelInner.Inner.second();
62  EXPECT_EQ(NestedTasks::InnerReason, isCancelled(CancelInner.Inner.first));
63  EXPECT_FALSE(isCancelled(CancelInner.Outer.first));
64  // Cancellation of outer task is inherited by inner task.
65  NestedTasks CancelOuter;
66  CancelOuter.Outer.second();
67  EXPECT_EQ(NestedTasks::OuterReason, isCancelled(CancelOuter.Inner.first));
68  EXPECT_EQ(NestedTasks::OuterReason, isCancelled(CancelOuter.Outer.first));
69 }
70 
71 TEST(CancellationTest, AsynCancellationTest) {
72  std::atomic<bool> HasCancelled(false);
73  Notification Cancelled;
74  auto TaskToBeCancelled = [&](Context Ctx) {
75  WithContext ContextGuard(std::move(Ctx));
76  Cancelled.wait();
77  HasCancelled = isCancelled();
78  };
79  auto Task = cancelableTask();
80  std::thread AsyncTask(TaskToBeCancelled, std::move(Task.first));
81  Task.second();
82  Cancelled.notify();
83  AsyncTask.join();
84 
85  EXPECT_TRUE(HasCancelled);
86 }
87 } // namespace
88 } // namespace clangd
89 } // namespace clang
clang::clangd::cancelableTask
std::pair< Context, Canceler > cancelableTask(int Reason)
Defines a new task whose cancellation may be requested.
Definition: Cancellation.cpp:24
clang::clangd::TEST
TEST(BackgroundQueueTest, Priority)
Definition: BackgroundIndexTests.cpp:750
Ctx
Context Ctx
Definition: TUScheduler.cpp:553
Outer
std::pair< Context, Canceler > Outer
Definition: CancellationTests.cpp:48
Cancellation.h
clang::clangd::isCancelled
int isCancelled(const Context &Ctx)
If the current context is within a cancelled task, returns the reason.
Definition: Cancellation.cpp:35
Inner
std::pair< Context, Canceler > Inner
Definition: CancellationTests.cpp:48
Threading.h
clang
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
Definition: ApplyReplacements.h:27
Context.h