Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/test/hotspot/gtest/utilities/test_lockFreeQueue.cpp
41145 views
1
/*
2
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
3
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4
*
5
* This code is free software; you can redistribute it and/or modify it
6
* under the terms of the GNU General Public License version 2 only, as
7
* published by the Free Software Foundation.
8
*
9
* This code is distributed in the hope that it will be useful, but WITHOUT
10
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12
* version 2 for more details (a copy is included in the LICENSE file that
13
* accompanied this code).
14
*
15
* You should have received a copy of the GNU General Public License version
16
* 2 along with this work; if not, write to the Free Software Foundation,
17
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18
*
19
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20
* or visit www.oracle.com if you need additional information or have any
21
* questions.
22
*/
23
24
#include "precompiled.hpp"
25
#include "memory/allocation.inline.hpp"
26
#include "runtime/atomic.hpp"
27
#include "utilities/globalDefinitions.hpp"
28
#include "utilities/lockFreeQueue.inline.hpp"
29
#include "utilities/pair.hpp"
30
#include "threadHelper.inline.hpp"
31
#include "unittest.hpp"
32
#include <new>
33
34
class LockFreeQueueTestElement {
35
typedef LockFreeQueueTestElement Element;
36
37
Element* volatile _entry;
38
Element* volatile _entry1;
39
size_t _id;
40
41
static Element* volatile* entry_ptr(Element& e) { return &e._entry; }
42
static Element* volatile* entry1_ptr(Element& e) { return &e._entry1; }
43
44
public:
45
class TestQueue: public LockFreeQueue<Element, &entry_ptr> {
46
public:
47
Element* pop() {
48
using Status = LockFreeQueuePopStatus;
49
while (true) {
50
Pair<Status, Element*> pop_result = try_pop();
51
if (pop_result.first == Status::success) {
52
return pop_result.second;
53
}
54
// Retry until success.
55
}
56
}
57
};
58
class TestQueue1: public LockFreeQueue<Element, &entry1_ptr> {
59
public:
60
Element* pop() {
61
using Status = LockFreeQueuePopStatus;
62
while (true) {
63
Pair<Status, Element*> pop_result = try_pop();
64
if (pop_result.first == Status::success) {
65
return pop_result.second;
66
}
67
// Retry until success.
68
}
69
}
70
};
71
72
LockFreeQueueTestElement(size_t id = 0) : _entry(), _entry1(), _id(id) {}
73
size_t id() const { return _id; }
74
void set_id(size_t value) { _id = value; }
75
Element* next() { return _entry; }
76
Element* next1() { return _entry1; }
77
};
78
79
typedef LockFreeQueueTestElement Element;
80
typedef Element::TestQueue TestQueue;
81
typedef Element::TestQueue1 TestQueue1;
82
83
static void initialize(Element* elements, size_t size, TestQueue* queue) {
84
for (size_t i = 0; i < size; ++i) {
85
elements[i].set_id(i);
86
}
87
ASSERT_TRUE(queue->empty());
88
ASSERT_EQ(0u, queue->length());
89
ASSERT_TRUE(queue->pop() == NULL);
90
ASSERT_TRUE(queue->top() == NULL);
91
92
for (size_t id = 0; id < size; ++id) {
93
ASSERT_EQ(id, queue->length());
94
Element* e = &elements[id];
95
ASSERT_EQ(id, e->id());
96
queue->push(*e);
97
ASSERT_FALSE(queue->empty());
98
// top() is always the oldest element.
99
ASSERT_EQ(&elements[0], queue->top());
100
}
101
}
102
103
class LockFreeQueueTestBasics : public ::testing::Test {
104
public:
105
LockFreeQueueTestBasics();
106
107
static const size_t nelements = 10;
108
Element elements[nelements];
109
TestQueue queue;
110
};
111
112
const size_t LockFreeQueueTestBasics::nelements;
113
114
LockFreeQueueTestBasics::LockFreeQueueTestBasics() : queue() {
115
initialize(elements, nelements, &queue);
116
}
117
118
TEST_F(LockFreeQueueTestBasics, pop) {
119
for (size_t i = 0; i < nelements; ++i) {
120
ASSERT_FALSE(queue.empty());
121
ASSERT_EQ(nelements - i, queue.length());
122
Element* e = queue.pop();
123
ASSERT_TRUE(e != NULL);
124
ASSERT_EQ(&elements[i], e);
125
ASSERT_EQ(i, e->id());
126
}
127
ASSERT_TRUE(queue.empty());
128
ASSERT_EQ(0u, queue.length());
129
ASSERT_TRUE(queue.pop() == NULL);
130
}
131
132
TEST_F(LockFreeQueueTestBasics, append) {
133
TestQueue other_queue;
134
ASSERT_TRUE(other_queue.empty());
135
ASSERT_EQ(0u, other_queue.length());
136
ASSERT_TRUE(other_queue.top() == NULL);
137
ASSERT_TRUE(other_queue.pop() == NULL);
138
139
Pair<Element*, Element*> pair = queue.take_all();
140
other_queue.append(*pair.first, *pair.second);
141
ASSERT_EQ(nelements, other_queue.length());
142
ASSERT_TRUE(queue.empty());
143
ASSERT_EQ(0u, queue.length());
144
ASSERT_TRUE(queue.pop() == NULL);
145
ASSERT_TRUE(queue.top() == NULL);
146
147
for (size_t i = 0; i < nelements; ++i) {
148
ASSERT_EQ(nelements - i, other_queue.length());
149
Element* e = other_queue.pop();
150
ASSERT_TRUE(e != NULL);
151
ASSERT_EQ(&elements[i], e);
152
ASSERT_EQ(i, e->id());
153
}
154
ASSERT_EQ(0u, other_queue.length());
155
ASSERT_TRUE(other_queue.pop() == NULL);
156
}
157
158
TEST_F(LockFreeQueueTestBasics, two_queues) {
159
TestQueue1 queue1;
160
ASSERT_TRUE(queue1.pop() == NULL);
161
162
for (size_t id = 0; id < nelements; ++id) {
163
queue1.push(elements[id]);
164
}
165
ASSERT_EQ(nelements, queue1.length());
166
Element* e0 = queue.top();
167
Element* e1 = queue1.top();
168
while (true) {
169
ASSERT_EQ(e0, e1);
170
if (e0 == NULL) break;
171
e0 = e0->next();
172
e1 = e1->next1();
173
}
174
175
for (size_t i = 0; i < nelements; ++i) {
176
ASSERT_EQ(nelements - i, queue.length());
177
ASSERT_EQ(nelements - i, queue1.length());
178
179
Element* e = queue.pop();
180
ASSERT_TRUE(e != NULL);
181
ASSERT_EQ(&elements[i], e);
182
ASSERT_EQ(i, e->id());
183
184
Element* e1 = queue1.pop();
185
ASSERT_TRUE(e1 != NULL);
186
ASSERT_EQ(&elements[i], e1);
187
ASSERT_EQ(i, e1->id());
188
189
ASSERT_EQ(e, e1);
190
}
191
ASSERT_EQ(0u, queue.length());
192
ASSERT_EQ(0u, queue1.length());
193
ASSERT_TRUE(queue.pop() == NULL);
194
ASSERT_TRUE(queue1.pop() == NULL);
195
}
196
197
class LockFreeQueueTestThread : public JavaTestThread {
198
uint _id;
199
TestQueue* _from;
200
TestQueue* _to;
201
volatile size_t* _processed;
202
size_t _process_limit;
203
size_t _local_processed;
204
volatile bool _ready;
205
206
public:
207
LockFreeQueueTestThread(Semaphore* post,
208
uint id,
209
TestQueue* from,
210
TestQueue* to,
211
volatile size_t* processed,
212
size_t process_limit) :
213
JavaTestThread(post),
214
_id(id),
215
_from(from),
216
_to(to),
217
_processed(processed),
218
_process_limit(process_limit),
219
_local_processed(0),
220
_ready(false)
221
{}
222
223
virtual void main_run() {
224
Atomic::release_store_fence(&_ready, true);
225
while (true) {
226
Element* e = _from->pop();
227
if (e != NULL) {
228
_to->push(*e);
229
Atomic::inc(_processed);
230
++_local_processed;
231
} else if (Atomic::load_acquire(_processed) == _process_limit) {
232
tty->print_cr("thread %u processed " SIZE_FORMAT, _id, _local_processed);
233
return;
234
}
235
}
236
}
237
238
bool ready() const { return Atomic::load_acquire(&_ready); }
239
};
240
241
TEST_VM(LockFreeQueueTest, stress) {
242
Semaphore post;
243
TestQueue initial_queue;
244
TestQueue start_queue;
245
TestQueue middle_queue;
246
TestQueue final_queue;
247
volatile size_t stage1_processed = 0;
248
volatile size_t stage2_processed = 0;
249
250
const size_t nelements = 10000;
251
Element* elements = NEW_C_HEAP_ARRAY(Element, nelements, mtOther);
252
for (size_t id = 0; id < nelements; ++id) {
253
::new (&elements[id]) Element(id);
254
initial_queue.push(elements[id]);
255
}
256
ASSERT_EQ(nelements, initial_queue.length());
257
258
// - stage1 threads pop from start_queue and push to middle_queue.
259
// - stage2 threads pop from middle_queue and push to final_queue.
260
// - all threads in a stage count the number of elements processed in
261
// their corresponding stageN_processed counter.
262
263
const uint stage1_threads = 2;
264
const uint stage2_threads = 2;
265
const uint nthreads = stage1_threads + stage2_threads;
266
LockFreeQueueTestThread* threads[nthreads] = {};
267
268
for (uint i = 0; i < ARRAY_SIZE(threads); ++i) {
269
TestQueue* from = &start_queue;
270
TestQueue* to = &middle_queue;
271
volatile size_t* processed = &stage1_processed;
272
if (i >= stage1_threads) {
273
from = &middle_queue;
274
to = &final_queue;
275
processed = &stage2_processed;
276
}
277
threads[i] =
278
new LockFreeQueueTestThread(&post, i, from, to, processed, nelements);
279
threads[i]->doit();
280
while (!threads[i]->ready()) {} // Wait until ready to start test.
281
}
282
283
// Transfer elements to start_queue to start test.
284
Pair<Element*, Element*> pair = initial_queue.take_all();
285
start_queue.append(*pair.first, *pair.second);
286
287
// Wait for all threads to complete.
288
for (uint i = 0; i < nthreads; ++i) {
289
post.wait();
290
}
291
292
// Verify expected state.
293
ASSERT_EQ(nelements, stage1_processed);
294
ASSERT_EQ(nelements, stage2_processed);
295
ASSERT_EQ(0u, initial_queue.length());
296
ASSERT_EQ(0u, start_queue.length());
297
ASSERT_EQ(0u, middle_queue.length());
298
ASSERT_EQ(nelements, final_queue.length());
299
while (final_queue.pop() != NULL) {}
300
301
FREE_C_HEAP_ARRAY(Element, elements);
302
}
303
304