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
@@ -26,29 +86,22 @@ TEST(ThreadSafeCachingTests, ReturnGetExpression) {
26
86
auto One = SyntaxFactory::makeIntegerLiteralToken (" 1" , {}, {});
27
87
auto MinusOne = SyntaxFactory::makeIntegerLiteralExpr (Minus, One);
28
88
89
+ Pool P;
90
+
29
91
for (unsigned i = 0 ; i < 10000 ; ++i) {
30
- llvm::SmallString<48 > Scratch;
31
- llvm::raw_svector_ostream OS (Scratch);
32
92
auto Return = SyntaxFactory::makeReturnStmt (ReturnKW, MinusOne);
33
93
34
- uintptr_t FirstDataPointer ;
35
- uintptr_t SecondDataPointer ;
94
+ auto Future1 = P. run (getExpressionFrom, Return) ;
95
+ auto Future2 = P. run (getExpressionFrom, Return) ;
36
96
37
- std::thread first (getExpressionFrom, Return, &FirstDataPointer);
38
- std::thread second (getExpressionFrom, Return, &SecondDataPointer);
39
- first.join ();
40
- second.join ();
97
+ auto FirstDataPointer = Future1.get ();
98
+ auto SecondDataPointer = Future2.get ();
41
99
42
100
auto DataPointer = reinterpret_cast <uintptr_t >(
43
101
Return.getExpression ().getValue ().getDataPointer ());
44
102
45
103
ASSERT_EQ (FirstDataPointer, SecondDataPointer);
46
104
ASSERT_EQ (FirstDataPointer, DataPointer);
47
-
48
- if (FirstDataPointer != SecondDataPointer ||
49
- FirstDataPointer != DataPointer) {
50
- break ;
51
- }
52
105
}
53
106
}
54
107
0 commit comments