Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/test/hotspot/gtest/utilities/test_concurrentHashtable.cpp
41145 views
1
/*
2
* Copyright (c) 2018, 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 "runtime/mutex.hpp"
26
#include "runtime/semaphore.hpp"
27
#include "runtime/thread.hpp"
28
#include "runtime/vmThread.hpp"
29
#include "runtime/vmOperations.hpp"
30
#include "utilities/concurrentHashTable.inline.hpp"
31
#include "utilities/concurrentHashTableTasks.inline.hpp"
32
#include "threadHelper.inline.hpp"
33
#include "unittest.hpp"
34
35
// NOTE: On win32 gtest asserts are not mt-safe.
36
// Amusingly as long as they do not assert they are mt-safe.
37
#define SIZE_32 5
38
39
struct Pointer : public AllStatic {
40
typedef uintptr_t Value;
41
static uintx get_hash(const Value& value, bool* dead_hash) {
42
return (uintx)value;
43
}
44
static void* allocate_node(void* context, size_t size, const Value& value) {
45
return ::malloc(size);
46
}
47
static void free_node(void* context, void* memory, const Value& value) {
48
::free(memory);
49
}
50
};
51
52
struct Allocator {
53
struct TableElement{
54
TableElement * volatile _next;
55
uintptr_t _value;
56
};
57
58
const uint nelements = 5;
59
TableElement* elements;
60
uint cur_index;
61
62
Allocator() : cur_index(0) {
63
elements = (TableElement*)::malloc(nelements * sizeof(TableElement));
64
}
65
66
void* allocate_node() {
67
return (void*)&elements[cur_index++];
68
}
69
70
void free_node(void* value) { /* Arena allocator. Ignore freed nodes*/ }
71
72
void reset() {
73
cur_index = 0;
74
}
75
76
~Allocator() {
77
::free(elements);
78
}
79
};
80
81
struct Config : public AllStatic {
82
typedef uintptr_t Value;
83
84
static uintx get_hash(const Value& value, bool* dead_hash) {
85
return (uintx)value;
86
}
87
static void* allocate_node(void* context, size_t size, const Value& value) {
88
Allocator* mm = (Allocator*)context;
89
return mm->allocate_node();
90
}
91
92
static void free_node(void* context, void* memory, const Value& value) {
93
Allocator* mm = (Allocator*)context;
94
mm->free_node(memory);
95
}
96
};
97
98
typedef ConcurrentHashTable<Pointer, mtInternal> SimpleTestTable;
99
typedef ConcurrentHashTable<Pointer, mtInternal>::MultiGetHandle SimpleTestGetHandle;
100
typedef ConcurrentHashTable<Config, mtInternal> CustomTestTable;
101
102
struct SimpleTestLookup {
103
uintptr_t _val;
104
SimpleTestLookup(uintptr_t val) : _val(val) {}
105
uintx get_hash() {
106
return Pointer::get_hash(_val, NULL);
107
}
108
bool equals(const uintptr_t* value, bool* is_dead) {
109
return _val == *value;
110
}
111
};
112
113
struct ValueGet {
114
uintptr_t _return;
115
ValueGet() : _return(0) {}
116
void operator()(uintptr_t* value) {
117
EXPECT_NE(value, (uintptr_t*)NULL) << "expected valid value";
118
_return = *value;
119
}
120
uintptr_t get_value() const {
121
return _return;
122
}
123
};
124
125
template <typename T=SimpleTestTable>
126
static uintptr_t cht_get_copy(T* cht, Thread* thr, SimpleTestLookup stl) {
127
ValueGet vg;
128
cht->get(thr, stl, vg);
129
return vg.get_value();
130
}
131
132
template <typename T=SimpleTestTable>
133
static void cht_find(Thread* thr, T* cht, uintptr_t val) {
134
SimpleTestLookup stl(val);
135
ValueGet vg;
136
EXPECT_EQ(cht->get(thr, stl, vg), true) << "Getting an old value failed.";
137
EXPECT_EQ(val, vg.get_value()) << "Getting an old value failed.";
138
}
139
140
template <typename T=SimpleTestTable>
141
static void cht_insert_and_find(Thread* thr, T* cht, uintptr_t val) {
142
SimpleTestLookup stl(val);
143
EXPECT_EQ(cht->insert(thr, stl, val), true) << "Inserting an unique value failed.";
144
cht_find(thr, cht, val);
145
}
146
147
static void cht_insert(Thread* thr) {
148
uintptr_t val = 0x2;
149
SimpleTestLookup stl(val);
150
SimpleTestTable* cht = new SimpleTestTable();
151
EXPECT_TRUE(cht->insert(thr, stl, val)) << "Insert unique value failed.";
152
EXPECT_EQ(cht_get_copy(cht, thr, stl), val) << "Getting an existing value failed.";
153
EXPECT_TRUE(cht->remove(thr, stl)) << "Removing an existing value failed.";
154
EXPECT_FALSE(cht->remove(thr, stl)) << "Removing an already removed item succeeded.";
155
EXPECT_NE(cht_get_copy(cht, thr, stl), val) << "Getting a removed value succeeded.";
156
delete cht;
157
}
158
159
static void cht_insert_get(Thread* thr) {
160
uintptr_t val = 0x2;
161
SimpleTestLookup stl(val);
162
SimpleTestTable* cht = new SimpleTestTable();
163
ValueGet vg;
164
EXPECT_TRUE(cht->insert_get(thr, stl, val, vg)) << "Insert unique value failed.";
165
EXPECT_EQ(val, vg.get_value()) << "Getting an inserted value failed.";
166
ValueGet vg_dup;
167
EXPECT_FALSE(cht->insert_get(thr, stl, val, vg_dup)) << "Insert duplicate value succeeded.";
168
EXPECT_EQ(val, vg_dup.get_value()) << "Getting an existing value failed.";
169
delete cht;
170
}
171
172
static void cht_get_insert(Thread* thr) {
173
uintptr_t val = 0x2;
174
SimpleTestLookup stl(val);
175
SimpleTestTable* cht = new SimpleTestTable();
176
177
{
178
SCOPED_TRACE("First");
179
cht_insert_and_find(thr, cht, val);
180
}
181
EXPECT_EQ(cht_get_copy(cht, thr, stl), val) << "Get an old value failed";
182
EXPECT_TRUE(cht->remove(thr, stl)) << "Removing existing value failed.";
183
EXPECT_NE(cht_get_copy(cht, thr, stl), val) << "Got an already removed item.";
184
185
{
186
SCOPED_TRACE("Second");
187
cht_insert_and_find(thr, cht, val);
188
}
189
190
delete cht;
191
}
192
193
static bool getinsert_bulkdelete_eval(uintptr_t* val) {
194
EXPECT_TRUE(*val > 0 && *val < 4) << "Val wrong for this test.";
195
return (*val & 0x1); // Delete all values ending with first bit set.
196
}
197
198
static void getinsert_bulkdelete_del(uintptr_t* val) {
199
EXPECT_EQ(*val & 0x1, (uintptr_t)1) << "Deleting wrong value.";
200
}
201
202
static void cht_getinsert_bulkdelete_insert_verified(Thread* thr, SimpleTestTable* cht, uintptr_t val,
203
bool verify_expect_get, bool verify_expect_inserted) {
204
SimpleTestLookup stl(val);
205
if (verify_expect_inserted) {
206
cht_insert_and_find(thr, cht, val);
207
}
208
if (verify_expect_get) {
209
cht_find(thr, cht, val);
210
}
211
}
212
213
static void cht_getinsert_bulkdelete(Thread* thr) {
214
uintptr_t val1 = 1;
215
uintptr_t val2 = 2;
216
uintptr_t val3 = 3;
217
SimpleTestLookup stl1(val1), stl2(val2), stl3(val3);
218
219
SimpleTestTable* cht = new SimpleTestTable();
220
cht_getinsert_bulkdelete_insert_verified(thr, cht, val1, false, true);
221
cht_getinsert_bulkdelete_insert_verified(thr, cht, val2, false, true);
222
cht_getinsert_bulkdelete_insert_verified(thr, cht, val3, false, true);
223
224
EXPECT_TRUE(cht->remove(thr, stl2)) << "Remove did not find value.";
225
226
cht_getinsert_bulkdelete_insert_verified(thr, cht, val1, true, false); // val1 should be present
227
cht_getinsert_bulkdelete_insert_verified(thr, cht, val2, false, true); // val2 should be inserted
228
cht_getinsert_bulkdelete_insert_verified(thr, cht, val3, true, false); // val3 should be present
229
230
EXPECT_EQ(cht_get_copy(cht, thr, stl1), val1) << "Get did not find value.";
231
EXPECT_EQ(cht_get_copy(cht, thr, stl2), val2) << "Get did not find value.";
232
EXPECT_EQ(cht_get_copy(cht, thr, stl3), val3) << "Get did not find value.";
233
234
// Removes all odd values.
235
cht->bulk_delete(thr, getinsert_bulkdelete_eval, getinsert_bulkdelete_del);
236
237
EXPECT_EQ(cht_get_copy(cht, thr, stl1), (uintptr_t)0) << "Odd value should not exist.";
238
EXPECT_FALSE(cht->remove(thr, stl1)) << "Odd value should not exist.";
239
EXPECT_EQ(cht_get_copy(cht, thr, stl2), val2) << "Even value should not have been removed.";
240
EXPECT_EQ(cht_get_copy(cht, thr, stl3), (uintptr_t)0) << "Add value should not exists.";
241
EXPECT_FALSE(cht->remove(thr, stl3)) << "Odd value should not exists.";
242
243
delete cht;
244
}
245
246
static void cht_getinsert_bulkdelete_task(Thread* thr) {
247
uintptr_t val1 = 1;
248
uintptr_t val2 = 2;
249
uintptr_t val3 = 3;
250
SimpleTestLookup stl1(val1), stl2(val2), stl3(val3);
251
252
SimpleTestTable* cht = new SimpleTestTable();
253
cht_getinsert_bulkdelete_insert_verified(thr, cht, val1, false, true);
254
cht_getinsert_bulkdelete_insert_verified(thr, cht, val2, false, true);
255
cht_getinsert_bulkdelete_insert_verified(thr, cht, val3, false, true);
256
257
EXPECT_TRUE(cht->remove(thr, stl2)) << "Remove did not find value.";
258
259
cht_getinsert_bulkdelete_insert_verified(thr, cht, val1, true, false); // val1 should be present
260
cht_getinsert_bulkdelete_insert_verified(thr, cht, val2, false, true); // val2 should be inserted
261
cht_getinsert_bulkdelete_insert_verified(thr, cht, val3, true, false); // val3 should be present
262
263
EXPECT_EQ(cht_get_copy(cht, thr, stl1), val1) << "Get did not find value.";
264
EXPECT_EQ(cht_get_copy(cht, thr, stl2), val2) << "Get did not find value.";
265
EXPECT_EQ(cht_get_copy(cht, thr, stl3), val3) << "Get did not find value.";
266
267
// Removes all odd values.
268
SimpleTestTable::BulkDeleteTask bdt(cht);
269
if (bdt.prepare(thr)) {
270
while(bdt.do_task(thr, getinsert_bulkdelete_eval, getinsert_bulkdelete_del)) {
271
bdt.pause(thr);
272
bdt.cont(thr);
273
}
274
bdt.done(thr);
275
}
276
277
EXPECT_EQ(cht_get_copy(cht, thr, stl1), (uintptr_t)0) << "Odd value should not exist.";
278
EXPECT_FALSE(cht->remove(thr, stl1)) << "Odd value should not exist.";
279
EXPECT_EQ(cht_get_copy(cht, thr, stl2), val2) << "Even value should not have been removed.";
280
EXPECT_EQ(cht_get_copy(cht, thr, stl3), (uintptr_t)0) << "Add value should not exists.";
281
EXPECT_FALSE(cht->remove(thr, stl3)) << "Odd value should not exists.";
282
283
delete cht;
284
}
285
286
static void cht_reset_shrink(Thread* thr) {
287
uintptr_t val1 = 1;
288
uintptr_t val2 = 2;
289
uintptr_t val3 = 3;
290
SimpleTestLookup stl1(val1), stl2(val2), stl3(val3);
291
292
Allocator mem_allocator;
293
const uint initial_log_table_size = 4;
294
CustomTestTable* cht = new CustomTestTable(&mem_allocator);
295
296
cht_insert_and_find(thr, cht, val1);
297
cht_insert_and_find(thr, cht, val2);
298
cht_insert_and_find(thr, cht, val3);
299
300
cht->unsafe_reset();
301
mem_allocator.reset();
302
303
EXPECT_EQ(cht_get_copy(cht, thr, stl1), (uintptr_t)0) << "Table should have been reset";
304
// Re-inserted values should not be considered duplicates; table was reset.
305
cht_insert_and_find(thr, cht, val1);
306
cht_insert_and_find(thr, cht, val2);
307
cht_insert_and_find(thr, cht, val3);
308
309
cht->unsafe_reset();
310
delete cht;
311
}
312
313
static void cht_scope(Thread* thr) {
314
uintptr_t val = 0x2;
315
SimpleTestLookup stl(val);
316
SimpleTestTable* cht = new SimpleTestTable();
317
EXPECT_TRUE(cht->insert(thr, stl, val)) << "Insert unique value failed.";
318
{
319
SimpleTestGetHandle get_handle(thr, cht);
320
EXPECT_EQ(*get_handle.get(stl), val) << "Getting a pre-existing value failed.";
321
}
322
// We do remove here to make sure the value-handle 'unlocked' the table when leaving the scope.
323
EXPECT_TRUE(cht->remove(thr, stl)) << "Removing a pre-existing value failed.";
324
EXPECT_FALSE(cht_get_copy(cht, thr, stl) == val) << "Got a removed value.";
325
delete cht;
326
}
327
328
struct ChtScan {
329
size_t _count;
330
ChtScan() : _count(0) {}
331
bool operator()(uintptr_t* val) {
332
EXPECT_EQ(*val, (uintptr_t)0x2) << "Got an unknown value.";
333
EXPECT_EQ(_count, 0u) << "Only one value should be in table.";
334
_count++;
335
return true; /* continue scan */
336
}
337
};
338
339
static void cht_scan(Thread* thr) {
340
uintptr_t val = 0x2;
341
SimpleTestLookup stl(val);
342
ChtScan scan;
343
SimpleTestTable* cht = new SimpleTestTable();
344
EXPECT_TRUE(cht->insert(thr, stl, val)) << "Insert unique value failed.";
345
EXPECT_EQ(cht->try_scan(thr, scan), true) << "Scanning an non-growing/shrinking table should work.";
346
EXPECT_TRUE(cht->remove(thr, stl)) << "Removing a pre-existing value failed.";
347
EXPECT_FALSE(cht_get_copy(cht, thr, stl) == val) << "Got a removed value.";
348
delete cht;
349
}
350
351
struct ChtCountScan {
352
size_t _count;
353
ChtCountScan() : _count(0) {}
354
bool operator()(uintptr_t* val) {
355
_count++;
356
return true; /* continue scan */
357
}
358
};
359
360
static void cht_move_to(Thread* thr) {
361
uintptr_t val1 = 0x2;
362
uintptr_t val2 = 0xe0000002;
363
uintptr_t val3 = 0x3;
364
SimpleTestLookup stl1(val1), stl2(val2), stl3(val3);
365
SimpleTestTable* from_cht = new SimpleTestTable();
366
EXPECT_TRUE(from_cht->insert(thr, stl1, val1)) << "Insert unique value failed.";
367
EXPECT_TRUE(from_cht->insert(thr, stl2, val2)) << "Insert unique value failed.";
368
EXPECT_TRUE(from_cht->insert(thr, stl3, val3)) << "Insert unique value failed.";
369
370
SimpleTestTable* to_cht = new SimpleTestTable();
371
EXPECT_TRUE(from_cht->try_move_nodes_to(thr, to_cht)) << "Moving nodes to new table failed";
372
373
ChtCountScan scan_old;
374
EXPECT_TRUE(from_cht->try_scan(thr, scan_old)) << "Scanning table should work.";
375
EXPECT_EQ(scan_old._count, (size_t)0) << "All items should be moved";
376
377
ChtCountScan scan_new;
378
EXPECT_TRUE(to_cht->try_scan(thr, scan_new)) << "Scanning table should work.";
379
EXPECT_EQ(scan_new._count, (size_t)3) << "All items should be moved";
380
EXPECT_TRUE(cht_get_copy(to_cht, thr, stl1) == val1) << "Getting an inserted value should work.";
381
EXPECT_TRUE(cht_get_copy(to_cht, thr, stl2) == val2) << "Getting an inserted value should work.";
382
EXPECT_TRUE(cht_get_copy(to_cht, thr, stl3) == val3) << "Getting an inserted value should work.";
383
}
384
385
static void cht_grow(Thread* thr) {
386
uintptr_t val = 0x2;
387
uintptr_t val2 = 0x22;
388
uintptr_t val3 = 0x222;
389
SimpleTestLookup stl(val), stl2(val2), stl3(val3);
390
SimpleTestTable* cht = new SimpleTestTable();
391
392
EXPECT_TRUE(cht->insert(thr, stl, val)) << "Insert unique value failed.";
393
EXPECT_TRUE(cht->insert(thr, stl2, val2)) << "Insert unique value failed.";
394
EXPECT_TRUE(cht->insert(thr, stl3, val3)) << "Insert unique value failed.";
395
EXPECT_FALSE(cht->insert(thr, stl3, val3)) << "Insert duplicate value should have failed.";
396
EXPECT_TRUE(cht_get_copy(cht, thr, stl) == val) << "Getting an inserted value should work.";
397
EXPECT_TRUE(cht_get_copy(cht, thr, stl2) == val2) << "Getting an inserted value should work.";
398
EXPECT_TRUE(cht_get_copy(cht, thr, stl3) == val3) << "Getting an inserted value should work.";
399
400
EXPECT_TRUE(cht->remove(thr, stl2)) << "Removing an inserted value should work.";
401
402
EXPECT_TRUE(cht_get_copy(cht, thr, stl) == val) << "Getting an inserted value should work.";
403
EXPECT_FALSE(cht_get_copy(cht, thr, stl2) == val2) << "Getting a removed value should have failed.";
404
EXPECT_TRUE(cht_get_copy(cht, thr, stl3) == val3) << "Getting an inserted value should work.";
405
406
407
EXPECT_TRUE(cht->grow(thr)) << "Growing uncontended should not fail.";
408
409
EXPECT_TRUE(cht_get_copy(cht, thr, stl) == val) << "Getting an item after grow failed.";
410
EXPECT_FALSE(cht_get_copy(cht, thr, stl2) == val2) << "Getting a removed value after grow should have failed.";
411
EXPECT_TRUE(cht_get_copy(cht, thr, stl3) == val3) << "Getting an item after grow failed.";
412
413
EXPECT_TRUE(cht->insert(thr, stl2, val2)) << "Insert unique value failed.";
414
EXPECT_TRUE(cht->remove(thr, stl3)) << "Removing an inserted value should work.";
415
416
EXPECT_TRUE(cht->shrink(thr)) << "Shrinking uncontended should not fail.";
417
418
EXPECT_TRUE(cht_get_copy(cht, thr, stl) == val) << "Getting an item after shrink failed.";
419
EXPECT_TRUE(cht_get_copy(cht, thr, stl2) == val2) << "Getting an item after shrink failed.";
420
EXPECT_FALSE(cht_get_copy(cht, thr, stl3) == val3) << "Getting a removed value after shrink should have failed.";
421
422
delete cht;
423
}
424
425
static void cht_task_grow(Thread* thr) {
426
uintptr_t val = 0x2;
427
uintptr_t val2 = 0x22;
428
uintptr_t val3 = 0x222;
429
SimpleTestLookup stl(val), stl2(val2), stl3(val3);
430
SimpleTestTable* cht = new SimpleTestTable();
431
432
EXPECT_TRUE(cht->insert(thr, stl, val)) << "Insert unique value failed.";
433
EXPECT_TRUE(cht->insert(thr, stl2, val2)) << "Insert unique value failed.";
434
EXPECT_TRUE(cht->insert(thr, stl3, val3)) << "Insert unique value failed.";
435
EXPECT_FALSE(cht->insert(thr, stl3, val3)) << "Insert duplicate value should have failed.";
436
EXPECT_TRUE(cht_get_copy(cht, thr, stl) == val) << "Getting an inserted value should work.";
437
EXPECT_TRUE(cht_get_copy(cht, thr, stl2) == val2) << "Getting an inserted value should work.";
438
EXPECT_TRUE(cht_get_copy(cht, thr, stl3) == val3) << "Getting an inserted value should work.";
439
440
EXPECT_TRUE(cht->remove(thr, stl2)) << "Removing an inserted value should work.";
441
442
EXPECT_TRUE(cht_get_copy(cht, thr, stl) == val) << "Getting an inserted value should work.";
443
EXPECT_FALSE(cht_get_copy(cht, thr, stl2) == val2) << "Getting a removed value should have failed.";
444
EXPECT_TRUE(cht_get_copy(cht, thr, stl3) == val3) << "Getting an inserted value should work.";
445
446
SimpleTestTable::GrowTask gt(cht);
447
EXPECT_TRUE(gt.prepare(thr)) << "Growing uncontended should not fail.";
448
while(gt.do_task(thr)) { /* grow */ }
449
gt.done(thr);
450
451
EXPECT_TRUE(cht_get_copy(cht, thr, stl) == val) << "Getting an item after grow failed.";
452
EXPECT_FALSE(cht_get_copy(cht, thr, stl2) == val2) << "Getting a removed value after grow should have failed.";
453
EXPECT_TRUE(cht_get_copy(cht, thr, stl3) == val3) << "Getting an item after grow failed.";
454
455
EXPECT_TRUE(cht->insert(thr, stl2, val2)) << "Insert unique value failed.";
456
EXPECT_TRUE(cht->remove(thr, stl3)) << "Removing an inserted value should work.";
457
458
EXPECT_TRUE(cht->shrink(thr)) << "Shrinking uncontended should not fail.";
459
460
EXPECT_TRUE(cht_get_copy(cht, thr, stl) == val) << "Getting an item after shrink failed.";
461
EXPECT_TRUE(cht_get_copy(cht, thr, stl2) == val2) << "Getting an item after shrink failed.";
462
EXPECT_FALSE(cht_get_copy(cht, thr, stl3) == val3) << "Getting a removed value after shrink should have failed.";
463
464
delete cht;
465
}
466
467
TEST_VM(ConcurrentHashTable, basic_insert) {
468
nomt_test_doer(cht_insert);
469
}
470
471
TEST_VM(ConcurrentHashTable, basic_get_insert) {
472
nomt_test_doer(cht_get_insert);
473
}
474
475
TEST_VM(ConcurrentHashTable, basic_insert_get) {
476
nomt_test_doer(cht_insert_get);
477
}
478
479
TEST_VM(ConcurrentHashTable, basic_scope) {
480
nomt_test_doer(cht_scope);
481
}
482
483
TEST_VM(ConcurrentHashTable, basic_get_insert_bulk_delete) {
484
nomt_test_doer(cht_getinsert_bulkdelete);
485
}
486
487
TEST_VM(ConcurrentHashTable, basic_get_insert_bulk_delete_task) {
488
nomt_test_doer(cht_getinsert_bulkdelete_task);
489
}
490
491
TEST_VM(ConcurrentHashTable, basic_reset_shrink) {
492
nomt_test_doer(cht_reset_shrink);
493
}
494
495
TEST_VM(ConcurrentHashTable, basic_scan) {
496
nomt_test_doer(cht_scan);
497
}
498
499
TEST_VM(ConcurrentHashTable, basic_move_to) {
500
nomt_test_doer(cht_move_to);
501
}
502
503
TEST_VM(ConcurrentHashTable, basic_grow) {
504
nomt_test_doer(cht_grow);
505
}
506
507
TEST_VM(ConcurrentHashTable, task_grow) {
508
nomt_test_doer(cht_task_grow);
509
}
510
511
//#############################################################################################
512
513
class TestInterface : public AllStatic {
514
public:
515
typedef uintptr_t Value;
516
static uintx get_hash(const Value& value, bool* dead_hash) {
517
return (uintx)(value + 18446744073709551557ul) * 18446744073709551557ul;
518
}
519
static void* allocate_node(void* context, size_t size, const Value& value) {
520
return AllocateHeap(size, mtInternal);
521
}
522
static void free_node(void* context, void* memory, const Value& value) {
523
FreeHeap(memory);
524
}
525
};
526
527
typedef ConcurrentHashTable<TestInterface, mtInternal> TestTable;
528
typedef ConcurrentHashTable<TestInterface, mtInternal>::MultiGetHandle TestGetHandle;
529
530
struct TestLookup {
531
uintptr_t _val;
532
TestLookup(uintptr_t val) : _val(val) {}
533
uintx get_hash() {
534
return TestInterface::get_hash(_val, NULL);
535
}
536
bool equals(const uintptr_t* value, bool* is_dead) {
537
return _val == *value;
538
}
539
};
540
541
static uintptr_t cht_get_copy(TestTable* cht, Thread* thr, TestLookup tl) {
542
ValueGet vg;
543
cht->get(thr, tl, vg);
544
return vg.get_value();
545
}
546
547
class CHTTestThread : public JavaTestThread {
548
public:
549
uintptr_t _start;
550
uintptr_t _stop;
551
TestTable *_cht;
552
jlong _stop_ms;
553
CHTTestThread(uintptr_t start, uintptr_t stop, TestTable* cht, Semaphore* post)
554
: JavaTestThread(post), _start(start), _stop(stop), _cht(cht) {}
555
virtual void premain() {}
556
void main_run() {
557
premain();
558
_stop_ms = os::javaTimeMillis() + 2000; // 2 seconds max test time
559
while (keep_looping() && test_loop()) { /* */ }
560
postmain();
561
}
562
virtual void postmain() {}
563
virtual bool keep_looping() {
564
return _stop_ms > os::javaTimeMillis();
565
};
566
virtual bool test_loop() = 0;
567
virtual ~CHTTestThread() {}
568
};
569
570
class ValueSaver {
571
uintptr_t* _vals;
572
size_t _it;
573
size_t _size;
574
public:
575
ValueSaver() : _it(0), _size(1024) {
576
_vals = NEW_C_HEAP_ARRAY(uintptr_t, _size, mtInternal);
577
}
578
579
bool operator()(uintptr_t* val) {
580
_vals[_it++] = *val;
581
if (_it == _size) {
582
_size *= 2;
583
_vals = REALLOC_RESOURCE_ARRAY(uintptr_t, _vals, _size/2, _size);
584
}
585
return true;
586
}
587
588
void check() {
589
for (size_t i = 0; i < _it; i++) {
590
size_t count = 0;
591
for (size_t j = (i + 1u); j < _it; j++) {
592
if (_vals[i] == _vals[j]) {
593
count++;
594
}
595
}
596
EXPECT_EQ(count, 0u);
597
}
598
}
599
};
600
601
static void integrity_check(Thread* thr, TestTable* cht)
602
{
603
ValueSaver vs;
604
cht->do_scan(thr, vs);
605
vs.check();
606
}
607
608
//#############################################################################################
609
// All threads are working on different items
610
// This item should only be delete by this thread
611
// Thus get_unsafe is safe for this test.
612
613
class SimpleInserterThread : public CHTTestThread {
614
public:
615
static volatile bool _exit;
616
617
SimpleInserterThread(uintptr_t start, uintptr_t stop, TestTable* cht, Semaphore* post)
618
: CHTTestThread(start, stop, cht, post) {};
619
virtual ~SimpleInserterThread(){}
620
621
bool keep_looping() {
622
return !_exit;
623
}
624
625
bool test_loop() {
626
bool grow;
627
for (uintptr_t v = _start; v <= _stop; v++) {
628
TestLookup tl(v);
629
EXPECT_TRUE(_cht->insert(this, tl, v, &grow)) << "Inserting an unique value should work.";
630
}
631
for (uintptr_t v = _start; v <= _stop; v++) {
632
TestLookup tl(v);
633
EXPECT_TRUE(cht_get_copy(_cht, this, tl) == v) << "Getting an previously inserted value unsafe failed.";
634
}
635
for (uintptr_t v = _start; v <= _stop; v++) {
636
TestLookup tl(v);
637
EXPECT_TRUE(_cht->remove(this, tl)) << "Removing an existing value failed.";
638
}
639
for (uintptr_t v = _start; v <= _stop; v++) {
640
TestLookup tl(v);
641
EXPECT_TRUE(cht_get_copy(_cht, this, tl) == 0) << "Got a removed value.";
642
}
643
return true;
644
}
645
};
646
647
volatile bool SimpleInserterThread::_exit = false;
648
649
class RunnerSimpleInserterThread : public CHTTestThread {
650
public:
651
Semaphore _done;
652
653
RunnerSimpleInserterThread(Semaphore* post) : CHTTestThread(0, 0, NULL, post) {
654
_cht = new TestTable(SIZE_32, SIZE_32);
655
};
656
virtual ~RunnerSimpleInserterThread(){}
657
658
void premain() {
659
660
SimpleInserterThread* ins1 = new SimpleInserterThread((uintptr_t)0x100, (uintptr_t) 0x1FF, _cht, &_done);
661
SimpleInserterThread* ins2 = new SimpleInserterThread((uintptr_t)0x200, (uintptr_t) 0x2FF, _cht, &_done);
662
SimpleInserterThread* ins3 = new SimpleInserterThread((uintptr_t)0x300, (uintptr_t) 0x3FF, _cht, &_done);
663
SimpleInserterThread* ins4 = new SimpleInserterThread((uintptr_t)0x400, (uintptr_t) 0x4FF, _cht, &_done);
664
665
for (uintptr_t v = 0x500; v < 0x5FF; v++ ) {
666
TestLookup tl(v);
667
EXPECT_TRUE(_cht->insert(this, tl, v)) << "Inserting an unique value should work.";
668
}
669
670
ins1->doit();
671
ins2->doit();
672
ins3->doit();
673
ins4->doit();
674
675
}
676
677
bool test_loop() {
678
for (uintptr_t v = 0x500; v < 0x5FF; v++ ) {
679
TestLookup tl(v);
680
EXPECT_TRUE(cht_get_copy(_cht, this, tl) == v) << "Getting an previously inserted value unsafe failed.";;
681
}
682
return true;
683
}
684
685
void postmain() {
686
SimpleInserterThread::_exit = true;
687
for (int i = 0; i < 4; i++) {
688
_done.wait();
689
}
690
for (uintptr_t v = 0x500; v < 0x5FF; v++ ) {
691
TestLookup tl(v);
692
EXPECT_TRUE(_cht->remove(this, tl)) << "Removing an existing value failed.";
693
}
694
integrity_check(this, _cht);
695
delete _cht;
696
}
697
};
698
699
700
TEST_VM(ConcurrentHashTable, concurrent_simple) {
701
SimpleInserterThread::_exit = false;
702
mt_test_doer<RunnerSimpleInserterThread>();
703
}
704
705
//#############################################################################################
706
// In this test we try to get a 'bad' value
707
class DeleteInserterThread : public CHTTestThread {
708
public:
709
static volatile bool _exit;
710
711
DeleteInserterThread(uintptr_t start, uintptr_t stop, TestTable* cht, Semaphore* post) : CHTTestThread(start, stop, cht, post) {};
712
virtual ~DeleteInserterThread(){}
713
714
bool keep_looping() {
715
return !_exit;
716
}
717
718
bool test_loop() {
719
for (uintptr_t v = _start; v <= _stop; v++) {
720
TestLookup tl(v);
721
_cht->insert(this, tl, v);
722
}
723
for (uintptr_t v = _start; v <= _stop; v++) {
724
TestLookup tl(v);
725
_cht->remove(this, tl);
726
}
727
return true;
728
}
729
};
730
731
volatile bool DeleteInserterThread::_exit = true;
732
733
class RunnerDeleteInserterThread : public CHTTestThread {
734
public:
735
Semaphore _done;
736
737
RunnerDeleteInserterThread(Semaphore* post) : CHTTestThread(0, 0, NULL, post) {
738
_cht = new TestTable(SIZE_32, SIZE_32);
739
};
740
virtual ~RunnerDeleteInserterThread(){}
741
742
void premain() {
743
DeleteInserterThread* ins1 = new DeleteInserterThread((uintptr_t)0x1, (uintptr_t) 0xFFF, _cht, &_done);
744
DeleteInserterThread* ins2 = new DeleteInserterThread((uintptr_t)0x1, (uintptr_t) 0xFFF, _cht, &_done);
745
DeleteInserterThread* ins3 = new DeleteInserterThread((uintptr_t)0x1, (uintptr_t) 0xFFF, _cht, &_done);
746
DeleteInserterThread* ins4 = new DeleteInserterThread((uintptr_t)0x1, (uintptr_t) 0xFFF, _cht, &_done);
747
748
ins1->doit();
749
ins2->doit();
750
ins3->doit();
751
ins4->doit();
752
}
753
754
bool test_loop() {
755
for (uintptr_t v = 0x1; v < 0xFFF; v++ ) {
756
uintptr_t tv;
757
if (v & 0x1) {
758
TestLookup tl(v);
759
tv = cht_get_copy(_cht, this, tl);
760
} else {
761
TestLookup tl(v);
762
TestGetHandle value_handle(this, _cht);
763
uintptr_t* tmp = value_handle.get(tl);
764
tv = tmp != NULL ? *tmp : 0;
765
}
766
EXPECT_TRUE(tv == 0 || tv == v) << "Got unknown value.";
767
}
768
return true;
769
}
770
771
void postmain() {
772
DeleteInserterThread::_exit = true;
773
for (int i = 0; i < 4; i++) {
774
_done.wait();
775
}
776
integrity_check(this, _cht);
777
delete _cht;
778
}
779
};
780
781
TEST_VM(ConcurrentHashTable, concurrent_deletes) {
782
DeleteInserterThread::_exit = false;
783
mt_test_doer<RunnerDeleteInserterThread>();
784
}
785
786
//#############################################################################################
787
788
#define START_SIZE 13
789
#define END_SIZE 17
790
#define START (uintptr_t)0x10000
791
#define RANGE (uintptr_t)0xFFFF
792
793
#define GSTEST_THREAD_COUNT 5
794
795
796
class GSInserterThread: public CHTTestThread {
797
public:
798
static volatile bool _shrink;
799
GSInserterThread(uintptr_t start, uintptr_t stop, TestTable* cht, Semaphore* post) : CHTTestThread(start, stop, cht, post) {};
800
virtual ~GSInserterThread(){}
801
bool keep_looping() {
802
return !(_shrink && _cht->get_size_log2(this) == START_SIZE);
803
}
804
bool test_loop() {
805
bool grow;
806
for (uintptr_t v = _start; v <= _stop; v++) {
807
TestLookup tl(v);
808
EXPECT_TRUE(_cht->insert(this, tl, v, &grow)) << "Inserting an unique value should work.";
809
if (grow && !_shrink) {
810
_cht->grow(this);
811
}
812
}
813
for (uintptr_t v = _start; v <= _stop; v++) {
814
TestLookup tl(v);
815
EXPECT_TRUE(cht_get_copy(_cht, this, tl) == v) << "Getting an previously inserted value unsafe failed.";
816
}
817
for (uintptr_t v = _start; v <= _stop; v++) {
818
TestLookup tl(v);
819
EXPECT_TRUE(_cht->remove(this, tl)) << "Removing an existing value failed.";
820
}
821
if (_shrink) {
822
_cht->shrink(this);
823
}
824
for (uintptr_t v = _start; v <= _stop; v++) {
825
TestLookup tl(v);
826
EXPECT_FALSE(cht_get_copy(_cht, this, tl) == v) << "Getting a removed value should have failed.";
827
}
828
if (!_shrink && _cht->get_size_log2(this) == END_SIZE) {
829
_shrink = true;
830
}
831
return true;
832
}
833
};
834
835
volatile bool GSInserterThread::_shrink = false;
836
837
class GSScannerThread : public CHTTestThread {
838
public:
839
GSScannerThread(uintptr_t start, uintptr_t stop, TestTable* cht, Semaphore* post) : CHTTestThread(start, stop, cht, post) {};
840
virtual ~GSScannerThread(){}
841
842
bool operator()(uintptr_t* val) {
843
if (*val >= this->_start && *val <= this->_stop) {
844
return false;
845
}
846
// continue scan
847
return true;
848
}
849
850
bool test_loop() {
851
_cht->try_scan(this, *this);
852
os::naked_short_sleep(5);
853
return true;
854
}
855
};
856
857
class RunnerGSInserterThread : public CHTTestThread {
858
public:
859
uintptr_t _start;
860
uintptr_t _range;
861
Semaphore _done;
862
863
RunnerGSInserterThread(Semaphore* post) : CHTTestThread(0, 0, NULL, post) {
864
_cht = new TestTable(START_SIZE, END_SIZE, 2);
865
};
866
virtual ~RunnerGSInserterThread(){}
867
868
void premain() {
869
volatile bool timeout = false;
870
_start = START;
871
_range = RANGE;
872
CHTTestThread* tt[GSTEST_THREAD_COUNT];
873
tt[0] = new GSInserterThread(_start, _start + _range, _cht, &_done);
874
_start += _range + 1;
875
tt[1] = new GSInserterThread(_start, _start + _range, _cht, &_done);
876
_start += _range + 1;
877
tt[2] = new GSInserterThread(_start, _start + _range, _cht, &_done);
878
_start += _range + 1;
879
tt[3] = new GSInserterThread(_start, _start + _range, _cht, &_done);
880
tt[4] = new GSScannerThread(_start, _start + _range, _cht, &_done);
881
_start += _range + 1;
882
883
884
for (uintptr_t v = _start; v <= (_start + _range); v++ ) {
885
TestLookup tl(v);
886
EXPECT_TRUE(_cht->insert(this, tl, v)) << "Inserting an unique value should work.";
887
}
888
889
for (int i = 0; i < GSTEST_THREAD_COUNT; i++) {
890
tt[i]->doit();
891
}
892
}
893
894
bool test_loop() {
895
for (uintptr_t v = _start; v <= (_start + _range); v++ ) {
896
TestLookup tl(v);
897
EXPECT_TRUE(cht_get_copy(_cht, this, tl) == v) << "Getting an previously inserted value unsafe failed.";
898
}
899
return true;
900
}
901
902
void postmain() {
903
GSInserterThread::_shrink = true;
904
for (uintptr_t v = _start; v <= (_start + _range); v++ ) {
905
TestLookup tl(v);
906
EXPECT_TRUE(_cht->remove(this, tl)) << "Removing an existing value failed.";
907
}
908
for (int i = 0; i < GSTEST_THREAD_COUNT; i++) {
909
_done.wait();
910
}
911
EXPECT_TRUE(_cht->get_size_log2(this) == START_SIZE) << "Not at start size.";
912
Count cnt;
913
_cht->do_scan(this, cnt);
914
EXPECT_TRUE(cnt._cnt == 0) << "Items still in table";
915
delete _cht;
916
}
917
918
struct Count {
919
Count() : _cnt(0) {}
920
size_t _cnt;
921
bool operator()(uintptr_t*) { _cnt++; return true; };
922
};
923
};
924
925
TEST_VM(ConcurrentHashTable, concurrent_scan_grow_shrink) {
926
GSInserterThread::_shrink = false;
927
mt_test_doer<RunnerGSInserterThread>();
928
}
929
930
931
//#############################################################################################
932
933
#define GI_BD_GI_BD_START_SIZE 13
934
#define GI_BD_END_SIZE 17
935
#define GI_BD_START (uintptr_t)0x1
936
#define GI_BD_RANGE (uintptr_t)0x3FFFF
937
938
#define GI_BD_TEST_THREAD_COUNT 4
939
940
941
class GI_BD_InserterThread: public CHTTestThread {
942
public:
943
static volatile bool _shrink;
944
uintptr_t _br;
945
GI_BD_InserterThread(uintptr_t start, uintptr_t stop, TestTable* cht, Semaphore* post, uintptr_t br)
946
: CHTTestThread(start, stop, cht, post), _br(br) {};
947
virtual ~GI_BD_InserterThread(){}
948
949
bool keep_looping() {
950
return !(_shrink && _cht->get_size_log2(this) == GI_BD_GI_BD_START_SIZE);
951
}
952
953
bool test_loop() {
954
bool grow;
955
MyDel del(_br);
956
for (uintptr_t v = _start; v <= _stop; v++) {
957
{
958
TestLookup tl(v);
959
ValueGet vg;
960
do {
961
if (_cht->get(this, tl, vg, &grow)) {
962
EXPECT_EQ(v, vg.get_value()) << "Getting an old value failed.";
963
break;
964
}
965
if (_cht->insert(this, tl, v, &grow)) {
966
break;
967
}
968
} while(true);
969
}
970
if (grow && !_shrink) {
971
_cht->grow(this);
972
}
973
}
974
if (_shrink) {
975
_cht->shrink(this);
976
}
977
_cht->try_bulk_delete(this, *this, del);
978
if (!_shrink && _cht->is_max_size_reached()) {
979
_shrink = true;
980
}
981
_cht->bulk_delete(this, *this, del);
982
return true;
983
}
984
985
bool operator()(uintptr_t* val) {
986
return (*val & _br) == 1;
987
}
988
989
struct MyDel {
990
MyDel(uintptr_t &br) : _br(br) {};
991
uintptr_t &_br;
992
void operator()(uintptr_t* val) {
993
EXPECT_EQ((*val & _br), _br) << "Removing an item that should not have been removed.";
994
}
995
};
996
};
997
998
volatile bool GI_BD_InserterThread::_shrink = false;
999
1000
class RunnerGI_BD_InserterThread : public CHTTestThread {
1001
public:
1002
Semaphore _done;
1003
uintptr_t _start;
1004
uintptr_t _range;
1005
RunnerGI_BD_InserterThread(Semaphore* post) : CHTTestThread(0, 0, NULL, post) {
1006
_cht = new TestTable(GI_BD_GI_BD_START_SIZE, GI_BD_END_SIZE, 2);
1007
};
1008
virtual ~RunnerGI_BD_InserterThread(){}
1009
1010
void premain() {
1011
_start = GI_BD_START;
1012
_range = GI_BD_RANGE;
1013
CHTTestThread* tt[GI_BD_TEST_THREAD_COUNT];
1014
tt[0] = new GI_BD_InserterThread(_start, _start + _range, _cht, &_done, (uintptr_t)0x1);
1015
tt[1] = new GI_BD_InserterThread(_start, _start + _range, _cht, &_done, (uintptr_t)0x2);
1016
tt[2] = new GI_BD_InserterThread(_start, _start + _range, _cht, &_done, (uintptr_t)0x4);
1017
tt[3] = new GI_BD_InserterThread(_start, _start + _range, _cht, &_done, (uintptr_t)0x8);
1018
1019
for (uintptr_t v = _start; v <= (_start + _range); v++ ) {
1020
TestLookup tl(v);
1021
EXPECT_TRUE(_cht->insert(this, tl, v)) << "Inserting an unique value should work.";
1022
}
1023
1024
for (int i =0; i < GI_BD_TEST_THREAD_COUNT; i++) {
1025
tt[i]->doit();
1026
}
1027
}
1028
1029
bool test_loop() {
1030
for (uintptr_t v = _start; v <= (_start + _range); v++ ) {
1031
TestLookup tl(v);
1032
if (v & 0xF) {
1033
cht_get_copy(_cht, this, tl);
1034
} else {
1035
EXPECT_EQ(cht_get_copy(_cht, this, tl), v) << "Item ending with 0xX0 should never be removed.";
1036
}
1037
}
1038
return true;
1039
}
1040
1041
void postmain() {
1042
GI_BD_InserterThread::_shrink = true;
1043
for (uintptr_t v = _start; v <= (_start + _range); v++ ) {
1044
TestLookup tl(v);
1045
if (v & 0xF) {
1046
_cht->remove(this, tl);
1047
} else {
1048
EXPECT_TRUE(_cht->remove(this, tl)) << "Removing item ending with 0xX0 should always work.";
1049
}
1050
}
1051
for (int i = 0; i < GI_BD_TEST_THREAD_COUNT; i++) {
1052
_done.wait();
1053
}
1054
EXPECT_TRUE(_cht->get_size_log2(this) == GI_BD_GI_BD_START_SIZE) << "We have not shrunk back to start size.";
1055
delete _cht;
1056
}
1057
};
1058
1059
TEST_VM(ConcurrentHashTable, concurrent_get_insert_bulk_delete) {
1060
GI_BD_InserterThread::_shrink = false;
1061
mt_test_doer<RunnerGI_BD_InserterThread>();
1062
}
1063
1064
//#############################################################################################
1065
1066
class MT_BD_Thread : public JavaTestThread {
1067
TestTable::BulkDeleteTask* _bd;
1068
public:
1069
MT_BD_Thread(Semaphore* post, TestTable::BulkDeleteTask* bd)
1070
: JavaTestThread(post), _bd(bd){}
1071
virtual ~MT_BD_Thread() {}
1072
void main_run() {
1073
MyDel del;
1074
while(_bd->do_task(this, *this, del));
1075
}
1076
1077
bool operator()(uintptr_t* val) {
1078
return true;
1079
}
1080
1081
struct MyDel {
1082
void operator()(uintptr_t* val) {
1083
}
1084
};
1085
};
1086
1087
class Driver_BD_Thread : public JavaTestThread {
1088
public:
1089
Semaphore _done;
1090
Driver_BD_Thread(Semaphore* post) : JavaTestThread(post) {
1091
};
1092
virtual ~Driver_BD_Thread(){}
1093
1094
void main_run() {
1095
Semaphore done(0);
1096
TestTable* cht = new TestTable(16, 16, 2);
1097
for (uintptr_t v = 1; v < 99999; v++ ) {
1098
TestLookup tl(v);
1099
EXPECT_TRUE(cht->insert(this, tl, v)) << "Inserting an unique value should work.";
1100
}
1101
TestTable::BulkDeleteTask bdt(cht, true /* mt */ );
1102
EXPECT_TRUE(bdt.prepare(this)) << "Uncontended prepare must work.";
1103
1104
MT_BD_Thread* tt[4];
1105
for (int i = 0; i < 4; i++) {
1106
tt[i] = new MT_BD_Thread(&done, &bdt);
1107
tt[i]->doit();
1108
}
1109
1110
for (uintptr_t v = 1; v < 99999; v++ ) {
1111
TestLookup tl(v);
1112
cht_get_copy(cht, this, tl);
1113
}
1114
1115
for (int i = 0; i < 4; i++) {
1116
done.wait();
1117
}
1118
1119
bdt.done(this);
1120
1121
cht->do_scan(this, *this);
1122
}
1123
1124
bool operator()(uintptr_t* val) {
1125
EXPECT_TRUE(false) << "No items should left";
1126
return true;
1127
}
1128
};
1129
1130
TEST_VM(ConcurrentHashTable, concurrent_mt_bulk_delete) {
1131
mt_test_doer<Driver_BD_Thread>();
1132
}
1133
1134