Path: blob/master/test/hotspot/gtest/utilities/test_lockFreeStack.cpp
41145 views
/*1* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*/2223#include "precompiled.hpp"24#include "memory/allocation.inline.hpp"25#include "runtime/atomic.hpp"26#include "utilities/globalDefinitions.hpp"27#include "utilities/lockFreeStack.hpp"28#include "threadHelper.inline.hpp"29#include "unittest.hpp"30#include <new>3132class LockFreeStackTestElement {33typedef LockFreeStackTestElement Element;3435Element* volatile _entry;36Element* volatile _entry1;37size_t _id;3839static Element* volatile* entry_ptr(Element& e) { return &e._entry; }40static Element* volatile* entry1_ptr(Element& e) { return &e._entry1; }4142public:43LockFreeStackTestElement(size_t id = 0) : _entry(), _entry1(), _id(id) {}44size_t id() const { return _id; }45void set_id(size_t value) { _id = value; }4647typedef LockFreeStack<Element, &entry_ptr> TestStack;48typedef LockFreeStack<Element, &entry1_ptr> TestStack1;49};5051typedef LockFreeStackTestElement Element;52typedef Element::TestStack TestStack;53typedef Element::TestStack1 TestStack1;5455static void initialize_ids(Element* elements, size_t size) {56for (size_t i = 0; i < size; ++i) {57elements[i].set_id(i);58}59}6061class LockFreeStackTestBasics : public ::testing::Test {62public:63LockFreeStackTestBasics();6465static const size_t nelements = 10;66Element elements[nelements];67TestStack stack;6869private:70void initialize();71};7273const size_t LockFreeStackTestBasics::nelements;7475LockFreeStackTestBasics::LockFreeStackTestBasics() : stack() {76initialize_ids(elements, nelements);77initialize();78}7980void LockFreeStackTestBasics::initialize() {81ASSERT_TRUE(stack.empty());82ASSERT_EQ(0u, stack.length());83ASSERT_TRUE(stack.pop() == NULL);84ASSERT_TRUE(stack.top() == NULL);8586for (size_t id = 0; id < nelements; ++id) {87ASSERT_EQ(id, stack.length());88Element* e = &elements[id];89ASSERT_EQ(id, e->id());90stack.push(*e);91ASSERT_FALSE(stack.empty());92ASSERT_EQ(e, stack.top());93}94}9596TEST_F(LockFreeStackTestBasics, push_pop) {97for (size_t i = nelements; i > 0; ) {98ASSERT_FALSE(stack.empty());99ASSERT_EQ(i, stack.length());100--i;101Element* e = stack.pop();102ASSERT_TRUE(e != NULL);103ASSERT_EQ(&elements[i], e);104ASSERT_EQ(i, e->id());105}106ASSERT_TRUE(stack.empty());107ASSERT_EQ(0u, stack.length());108ASSERT_TRUE(stack.pop() == NULL);109}110111TEST_F(LockFreeStackTestBasics, prepend_one) {112TestStack other_stack;113ASSERT_TRUE(other_stack.empty());114ASSERT_TRUE(other_stack.pop() == NULL);115ASSERT_EQ(0u, other_stack.length());116ASSERT_TRUE(other_stack.top() == NULL);117ASSERT_TRUE(other_stack.pop() == NULL);118119other_stack.prepend(*stack.pop_all());120ASSERT_EQ(nelements, other_stack.length());121ASSERT_TRUE(stack.empty());122ASSERT_EQ(0u, stack.length());123ASSERT_TRUE(stack.pop() == NULL);124ASSERT_TRUE(stack.top() == NULL);125126for (size_t i = nelements; i > 0; ) {127ASSERT_EQ(i, other_stack.length());128--i;129Element* e = other_stack.pop();130ASSERT_TRUE(e != NULL);131ASSERT_EQ(&elements[i], e);132ASSERT_EQ(i, e->id());133}134ASSERT_EQ(0u, other_stack.length());135ASSERT_TRUE(other_stack.pop() == NULL);136}137138TEST_F(LockFreeStackTestBasics, prepend_two) {139TestStack other_stack;140ASSERT_TRUE(other_stack.empty());141ASSERT_EQ(0u, other_stack.length());142ASSERT_TRUE(other_stack.top() == NULL);143ASSERT_TRUE(other_stack.pop() == NULL);144145Element* top = stack.pop_all();146ASSERT_EQ(top, &elements[nelements - 1]);147other_stack.prepend(*top, elements[0]);148149for (size_t i = nelements; i > 0; ) {150ASSERT_EQ(i, other_stack.length());151--i;152Element* e = other_stack.pop();153ASSERT_TRUE(e != NULL);154ASSERT_EQ(&elements[i], e);155ASSERT_EQ(i, e->id());156}157ASSERT_EQ(0u, other_stack.length());158ASSERT_TRUE(other_stack.pop() == NULL);159}160161TEST_F(LockFreeStackTestBasics, two_stacks) {162TestStack1 stack1;163ASSERT_TRUE(stack1.pop() == NULL);164165for (size_t id = 0; id < nelements; ++id) {166stack1.push(elements[id]);167}168ASSERT_EQ(nelements, stack1.length());169Element* e0 = stack.top();170Element* e1 = stack1.top();171while (true) {172ASSERT_EQ(e0, e1);173if (e0 == NULL) break;174e0 = stack.next(*e0);175e1 = stack1.next(*e1);176}177178for (size_t i = nelements; i > 0; ) {179ASSERT_EQ(i, stack.length());180ASSERT_EQ(i, stack1.length());181--i;182Element* e = stack.pop();183ASSERT_TRUE(e != NULL);184ASSERT_EQ(&elements[i], e);185ASSERT_EQ(i, e->id());186187Element* e1 = stack1.pop();188ASSERT_TRUE(e1 != NULL);189ASSERT_EQ(&elements[i], e1);190ASSERT_EQ(i, e1->id());191192ASSERT_EQ(e, e1);193}194ASSERT_EQ(0u, stack.length());195ASSERT_EQ(0u, stack1.length());196ASSERT_TRUE(stack.pop() == NULL);197ASSERT_TRUE(stack1.pop() == NULL);198}199200class LockFreeStackTestThread : public JavaTestThread {201uint _id;202TestStack* _from;203TestStack* _to;204volatile size_t* _processed;205size_t _process_limit;206size_t _local_processed;207volatile bool _ready;208209public:210LockFreeStackTestThread(Semaphore* post,211uint id,212TestStack* from,213TestStack* to,214volatile size_t* processed,215size_t process_limit) :216JavaTestThread(post),217_id(id),218_from(from),219_to(to),220_processed(processed),221_process_limit(process_limit),222_local_processed(0),223_ready(false)224{}225226virtual void main_run() {227Atomic::release_store_fence(&_ready, true);228while (true) {229Element* e = _from->pop();230if (e != NULL) {231_to->push(*e);232Atomic::inc(_processed);233++_local_processed;234} else if (Atomic::load_acquire(_processed) == _process_limit) {235tty->print_cr("thread %u processed " SIZE_FORMAT, _id, _local_processed);236return;237}238}239}240241bool ready() const { return Atomic::load_acquire(&_ready); }242};243244TEST_VM(LockFreeStackTest, stress) {245Semaphore post;246TestStack initial_stack;247TestStack start_stack;248TestStack middle_stack;249TestStack final_stack;250volatile size_t stage1_processed = 0;251volatile size_t stage2_processed = 0;252253const size_t nelements = 10000;254Element* elements = NEW_C_HEAP_ARRAY(Element, nelements, mtOther);255for (size_t id = 0; id < nelements; ++id) {256::new (&elements[id]) Element(id);257initial_stack.push(elements[id]);258}259ASSERT_EQ(nelements, initial_stack.length());260261// - stage1 threads pop from start_stack and push to middle_stack.262// - stage2 threads pop from middle_stack and push to final_stack.263// - all threads in a stage count the number of elements processed in264// their corresponding stageN_processed counter.265266const uint stage1_threads = 2;267const uint stage2_threads = 2;268const uint nthreads = stage1_threads + stage2_threads;269LockFreeStackTestThread* threads[nthreads] = {};270271for (uint i = 0; i < ARRAY_SIZE(threads); ++i) {272TestStack* from = &start_stack;273TestStack* to = &middle_stack;274volatile size_t* processed = &stage1_processed;275if (i >= stage1_threads) {276from = &middle_stack;277to = &final_stack;278processed = &stage2_processed;279}280threads[i] =281new LockFreeStackTestThread(&post, i, from, to, processed, nelements);282threads[i]->doit();283while (!threads[i]->ready()) {} // Wait until ready to start test.284}285286// Transfer elements to start_stack to start test.287start_stack.prepend(*initial_stack.pop_all());288289// Wait for all threads to complete.290for (uint i = 0; i < nthreads; ++i) {291post.wait();292}293294// Verify expected state.295ASSERT_EQ(nelements, stage1_processed);296ASSERT_EQ(nelements, stage2_processed);297ASSERT_EQ(0u, initial_stack.length());298ASSERT_EQ(0u, start_stack.length());299ASSERT_EQ(0u, middle_stack.length());300ASSERT_EQ(nelements, final_stack.length());301while (final_stack.pop() != NULL) {}302303FREE_C_HEAP_ARRAY(Element, elements);304}305306307