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