1 | /* |
2 | * Copyright (c) 2019, 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 "runtime/orderAccess.hpp" |
28 | #include "utilities/globalDefinitions.hpp" |
29 | #include "utilities/lockFreeStack.hpp" |
30 | #include "threadHelper.inline.hpp" |
31 | #include "unittest.hpp" |
32 | #include <new> |
33 | |
34 | class LockFreeStackTestElement { |
35 | typedef LockFreeStackTestElement 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 | LockFreeStackTestElement(size_t id = 0) : _entry(), _entry1(), _id(id) {} |
46 | size_t id() const { return _id; } |
47 | void set_id(size_t value) { _id = value; } |
48 | |
49 | typedef LockFreeStack<Element, &entry_ptr> TestStack; |
50 | typedef LockFreeStack<Element, &entry1_ptr> TestStack1; |
51 | }; |
52 | |
53 | typedef LockFreeStackTestElement Element; |
54 | typedef Element::TestStack TestStack; |
55 | typedef Element::TestStack1 TestStack1; |
56 | |
57 | static void initialize_ids(Element* elements, size_t size) { |
58 | for (size_t i = 0; i < size; ++i) { |
59 | elements[i].set_id(i); |
60 | } |
61 | } |
62 | |
63 | class LockFreeStackTestBasics : public ::testing::Test { |
64 | public: |
65 | LockFreeStackTestBasics(); |
66 | |
67 | static const size_t nelements = 10; |
68 | Element elements[nelements]; |
69 | TestStack stack; |
70 | |
71 | private: |
72 | void initialize(); |
73 | }; |
74 | |
75 | const size_t LockFreeStackTestBasics::nelements; |
76 | |
77 | LockFreeStackTestBasics::LockFreeStackTestBasics() : stack() { |
78 | initialize_ids(elements, nelements); |
79 | initialize(); |
80 | } |
81 | |
82 | void LockFreeStackTestBasics::initialize() { |
83 | ASSERT_TRUE(stack.empty()); |
84 | ASSERT_EQ(0u, stack.length()); |
85 | ASSERT_TRUE(stack.pop() == NULL); |
86 | ASSERT_TRUE(stack.top() == NULL); |
87 | |
88 | for (size_t id = 0; id < nelements; ++id) { |
89 | ASSERT_EQ(id, stack.length()); |
90 | Element* e = &elements[id]; |
91 | ASSERT_EQ(id, e->id()); |
92 | stack.push(*e); |
93 | ASSERT_FALSE(stack.empty()); |
94 | ASSERT_EQ(e, stack.top()); |
95 | } |
96 | } |
97 | |
98 | TEST_F(LockFreeStackTestBasics, push_pop) { |
99 | for (size_t i = nelements; i > 0; ) { |
100 | ASSERT_FALSE(stack.empty()); |
101 | ASSERT_EQ(i, stack.length()); |
102 | --i; |
103 | Element* e = stack.pop(); |
104 | ASSERT_TRUE(e != NULL); |
105 | ASSERT_EQ(&elements[i], e); |
106 | ASSERT_EQ(i, e->id()); |
107 | } |
108 | ASSERT_TRUE(stack.empty()); |
109 | ASSERT_EQ(0u, stack.length()); |
110 | ASSERT_TRUE(stack.pop() == NULL); |
111 | } |
112 | |
113 | TEST_F(LockFreeStackTestBasics, prepend_one) { |
114 | TestStack other_stack; |
115 | ASSERT_TRUE(other_stack.empty()); |
116 | ASSERT_TRUE(other_stack.pop() == NULL); |
117 | ASSERT_EQ(0u, other_stack.length()); |
118 | ASSERT_TRUE(other_stack.top() == NULL); |
119 | ASSERT_TRUE(other_stack.pop() == NULL); |
120 | |
121 | other_stack.prepend(*stack.pop_all()); |
122 | ASSERT_EQ(nelements, other_stack.length()); |
123 | ASSERT_TRUE(stack.empty()); |
124 | ASSERT_EQ(0u, stack.length()); |
125 | ASSERT_TRUE(stack.pop() == NULL); |
126 | ASSERT_TRUE(stack.top() == NULL); |
127 | |
128 | for (size_t i = nelements; i > 0; ) { |
129 | ASSERT_EQ(i, other_stack.length()); |
130 | --i; |
131 | Element* e = other_stack.pop(); |
132 | ASSERT_TRUE(e != NULL); |
133 | ASSERT_EQ(&elements[i], e); |
134 | ASSERT_EQ(i, e->id()); |
135 | } |
136 | ASSERT_EQ(0u, other_stack.length()); |
137 | ASSERT_TRUE(other_stack.pop() == NULL); |
138 | } |
139 | |
140 | TEST_F(LockFreeStackTestBasics, prepend_two) { |
141 | TestStack other_stack; |
142 | ASSERT_TRUE(other_stack.empty()); |
143 | ASSERT_EQ(0u, other_stack.length()); |
144 | ASSERT_TRUE(other_stack.top() == NULL); |
145 | ASSERT_TRUE(other_stack.pop() == NULL); |
146 | |
147 | Element* top = stack.pop_all(); |
148 | ASSERT_EQ(top, &elements[nelements - 1]); |
149 | other_stack.prepend(*top, elements[0]); |
150 | |
151 | for (size_t i = nelements; i > 0; ) { |
152 | ASSERT_EQ(i, other_stack.length()); |
153 | --i; |
154 | Element* e = other_stack.pop(); |
155 | ASSERT_TRUE(e != NULL); |
156 | ASSERT_EQ(&elements[i], e); |
157 | ASSERT_EQ(i, e->id()); |
158 | } |
159 | ASSERT_EQ(0u, other_stack.length()); |
160 | ASSERT_TRUE(other_stack.pop() == NULL); |
161 | } |
162 | |
163 | TEST_F(LockFreeStackTestBasics, two_stacks) { |
164 | TestStack1 stack1; |
165 | ASSERT_TRUE(stack1.pop() == NULL); |
166 | |
167 | for (size_t id = 0; id < nelements; ++id) { |
168 | stack1.push(elements[id]); |
169 | } |
170 | ASSERT_EQ(nelements, stack1.length()); |
171 | Element* e0 = stack.top(); |
172 | Element* e1 = stack1.top(); |
173 | while (true) { |
174 | ASSERT_EQ(e0, e1); |
175 | if (e0 == NULL) break; |
176 | e0 = stack.next(*e0); |
177 | e1 = stack1.next(*e1); |
178 | } |
179 | |
180 | for (size_t i = nelements; i > 0; ) { |
181 | ASSERT_EQ(i, stack.length()); |
182 | ASSERT_EQ(i, stack1.length()); |
183 | --i; |
184 | Element* e = stack.pop(); |
185 | ASSERT_TRUE(e != NULL); |
186 | ASSERT_EQ(&elements[i], e); |
187 | ASSERT_EQ(i, e->id()); |
188 | |
189 | Element* e1 = stack1.pop(); |
190 | ASSERT_TRUE(e1 != NULL); |
191 | ASSERT_EQ(&elements[i], e1); |
192 | ASSERT_EQ(i, e1->id()); |
193 | |
194 | ASSERT_EQ(e, e1); |
195 | } |
196 | ASSERT_EQ(0u, stack.length()); |
197 | ASSERT_EQ(0u, stack1.length()); |
198 | ASSERT_TRUE(stack.pop() == NULL); |
199 | ASSERT_TRUE(stack1.pop() == NULL); |
200 | } |
201 | |
202 | class LockFreeStackTestThread : public JavaTestThread { |
203 | uint _id; |
204 | TestStack* _from; |
205 | TestStack* _to; |
206 | volatile size_t* _processed; |
207 | size_t _process_limit; |
208 | size_t _local_processed; |
209 | volatile bool _ready; |
210 | |
211 | public: |
212 | LockFreeStackTestThread(Semaphore* post, |
213 | uint id, |
214 | TestStack* from, |
215 | TestStack* to, |
216 | volatile size_t* processed, |
217 | size_t process_limit) : |
218 | JavaTestThread(post), |
219 | _id(id), |
220 | _from(from), |
221 | _to(to), |
222 | _processed(processed), |
223 | _process_limit(process_limit), |
224 | _local_processed(0), |
225 | _ready(false) |
226 | {} |
227 | |
228 | virtual void main_run() { |
229 | OrderAccess::release_store_fence(&_ready, true); |
230 | while (true) { |
231 | Element* e = _from->pop(); |
232 | if (e != NULL) { |
233 | _to->push(*e); |
234 | Atomic::inc(_processed); |
235 | ++_local_processed; |
236 | } else if (OrderAccess::load_acquire(_processed) == _process_limit) { |
237 | tty->print_cr("thread %u processed " SIZE_FORMAT, _id, _local_processed); |
238 | return; |
239 | } |
240 | } |
241 | } |
242 | |
243 | bool ready() const { return OrderAccess::load_acquire(&_ready); } |
244 | }; |
245 | |
246 | TEST_VM(LockFreeStackTest, stress) { |
247 | Semaphore post; |
248 | TestStack initial_stack; |
249 | TestStack start_stack; |
250 | TestStack middle_stack; |
251 | TestStack final_stack; |
252 | volatile size_t stage1_processed = 0; |
253 | volatile size_t stage2_processed = 0; |
254 | |
255 | const size_t nelements = 10000; |
256 | Element* elements = NEW_C_HEAP_ARRAY(Element, nelements, mtOther); |
257 | for (size_t id = 0; id < nelements; ++id) { |
258 | ::new (&elements[id]) Element(id); |
259 | initial_stack.push(elements[id]); |
260 | } |
261 | ASSERT_EQ(nelements, initial_stack.length()); |
262 | |
263 | // - stage1 threads pop from start_stack and push to middle_stack. |
264 | // - stage2 threads pop from middle_stack and push to final_stack. |
265 | // - all threads in a stage count the number of elements processed in |
266 | // their corresponding stageN_processed counter. |
267 | |
268 | const uint stage1_threads = 2; |
269 | const uint stage2_threads = 2; |
270 | const uint nthreads = stage1_threads + stage2_threads; |
271 | LockFreeStackTestThread* threads[nthreads] = {}; |
272 | |
273 | for (uint i = 0; i < ARRAY_SIZE(threads); ++i) { |
274 | TestStack* from = &start_stack; |
275 | TestStack* to = &middle_stack; |
276 | volatile size_t* processed = &stage1_processed; |
277 | if (i >= stage1_threads) { |
278 | from = &middle_stack; |
279 | to = &final_stack; |
280 | processed = &stage2_processed; |
281 | } |
282 | threads[i] = |
283 | new LockFreeStackTestThread(&post, i, from, to, processed, nelements); |
284 | threads[i]->doit(); |
285 | while (!threads[i]->ready()) {} // Wait until ready to start test. |
286 | } |
287 | |
288 | // Transfer elements to start_stack to start test. |
289 | start_stack.prepend(*initial_stack.pop_all()); |
290 | |
291 | // Wait for all threads to complete. |
292 | for (uint i = 0; i < nthreads; ++i) { |
293 | post.wait(); |
294 | } |
295 | |
296 | // Verify expected state. |
297 | ASSERT_EQ(nelements, stage1_processed); |
298 | ASSERT_EQ(nelements, stage2_processed); |
299 | ASSERT_EQ(0u, initial_stack.length()); |
300 | ASSERT_EQ(0u, start_stack.length()); |
301 | ASSERT_EQ(0u, middle_stack.length()); |
302 | ASSERT_EQ(nelements, final_stack.length()); |
303 | while (final_stack.pop() != NULL) {} |
304 | |
305 | FREE_C_HEAP_ARRAY(Element, elements); |
306 | } |
307 | |