forked from swiftlang/swift
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathThreadSafeCachingTests.cpp
106 lines (86 loc) · 2.8 KB
/
ThreadSafeCachingTests.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
#include "swift/Syntax/SyntaxFactory.h"
#include "llvm/ADT/SmallString.h"
#include "gtest/gtest.h"
#include <future>
#include <thread>
#include <queue>
using namespace swift;
using namespace swift::syntax;
static uintptr_t getExpressionFrom(ReturnStmtSyntax Return) {
auto Expression = Return.getExpression().getValue();
return reinterpret_cast<uintptr_t>(Expression.getDataPointer());
}
class Pool {
static constexpr size_t NumThreads = 2;
using FuncTy = std::function<uintptr_t(ReturnStmtSyntax)>;
std::vector<std::thread> Workers;
std::queue<std::function<void()>> Tasks;
std::mutex QueueLock;
std::condition_variable Condition;
bool Stop;
public:
Pool() : Stop(false) {
for (size_t i = 0; i < NumThreads; ++i)
Workers.emplace_back([this] {
while (true) {
std::function<void()> Task;
{
std::unique_lock<std::mutex> L(QueueLock);
Condition.wait(L, [this]{
return Stop || !Tasks.empty();
});
if (Stop && Tasks.empty()) {
return;
}
Task = std::move(Tasks.front());
Tasks.pop();
}
Task();
}
});
}
std::future<uintptr_t> run(FuncTy Func, ReturnStmtSyntax Return) {
auto Task = std::make_shared<std::packaged_task<uintptr_t()>>(
std::bind(Func, Return));
auto Future = Task->get_future();
{
std::unique_lock<std::mutex> L(QueueLock);
Tasks.emplace([Task](){ (*Task)(); });
}
Condition.notify_one();
return Future;
}
~Pool() {
{
std::lock_guard<std::mutex> L(QueueLock);
Stop = true;
}
Condition.notify_all();
for (auto &Worker : Workers) {
Worker.join();
}
}
};
// Tests that, when multiple threads ask for a child node of the same syntax
// node:
// - Only one thread inserts the realized child into the parent
// - Both threads get the exact same child (by identity)
TEST(ThreadSafeCachingTests, ReturnGetExpression) {
auto ReturnKW = SyntaxFactory::makeReturnKeyword({}, Trivia::spaces(1));
auto Minus = SyntaxFactory::makePrefixOperator("-", {}, {});
auto One = SyntaxFactory::makeIntegerLiteral("1", {}, {});
auto MinusOne = SyntaxFactory::makePrefixOperatorExpr(Minus,
SyntaxFactory::makeIntegerLiteralExpr(One));
Pool P;
for (unsigned i = 0; i < 10000; ++i) {
auto Return = SyntaxFactory::makeReturnStmt(ReturnKW, MinusOne);
auto Future1 = P.run(getExpressionFrom, Return);
auto Future2 = P.run(getExpressionFrom, Return);
auto FirstDataPointer = Future1.get();
auto SecondDataPointer = Future2.get();
auto DataPointer = reinterpret_cast<uintptr_t>(
Return.getExpression().getValue().getDataPointer());
ASSERT_EQ(FirstDataPointer, SecondDataPointer);
ASSERT_EQ(FirstDataPointer, DataPointer);
}
}