1 /* 2 * Copyright (c) 2018, 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/vm_operations.hpp" 30 #include "utilities/concurrentHashTable.inline.hpp" 31 #include "utilities/concurrentHashTableTasks.inline.hpp" 32 #include "utilitiesHelper.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; 40 41 typedef ConcurrentHashTable<uintptr_t, Pointer, mtInternal> SimpleTestTable; 42 typedef ConcurrentHashTable<uintptr_t, Pointer, mtInternal>::MultiGetHandle SimpleTestGetHandle; 43 44 // Simplest working CRPT implementation for the hash-table. 45 struct Pointer : public SimpleTestTable::BaseConfig { 46 static uintx get_hash(const uintptr_t& value, bool* dead_hash) { 47 return (uintx)value; 48 } 49 static const uintptr_t& notfound() { 50 static uintptr_t notfound = 0; 51 return notfound; 52 } 53 static void* allocate_node(size_t size, const uintptr_t& value) { 54 return ::malloc(size); 55 } 56 static void free_node(void* memory, const uintptr_t& value) { 57 ::free(memory); 58 } 59 }; 60 61 struct SimpleTestLookup { 62 uintptr_t _val; 63 SimpleTestLookup(uintptr_t val) : _val(val) {} 64 uintx get_hash() { 65 return Pointer::get_hash(_val, NULL); 66 } 67 bool equals(const uintptr_t* value, bool* is_dead) { 68 return _val == *value; 69 } 70 }; 71 72 static void cht_insert(Thread* thr) { 73 uintptr_t val = 0x2; 74 SimpleTestLookup stl(val); 75 SimpleTestTable* cht = new SimpleTestTable(); 76 EXPECT_TRUE(cht->insert(thr, stl, val)) << "Insert unique value failed."; 77 EXPECT_EQ(cht->get_copy(thr, stl), val) << "Getting an existing value failed."; 78 EXPECT_TRUE(cht->remove(thr, stl)) << "Removing an existing value failed."; 79 EXPECT_FALSE(cht->remove(thr, stl)) << "Removing an already removed item succeeded."; 80 EXPECT_NE(cht->get_copy(thr, stl), val) << "Getting a removed value succeeded."; 81 delete cht; 82 } 83 84 struct ValVerify { 85 uintptr_t _val; 86 bool called_get; 87 bool called_insert; 88 ValVerify(uintptr_t val) : called_get(false), called_insert(false), _val(val) {} 89 void operator()(bool inserted, uintptr_t* val) { 90 EXPECT_EQ(_val, *val) << "The value inserted is not correct."; 91 if (inserted) { 92 called_insert = true; 93 } else { 94 called_get = true; 95 } 96 } 97 void verify(bool get, bool insert) { 98 EXPECT_EQ(called_get, get) << "Get unexpected"; 99 EXPECT_EQ(called_insert, insert) << "Insert unexpected"; 100 } 101 }; 102 103 static void cht_get_insert_helper(Thread* thr, SimpleTestTable* cht, uintptr_t val) { 104 { 105 SimpleTestLookup stl(val); 106 ValVerify vv(val); 107 EXPECT_EQ(cht->get_insert(thr, stl, val, vv), false) << "Inserting an unique value failed."; 108 vv.verify(false, true); 109 } 110 111 { 112 SimpleTestLookup stl(val); 113 ValVerify vv(val); 114 EXPECT_EQ(cht->get_insert(thr, stl, val, vv), true) << "Getting an old value failed."; 115 vv.verify(true, false); 116 } 117 } 118 119 static void cht_get_insert(Thread* thr) { 120 uintptr_t val = 0x2; 121 SimpleTestLookup stl(val); 122 SimpleTestTable* cht = new SimpleTestTable(); 123 124 { 125 SCOPED_TRACE("First"); 126 cht_get_insert_helper(thr, cht, val); 127 } 128 EXPECT_EQ(cht->get_copy(thr, stl), val) << "Get an old value failed"; 129 EXPECT_TRUE(cht->remove(thr, stl)) << "Removing existing value failed."; 130 EXPECT_NE(cht->get_copy(thr, stl), val) << "Got an already removed item."; 131 132 { 133 SCOPED_TRACE("Second"); 134 cht_get_insert_helper(thr, cht, val); 135 } 136 137 delete cht; 138 } 139 140 static bool getinsert_bulkdelete_eval(uintptr_t* val) { 141 EXPECT_TRUE(*val > 0 && *val < 4) << "Val wrong for this test."; 142 return (*val & 0x1); // Delete all values ending with first bit set. 143 } 144 145 static void getinsert_bulkdelete_del(uintptr_t* val) { 146 EXPECT_EQ(*val & 0x1, (uintptr_t)1) << "Deleting wrong value."; 147 } 148 149 static void cht_getinsert_bulkdelete_insert_verified(Thread* thr, SimpleTestTable* cht, uintptr_t val, 150 bool verify_expect_get, bool verify_expect_inserted) { 151 ValVerify vv(val); 152 SimpleTestLookup stl(val); 153 EXPECT_EQ(cht->get_insert(thr, stl, val, vv), verify_expect_get) << "Inserting an unique value failed."; 154 vv.verify(verify_expect_get, verify_expect_inserted); 155 } 156 157 static void cht_getinsert_bulkdelete(Thread* thr) { 158 uintptr_t val1 = 1; 159 uintptr_t val2 = 2; 160 uintptr_t val3 = 3; 161 SimpleTestLookup stl1(val1), stl2(val2), stl3(val3); 162 163 SimpleTestTable* cht = new SimpleTestTable(); 164 cht_getinsert_bulkdelete_insert_verified(thr, cht, val1, false, true); 165 cht_getinsert_bulkdelete_insert_verified(thr, cht, val2, false, true); 166 cht_getinsert_bulkdelete_insert_verified(thr, cht, val3, false, true); 167 168 EXPECT_TRUE(cht->remove(thr, stl2)) << "Remove did not find value."; 169 170 cht_getinsert_bulkdelete_insert_verified(thr, cht, val1, true, false); // val1 should be present 171 cht_getinsert_bulkdelete_insert_verified(thr, cht, val2, false, true); // val2 should be inserted 172 cht_getinsert_bulkdelete_insert_verified(thr, cht, val3, true, false); // val3 should be present 173 174 EXPECT_EQ(cht->get_copy(thr, stl1), val1) << "Get did not find value."; 175 EXPECT_EQ(cht->get_copy(thr, stl2), val2) << "Get did not find value."; 176 EXPECT_EQ(cht->get_copy(thr, stl3), val3) << "Get did not find value."; 177 178 // Removes all odd values. 179 cht->bulk_delete(thr, getinsert_bulkdelete_eval, getinsert_bulkdelete_del); 180 181 EXPECT_EQ(cht->get_copy(thr, stl1), (uintptr_t)0) << "Odd value should not exist."; 182 EXPECT_FALSE(cht->remove(thr, stl1)) << "Odd value should not exist."; 183 EXPECT_EQ(cht->get_copy(thr, stl2), val2) << "Even value should not have been removed."; 184 EXPECT_EQ(cht->get_copy(thr, stl3), (uintptr_t)0) << "Add value should not exists."; 185 EXPECT_FALSE(cht->remove(thr, stl3)) << "Odd value should not exists."; 186 187 delete cht; 188 } 189 190 static void cht_getinsert_bulkdelete_task(Thread* thr) { 191 uintptr_t val1 = 1; 192 uintptr_t val2 = 2; 193 uintptr_t val3 = 3; 194 SimpleTestLookup stl1(val1), stl2(val2), stl3(val3); 195 196 SimpleTestTable* cht = new SimpleTestTable(); 197 cht_getinsert_bulkdelete_insert_verified(thr, cht, val1, false, true); 198 cht_getinsert_bulkdelete_insert_verified(thr, cht, val2, false, true); 199 cht_getinsert_bulkdelete_insert_verified(thr, cht, val3, false, true); 200 201 EXPECT_TRUE(cht->remove(thr, stl2)) << "Remove did not find value."; 202 203 cht_getinsert_bulkdelete_insert_verified(thr, cht, val1, true, false); // val1 should be present 204 cht_getinsert_bulkdelete_insert_verified(thr, cht, val2, false, true); // val2 should be inserted 205 cht_getinsert_bulkdelete_insert_verified(thr, cht, val3, true, false); // val3 should be present 206 207 EXPECT_EQ(cht->get_copy(thr, stl1), val1) << "Get did not find value."; 208 EXPECT_EQ(cht->get_copy(thr, stl2), val2) << "Get did not find value."; 209 EXPECT_EQ(cht->get_copy(thr, stl3), val3) << "Get did not find value."; 210 211 // Removes all odd values. 212 SimpleTestTable::BulkDeleteTask bdt(cht); 213 if (bdt.prepare(thr)) { 214 while(bdt.doTask(thr, getinsert_bulkdelete_eval, getinsert_bulkdelete_del)) { 215 bdt.pause(thr); 216 EXPECT_TRUE(bdt.cont(thr)) << "Uncontended continue should work."; 217 } 218 bdt.done(thr); 219 } 220 221 EXPECT_EQ(cht->get_copy(thr, stl1), (uintptr_t)0) << "Odd value should not exist."; 222 EXPECT_FALSE(cht->remove(thr, stl1)) << "Odd value should not exist."; 223 EXPECT_EQ(cht->get_copy(thr, stl2), val2) << "Even value should not have been removed."; 224 EXPECT_EQ(cht->get_copy(thr, stl3), (uintptr_t)0) << "Add value should not exists."; 225 EXPECT_FALSE(cht->remove(thr, stl3)) << "Odd value should not exists."; 226 227 delete cht; 228 } 229 230 static void cht_scope(Thread* thr) { 231 uintptr_t val = 0x2; 232 SimpleTestLookup stl(val); 233 SimpleTestTable* cht = new SimpleTestTable(); 234 EXPECT_TRUE(cht->insert(thr, stl, val)) << "Insert unique value failed."; 235 { 236 SimpleTestGetHandle get_handle(thr, cht); 237 EXPECT_EQ(*get_handle.get(stl), val) << "Getting a pre-existing value failed."; 238 } 239 // We do remove here to make sure the value-handle 'unlocked' the table when leaving the scope. 240 EXPECT_TRUE(cht->remove(thr, stl)) << "Removing a pre-existing value failed."; 241 EXPECT_FALSE(cht->get_copy(thr, stl) == val) << "Got a removed value."; 242 delete cht; 243 } 244 245 struct ChtScan { 246 size_t _count; 247 ChtScan() : _count(0) {} 248 bool operator()(uintptr_t* val) { 249 EXPECT_EQ(*val, (uintptr_t)0x2) << "Got an unknown value."; 250 EXPECT_EQ(_count, 0u) << "Only one value should be in table."; 251 _count++; 252 return true; /* continue scan */ 253 } 254 }; 255 256 static void cht_scan(Thread* thr) { 257 uintptr_t val = 0x2; 258 SimpleTestLookup stl(val); 259 ChtScan scan; 260 SimpleTestTable* cht = new SimpleTestTable(); 261 EXPECT_TRUE(cht->insert(thr, stl, val)) << "Insert unique value failed."; 262 EXPECT_EQ(cht->try_scan(thr, scan), true) << "Scanning an non-growing/shrinking table should work."; 263 EXPECT_TRUE(cht->remove(thr, stl)) << "Removing a pre-existing value failed."; 264 EXPECT_FALSE(cht->get_copy(thr, stl) == val) << "Got a removed value."; 265 delete cht; 266 } 267 268 static void cht_grow(Thread* thr) { 269 uintptr_t val = 0x2; 270 uintptr_t val2 = 0x22; 271 uintptr_t val3 = 0x222; 272 SimpleTestLookup stl(val), stl2(val2), stl3(val3); 273 SimpleTestTable* cht = new SimpleTestTable(); 274 275 EXPECT_TRUE(cht->insert(thr, stl, val)) << "Insert unique value failed."; 276 EXPECT_TRUE(cht->insert(thr, stl2, val2)) << "Insert unique value failed."; 277 EXPECT_TRUE(cht->insert(thr, stl3, val3)) << "Insert unique value failed."; 278 EXPECT_FALSE(cht->insert(thr, stl3, val3)) << "Insert duplicate value should have failed."; 279 EXPECT_TRUE(cht->get_copy(thr, stl) == val) << "Getting an inserted value should work."; 280 EXPECT_TRUE(cht->get_copy(thr, stl2) == val2) << "Getting an inserted value should work."; 281 EXPECT_TRUE(cht->get_copy(thr, stl3) == val3) << "Getting an inserted value should work."; 282 283 EXPECT_TRUE(cht->remove(thr, stl2)) << "Removing an inserted value should work."; 284 285 EXPECT_TRUE(cht->get_copy(thr, stl) == val) << "Getting an inserted value should work."; 286 EXPECT_FALSE(cht->get_copy(thr, stl2) == val2) << "Getting a removed value should have failed."; 287 EXPECT_TRUE(cht->get_copy(thr, stl3) == val3) << "Getting an inserted value should work."; 288 289 290 EXPECT_TRUE(cht->grow(thr)) << "Growing uncontended should not fail."; 291 292 EXPECT_TRUE(cht->get_copy(thr, stl) == val) << "Getting an item after grow failed."; 293 EXPECT_FALSE(cht->get_copy(thr, stl2) == val2) << "Getting a removed value after grow should have failed."; 294 EXPECT_TRUE(cht->get_copy(thr, stl3) == val3) << "Getting an item after grow failed."; 295 296 EXPECT_TRUE(cht->insert(thr, stl2, val2)) << "Insert unique value failed."; 297 EXPECT_TRUE(cht->remove(thr, stl3)) << "Removing an inserted value should work."; 298 299 EXPECT_TRUE(cht->shrink(thr)) << "Shrinking uncontended should not fail."; 300 301 EXPECT_TRUE(cht->get_copy(thr, stl) == val) << "Getting an item after shrink failed."; 302 EXPECT_TRUE(cht->get_copy(thr, stl2) == val2) << "Getting an item after shrink failed."; 303 EXPECT_FALSE(cht->get_copy(thr, stl3) == val3) << "Getting a removed value after shrink should have failed."; 304 305 delete cht; 306 } 307 308 static void cht_task_grow(Thread* thr) { 309 uintptr_t val = 0x2; 310 uintptr_t val2 = 0x22; 311 uintptr_t val3 = 0x222; 312 SimpleTestLookup stl(val), stl2(val2), stl3(val3); 313 SimpleTestTable* cht = new SimpleTestTable(); 314 315 EXPECT_TRUE(cht->insert(thr, stl, val)) << "Insert unique value failed."; 316 EXPECT_TRUE(cht->insert(thr, stl2, val2)) << "Insert unique value failed."; 317 EXPECT_TRUE(cht->insert(thr, stl3, val3)) << "Insert unique value failed."; 318 EXPECT_FALSE(cht->insert(thr, stl3, val3)) << "Insert duplicate value should have failed."; 319 EXPECT_TRUE(cht->get_copy(thr, stl) == val) << "Getting an inserted value should work."; 320 EXPECT_TRUE(cht->get_copy(thr, stl2) == val2) << "Getting an inserted value should work."; 321 EXPECT_TRUE(cht->get_copy(thr, stl3) == val3) << "Getting an inserted value should work."; 322 323 EXPECT_TRUE(cht->remove(thr, stl2)) << "Removing an inserted value should work."; 324 325 EXPECT_TRUE(cht->get_copy(thr, stl) == val) << "Getting an inserted value should work."; 326 EXPECT_FALSE(cht->get_copy(thr, stl2) == val2) << "Getting a removed value should have failed."; 327 EXPECT_TRUE(cht->get_copy(thr, stl3) == val3) << "Getting an inserted value should work."; 328 329 SimpleTestTable::GrowTask gt(cht); 330 EXPECT_TRUE(gt.prepare(thr)) << "Growing uncontended should not fail."; 331 while(gt.doTask(thr)) { /* grow */ } 332 gt.done(thr); 333 334 EXPECT_TRUE(cht->get_copy(thr, stl) == val) << "Getting an item after grow failed."; 335 EXPECT_FALSE(cht->get_copy(thr, stl2) == val2) << "Getting a removed value after grow should have failed."; 336 EXPECT_TRUE(cht->get_copy(thr, stl3) == val3) << "Getting an item after grow failed."; 337 338 EXPECT_TRUE(cht->insert(thr, stl2, val2)) << "Insert unique value failed."; 339 EXPECT_TRUE(cht->remove(thr, stl3)) << "Removing an inserted value should work."; 340 341 EXPECT_TRUE(cht->shrink(thr)) << "Shrinking uncontended should not fail."; 342 343 EXPECT_TRUE(cht->get_copy(thr, stl) == val) << "Getting an item after shrink failed."; 344 EXPECT_TRUE(cht->get_copy(thr, stl2) == val2) << "Getting an item after shrink failed."; 345 EXPECT_FALSE(cht->get_copy(thr, stl3) == val3) << "Getting a removed value after shrink should have failed."; 346 347 delete cht; 348 } 349 350 TEST_VM(ConcurrentHashTable, basic_insert) { 351 nomt_test_doer(cht_insert); 352 } 353 354 TEST_VM(ConcurrentHashTable, basic_get_insert) { 355 nomt_test_doer(cht_get_insert); 356 } 357 358 TEST_VM(ConcurrentHashTable, basic_scope) { 359 nomt_test_doer(cht_scope); 360 } 361 362 TEST_VM(ConcurrentHashTable, basic_get_insert_bulk_delete) { 363 nomt_test_doer(cht_getinsert_bulkdelete); 364 } 365 366 TEST_VM(ConcurrentHashTable, basic_get_insert_bulk_delete_task) { 367 nomt_test_doer(cht_getinsert_bulkdelete_task); 368 } 369 370 TEST_VM(ConcurrentHashTable, basic_scan) { 371 nomt_test_doer(cht_scan); 372 } 373 374 TEST_VM(ConcurrentHashTable, basic_grow) { 375 nomt_test_doer(cht_grow); 376 } 377 378 TEST_VM(ConcurrentHashTable, task_grow) { 379 nomt_test_doer(cht_task_grow); 380 } 381 382 //############################################################################################# 383 384 class TestInterface; 385 386 typedef ConcurrentHashTable<uintptr_t, TestInterface, mtInternal> TestTable; 387 typedef ConcurrentHashTable<uintptr_t, TestInterface, mtInternal>::MultiGetHandle TestGetHandle; 388 389 class TestInterface : public TestTable::BaseConfig { 390 public: 391 static uintx get_hash(const uintptr_t& value, bool* dead_hash) { 392 return (uintx)(value + 18446744073709551557ul) * 18446744073709551557ul; 393 } 394 static const uintptr_t& notfound() { 395 static uintptr_t notfound = 0; 396 return notfound; 397 } 398 }; 399 400 struct TestLookup { 401 uintptr_t _val; 402 TestLookup(uintptr_t val) : _val(val) {} 403 uintx get_hash() { 404 return TestInterface::get_hash(_val, NULL); 405 } 406 bool equals(const uintptr_t* value, bool* is_dead) { 407 return _val == *value; 408 } 409 }; 410 411 class CHTTestThread : public JavaTestThread { 412 public: 413 uintptr_t _start; 414 uintptr_t _stop; 415 TestTable *_cht; 416 jlong _stop_ms; 417 CHTTestThread(uintptr_t start, uintptr_t stop, TestTable* cht, Semaphore* post) 418 : JavaTestThread(post), _start(start), _stop(stop), _cht(cht) {} 419 virtual void premain() {} 420 void main_run() { 421 premain(); 422 _stop_ms = os::javaTimeMillis() + 2000; // 2 seconds max test time 423 while (keep_looping() && test_loop()) { /* */ } 424 postmain(); 425 } 426 virtual void postmain() {} 427 virtual bool keep_looping() { 428 return _stop_ms > os::javaTimeMillis(); 429 }; 430 virtual bool test_loop() = 0; 431 virtual ~CHTTestThread() {} 432 }; 433 434 class ValueSaver { 435 uintptr_t* _vals; 436 size_t _it; 437 size_t _size; 438 public: 439 ValueSaver() : _it(0), _size(1024) { 440 _vals = NEW_C_HEAP_ARRAY(uintptr_t, _size, mtInternal); 441 } 442 443 bool operator()(uintptr_t* val) { 444 _vals[_it++] = *val; 445 if (_it == _size) { 446 _size *= 2; 447 _vals = REALLOC_RESOURCE_ARRAY(uintptr_t, _vals, _size/2, _size); 448 } 449 return true; 450 } 451 452 void check() { 453 for (size_t i = 0; i < _it; i++) { 454 size_t count = 0; 455 for (size_t j = (i + 1u); j < _it; j++) { 456 if (_vals[i] == _vals[j]) { 457 count++; 458 } 459 } 460 EXPECT_EQ(count, 0u); 461 } 462 } 463 }; 464 465 static void integrity_check(Thread* thr, TestTable* cht) 466 { 467 ValueSaver vs; 468 cht->do_scan(thr, vs); 469 vs.check(); 470 } 471 472 //############################################################################################# 473 // All threads are working on different items 474 // This item should only be delete by this thread 475 // Thus get_unsafe is safe for this test. 476 477 class SimpleInserterThread : public CHTTestThread { 478 public: 479 static volatile bool _exit; 480 481 SimpleInserterThread(uintptr_t start, uintptr_t stop, TestTable* cht, Semaphore* post) 482 : CHTTestThread(start, stop, cht, post) {}; 483 virtual ~SimpleInserterThread(){} 484 485 bool keep_looping() { 486 return !_exit; 487 } 488 489 bool test_loop() { 490 bool grow; 491 for (uintptr_t v = _start; v <= _stop; v++) { 492 TestLookup tl(v); 493 EXPECT_TRUE(_cht->insert(this, tl, v, &grow)) << "Inserting an unique value should work."; 494 } 495 for (uintptr_t v = _start; v <= _stop; v++) { 496 TestLookup tl(v); 497 EXPECT_TRUE(_cht->get_copy(this, tl) == v) << "Getting an previously inserted value unsafe failed."; 498 } 499 for (uintptr_t v = _start; v <= _stop; v++) { 500 TestLookup tl(v); 501 EXPECT_TRUE(_cht->remove(this, tl)) << "Removing an existing value failed."; 502 } 503 for (uintptr_t v = _start; v <= _stop; v++) { 504 TestLookup tl(v); 505 EXPECT_TRUE(_cht->get_copy(this, tl) == TestInterface::notfound()) << "Got a removed value."; 506 } 507 return true; 508 } 509 }; 510 511 volatile bool SimpleInserterThread::_exit = false; 512 513 class RunnerSimpleInserterThread : public CHTTestThread { 514 public: 515 Semaphore _done; 516 517 RunnerSimpleInserterThread(Semaphore* post) : CHTTestThread(0, 0, NULL, post) { 518 _cht = new TestTable(SIZE_32, SIZE_32); 519 }; 520 virtual ~RunnerSimpleInserterThread(){} 521 522 void premain() { 523 524 SimpleInserterThread* ins1 = new SimpleInserterThread((uintptr_t)0x100, (uintptr_t) 0x1FF, _cht, &_done); 525 SimpleInserterThread* ins2 = new SimpleInserterThread((uintptr_t)0x200, (uintptr_t) 0x2FF, _cht, &_done); 526 SimpleInserterThread* ins3 = new SimpleInserterThread((uintptr_t)0x300, (uintptr_t) 0x3FF, _cht, &_done); 527 SimpleInserterThread* ins4 = new SimpleInserterThread((uintptr_t)0x400, (uintptr_t) 0x4FF, _cht, &_done); 528 529 for (uintptr_t v = 0x500; v < 0x5FF; v++ ) { 530 TestLookup tl(v); 531 EXPECT_TRUE(_cht->insert(this, tl, v)) << "Inserting an unique value should work."; 532 } 533 534 ins1->doit(); 535 ins2->doit(); 536 ins3->doit(); 537 ins4->doit(); 538 539 } 540 541 bool test_loop() { 542 for (uintptr_t v = 0x500; v < 0x5FF; v++ ) { 543 TestLookup tl(v); 544 EXPECT_TRUE(_cht->get_copy(this, tl) == v) << "Getting an previously inserted value unsafe failed.";; 545 } 546 return true; 547 } 548 549 void postmain() { 550 SimpleInserterThread::_exit = true; 551 for (int i = 0; i < 4; i++) { 552 _done.wait(); 553 } 554 for (uintptr_t v = 0x500; v < 0x5FF; v++ ) { 555 TestLookup tl(v); 556 EXPECT_TRUE(_cht->remove(this, tl)) << "Removing an existing value failed."; 557 } 558 integrity_check(this, _cht); 559 delete _cht; 560 } 561 }; 562 563 564 TEST_VM(ConcurrentHashTable, concurrent_simple) { 565 SimpleInserterThread::_exit = false; 566 mt_test_doer<RunnerSimpleInserterThread>(); 567 } 568 569 //############################################################################################# 570 // In this test we try to get a 'bad' value 571 class DeleteInserterThread : public CHTTestThread { 572 public: 573 static volatile bool _exit; 574 575 DeleteInserterThread(uintptr_t start, uintptr_t stop, TestTable* cht, Semaphore* post) : CHTTestThread(start, stop, cht, post) {}; 576 virtual ~DeleteInserterThread(){} 577 578 bool keep_looping() { 579 return !_exit; 580 } 581 582 bool test_loop() { 583 for (uintptr_t v = _start; v <= _stop; v++) { 584 TestLookup tl(v); 585 _cht->insert(this, tl, v); 586 } 587 for (uintptr_t v = _start; v <= _stop; v++) { 588 TestLookup tl(v); 589 _cht->remove(this, tl); 590 } 591 return true; 592 } 593 }; 594 595 volatile bool DeleteInserterThread::_exit = true; 596 597 class RunnerDeleteInserterThread : public CHTTestThread { 598 public: 599 Semaphore _done; 600 601 RunnerDeleteInserterThread(Semaphore* post) : CHTTestThread(0, 0, NULL, post) { 602 _cht = new TestTable(SIZE_32, SIZE_32); 603 }; 604 virtual ~RunnerDeleteInserterThread(){} 605 606 void premain() { 607 DeleteInserterThread* ins1 = new DeleteInserterThread((uintptr_t)0x1, (uintptr_t) 0xFFF, _cht, &_done); 608 DeleteInserterThread* ins2 = new DeleteInserterThread((uintptr_t)0x1, (uintptr_t) 0xFFF, _cht, &_done); 609 DeleteInserterThread* ins3 = new DeleteInserterThread((uintptr_t)0x1, (uintptr_t) 0xFFF, _cht, &_done); 610 DeleteInserterThread* ins4 = new DeleteInserterThread((uintptr_t)0x1, (uintptr_t) 0xFFF, _cht, &_done); 611 612 ins1->doit(); 613 ins2->doit(); 614 ins3->doit(); 615 ins4->doit(); 616 } 617 618 bool test_loop() { 619 for (uintptr_t v = 0x1; v < 0xFFF; v++ ) { 620 uintptr_t tv; 621 if (v & 0x1) { 622 TestLookup tl(v); 623 tv = _cht->get_copy(this, tl); 624 } else { 625 TestLookup tl(v); 626 TestGetHandle value_handle(this, _cht); 627 uintptr_t* tmp = value_handle.get(tl); 628 tv = tmp != NULL ? *tmp : 0; 629 } 630 EXPECT_TRUE(tv == 0 || tv == v) << "Got unknown value."; 631 } 632 return true; 633 } 634 635 void postmain() { 636 DeleteInserterThread::_exit = true; 637 for (int i = 0; i < 4; i++) { 638 _done.wait(); 639 } 640 integrity_check(this, _cht); 641 delete _cht; 642 } 643 }; 644 645 TEST_VM(ConcurrentHashTable, concurrent_deletes) { 646 DeleteInserterThread::_exit = false; 647 mt_test_doer<RunnerDeleteInserterThread>(); 648 } 649 650 //############################################################################################# 651 652 #define START_SIZE 13 653 #define END_SIZE 17 654 #define START (uintptr_t)0x10000 655 #define RANGE (uintptr_t)0xFFFF 656 657 #define GSTEST_THREAD_COUNT 5 658 659 660 class GSInserterThread: public CHTTestThread { 661 public: 662 static volatile bool _shrink; 663 GSInserterThread(uintptr_t start, uintptr_t stop, TestTable* cht, Semaphore* post) : CHTTestThread(start, stop, cht, post) {}; 664 virtual ~GSInserterThread(){} 665 bool keep_looping() { 666 return !(_shrink && _cht->get_size_log2(this) == START_SIZE); 667 } 668 bool test_loop() { 669 bool grow; 670 for (uintptr_t v = _start; v <= _stop; v++) { 671 TestLookup tl(v); 672 EXPECT_TRUE(_cht->insert(this, tl, v, &grow)) << "Inserting an unique value should work."; 673 if (grow && !_shrink) { 674 _cht->grow(this); 675 } 676 } 677 for (uintptr_t v = _start; v <= _stop; v++) { 678 TestLookup tl(v); 679 EXPECT_TRUE(_cht->get_copy(this, tl) == v) << "Getting an previously inserted value unsafe failed."; 680 } 681 for (uintptr_t v = _start; v <= _stop; v++) { 682 TestLookup tl(v); 683 EXPECT_TRUE(_cht->remove(this, tl)) << "Removing an existing value failed."; 684 } 685 if (_shrink) { 686 _cht->shrink(this); 687 } 688 for (uintptr_t v = _start; v <= _stop; v++) { 689 TestLookup tl(v); 690 EXPECT_FALSE(_cht->get_copy(this, tl) == v) << "Getting a removed value should have failed."; 691 } 692 if (!_shrink && _cht->get_size_log2(this) == END_SIZE) { 693 _shrink = true; 694 } 695 return true; 696 } 697 }; 698 699 volatile bool GSInserterThread::_shrink = false; 700 701 class GSScannerThread : public CHTTestThread { 702 public: 703 GSScannerThread(uintptr_t start, uintptr_t stop, TestTable* cht, Semaphore* post) : CHTTestThread(start, stop, cht, post) {}; 704 virtual ~GSScannerThread(){} 705 706 bool operator()(uintptr_t* val) { 707 if (*val >= this->_start && *val <= this->_stop) { 708 return false; 709 } 710 // continue scan 711 return true; 712 } 713 714 bool test_loop() { 715 _cht->try_scan(this, *this); 716 os::naked_short_sleep(5); 717 return true; 718 } 719 }; 720 721 class RunnerGSInserterThread : public CHTTestThread { 722 public: 723 uintptr_t _start; 724 uintptr_t _range; 725 Semaphore _done; 726 727 RunnerGSInserterThread(Semaphore* post) : CHTTestThread(0, 0, NULL, post) { 728 _cht = new TestTable(START_SIZE, END_SIZE, 2); 729 }; 730 virtual ~RunnerGSInserterThread(){} 731 732 void premain() { 733 volatile bool timeout = false; 734 _start = START; 735 _range = RANGE; 736 CHTTestThread* tt[GSTEST_THREAD_COUNT]; 737 tt[0] = new GSInserterThread(_start, _start + _range, _cht, &_done); 738 _start += _range + 1; 739 tt[1] = new GSInserterThread(_start, _start + _range, _cht, &_done); 740 _start += _range + 1; 741 tt[2] = new GSInserterThread(_start, _start + _range, _cht, &_done); 742 _start += _range + 1; 743 tt[3] = new GSInserterThread(_start, _start + _range, _cht, &_done); 744 tt[4] = new GSScannerThread(_start, _start + _range, _cht, &_done); 745 _start += _range + 1; 746 747 748 for (uintptr_t v = _start; v <= (_start + _range); v++ ) { 749 TestLookup tl(v); 750 EXPECT_TRUE(_cht->insert(this, tl, v)) << "Inserting an unique value should work."; 751 } 752 753 for (int i = 0; i < GSTEST_THREAD_COUNT; i++) { 754 tt[i]->doit(); 755 } 756 } 757 758 bool test_loop() { 759 for (uintptr_t v = _start; v <= (_start + _range); v++ ) { 760 TestLookup tl(v); 761 EXPECT_TRUE(_cht->get_copy(this, tl) == v) << "Getting an previously inserted value unsafe failed."; 762 } 763 return true; 764 } 765 766 void postmain() { 767 GSInserterThread::_shrink = true; 768 for (uintptr_t v = _start; v <= (_start + _range); v++ ) { 769 TestLookup tl(v); 770 EXPECT_TRUE(_cht->remove(this, tl)) << "Removing an existing value failed."; 771 } 772 for (int i = 0; i < GSTEST_THREAD_COUNT; i++) { 773 _done.wait(); 774 } 775 EXPECT_TRUE(_cht->get_size_log2(this) == START_SIZE) << "Not at start size."; 776 Count cnt; 777 _cht->do_scan(this, cnt); 778 EXPECT_TRUE(cnt._cnt == 0) << "Items still in table"; 779 delete _cht; 780 } 781 782 struct Count { 783 Count() : _cnt(0) {} 784 size_t _cnt; 785 bool operator()(uintptr_t*) { _cnt++; return true; }; 786 }; 787 }; 788 789 TEST_VM(ConcurrentHashTable, concurrent_scan_grow_shrink) { 790 GSInserterThread::_shrink = false; 791 mt_test_doer<RunnerGSInserterThread>(); 792 } 793 794 795 //############################################################################################# 796 797 #define GI_BD_GI_BD_START_SIZE 13 798 #define GI_BD_END_SIZE 17 799 #define GI_BD_START (uintptr_t)0x1 800 #define GI_BD_RANGE (uintptr_t)0x3FFFF 801 802 #define GI_BD_TEST_THREAD_COUNT 4 803 804 805 class GI_BD_InserterThread: public CHTTestThread { 806 public: 807 static volatile bool _shrink; 808 uintptr_t _br; 809 GI_BD_InserterThread(uintptr_t start, uintptr_t stop, TestTable* cht, Semaphore* post, uintptr_t br) 810 : CHTTestThread(start, stop, cht, post), _br(br) {}; 811 virtual ~GI_BD_InserterThread(){} 812 813 bool keep_looping() { 814 return !(_shrink && _cht->get_size_log2(this) == GI_BD_GI_BD_START_SIZE); 815 } 816 817 bool test_loop() { 818 bool grow; 819 MyDel del(_br); 820 for (uintptr_t v = _start; v <= _stop; v++) { 821 ValVerify vv(v); 822 TestLookup tl(v); 823 _cht->get_insert(this, tl, v, vv, &grow); 824 EXPECT_NE(vv.called_get, vv.called_insert) << "Non or both callbacks was called."; 825 if (grow && !_shrink) { 826 _cht->grow(this); 827 } 828 } 829 if (_shrink) { 830 _cht->shrink(this); 831 } 832 _cht->try_bulk_delete(this, *this, del); 833 if (!_shrink && _cht->is_max_size_reached()) { 834 _shrink = true; 835 } 836 _cht->bulk_delete(this, *this, del); 837 return true; 838 } 839 840 bool operator()(uintptr_t* val) { 841 return (*val & _br) == 1; 842 } 843 844 struct MyDel { 845 MyDel(uintptr_t &br) : _br(br) {}; 846 uintptr_t &_br; 847 void operator()(uintptr_t* val) { 848 EXPECT_EQ((*val & _br), _br) << "Removing an item that should not have been removed."; 849 } 850 }; 851 }; 852 853 volatile bool GI_BD_InserterThread::_shrink = false; 854 855 class RunnerGI_BD_InserterThread : public CHTTestThread { 856 public: 857 Semaphore _done; 858 uintptr_t _start; 859 uintptr_t _range; 860 RunnerGI_BD_InserterThread(Semaphore* post) : CHTTestThread(0, 0, NULL, post) { 861 _cht = new TestTable(GI_BD_GI_BD_START_SIZE, GI_BD_END_SIZE, 2); 862 }; 863 virtual ~RunnerGI_BD_InserterThread(){} 864 865 void premain() { 866 _start = GI_BD_START; 867 _range = GI_BD_RANGE; 868 CHTTestThread* tt[GI_BD_TEST_THREAD_COUNT]; 869 tt[0] = new GI_BD_InserterThread(_start, _start + _range, _cht, &_done, (uintptr_t)0x1); 870 tt[1] = new GI_BD_InserterThread(_start, _start + _range, _cht, &_done, (uintptr_t)0x2); 871 tt[2] = new GI_BD_InserterThread(_start, _start + _range, _cht, &_done, (uintptr_t)0x4); 872 tt[3] = new GI_BD_InserterThread(_start, _start + _range, _cht, &_done, (uintptr_t)0x8); 873 874 for (uintptr_t v = _start; v <= (_start + _range); v++ ) { 875 TestLookup tl(v); 876 EXPECT_TRUE(_cht->insert(this, tl, v)) << "Inserting an unique value should work."; 877 } 878 879 for (int i =0; i < GI_BD_TEST_THREAD_COUNT; i++) { 880 tt[i]->doit(); 881 } 882 } 883 884 bool test_loop() { 885 for (uintptr_t v = _start; v <= (_start + _range); v++ ) { 886 TestLookup tl(v); 887 if (v & 0xF) { 888 _cht->get_copy(this, tl); 889 } else { 890 EXPECT_EQ(_cht->get_copy(this, tl), v) << "Item ending with 0xX0 should never be removed."; 891 } 892 } 893 return true; 894 } 895 896 void postmain() { 897 GI_BD_InserterThread::_shrink = true; 898 for (uintptr_t v = _start; v <= (_start + _range); v++ ) { 899 TestLookup tl(v); 900 if (v & 0xF) { 901 _cht->remove(this, tl); 902 } else { 903 EXPECT_TRUE(_cht->remove(this, tl)) << "Removing item ending with 0xX0 should always work."; 904 } 905 } 906 for (int i = 0; i < GI_BD_TEST_THREAD_COUNT; i++) { 907 _done.wait(); 908 } 909 EXPECT_TRUE(_cht->get_size_log2(this) == GI_BD_GI_BD_START_SIZE) << "We have not shrunk back to start size."; 910 delete _cht; 911 } 912 }; 913 914 TEST_VM(ConcurrentHashTable, concurrent_get_insert_bulk_delete) { 915 GI_BD_InserterThread::_shrink = false; 916 mt_test_doer<RunnerGI_BD_InserterThread>(); 917 }