diff --git a/src/hotspot/share/gc/shared/oopStorage.cpp b/src/hotspot/share/gc/shared/oopStorage.cpp index ac66a13..5b4a27c 100644 --- a/src/hotspot/share/gc/shared/oopStorage.cpp +++ b/src/hotspot/share/gc/shared/oopStorage.cpp @@ -727,7 +727,7 @@ OopStorage::OopStorage(const char* name, _allocation_mutex(allocation_mutex), _active_mutex(active_mutex), _allocation_count(0), - _concurrent_iteration_active(false) + _concurrent_iteration_active(0) { _active_array->increment_refcount(); assert(_active_mutex->rank() < _allocation_mutex->rank(), @@ -769,7 +769,7 @@ void OopStorage::delete_empty_blocks_safepoint() { // blocks available for deletion. while (reduce_deferred_updates()) {} // Don't interfere with a concurrent iteration. - if (_concurrent_iteration_active) return; + if (_concurrent_iteration_active > 0) return; // Delete empty (and otherwise deletable) blocks from end of _allocation_list. for (Block* block = _allocation_list.tail(); (block != NULL) && block->is_deletable(); @@ -804,7 +804,7 @@ void OopStorage::delete_empty_blocks_concurrent() { { MutexLockerEx aml(_active_mutex, Mutex::_no_safepoint_check_flag); // Don't interfere with a concurrent iteration. - if (_concurrent_iteration_active) return; + if (_concurrent_iteration_active > 0) return; _active_array->remove(block); } // Remove block from _allocation_list and delete it. @@ -875,7 +875,7 @@ OopStorage::BasicParState::BasicParState(const OopStorage* storage, _concurrent(concurrent) { assert(estimated_thread_count > 0, "estimated thread count must be positive"); - update_iteration_state(true); + update_iteration_state(1); // Get the block count *after* iteration state updated, so concurrent // empty block deletion is suppressed and can't reduce the count. But // ensure the count we use was written after the block with that count @@ -885,14 +885,13 @@ OopStorage::BasicParState::BasicParState(const OopStorage* storage, OopStorage::BasicParState::~BasicParState() { _storage->relinquish_block_array(_active_array); - update_iteration_state(false); + update_iteration_state(-1); } -void OopStorage::BasicParState::update_iteration_state(bool value) { +void OopStorage::BasicParState::update_iteration_state(int value) { if (_concurrent) { MutexLockerEx ml(_storage->_active_mutex, Mutex::_no_safepoint_check_flag); - assert(_storage->_concurrent_iteration_active != value, "precondition"); - _storage->_concurrent_iteration_active = value; + _storage->_concurrent_iteration_active += value; } } @@ -954,7 +953,7 @@ void OopStorage::print_on(outputStream* st) const { st->print("%s: " SIZE_FORMAT " entries in " SIZE_FORMAT " blocks (%.F%%), " SIZE_FORMAT " bytes", name(), allocations, blocks, alloc_percentage, total_memory_usage()); - if (_concurrent_iteration_active) { + if (_concurrent_iteration_active > 0) { st->print(", concurrent iteration active"); } } diff --git a/src/hotspot/share/gc/shared/oopStorage.hpp b/src/hotspot/share/gc/shared/oopStorage.hpp index 6721618..3d76f86 100644 --- a/src/hotspot/share/gc/shared/oopStorage.hpp +++ b/src/hotspot/share/gc/shared/oopStorage.hpp @@ -220,7 +220,7 @@ private: mutable SingleWriterSynchronizer _protect_active; // mutable because this gets set even for const iteration. - mutable bool _concurrent_iteration_active; + mutable int _concurrent_iteration_active; Block* find_block_or_null(const oop* ptr) const; void delete_empty_block(const Block& block); diff --git a/src/hotspot/share/gc/shared/oopStorageParState.hpp b/src/hotspot/share/gc/shared/oopStorageParState.hpp index bbeffde..e4a1e86 100644 --- a/src/hotspot/share/gc/shared/oopStorageParState.hpp +++ b/src/hotspot/share/gc/shared/oopStorageParState.hpp @@ -31,22 +31,16 @@ ////////////////////////////////////////////////////////////////////////////// // Support for parallel and optionally concurrent state iteration. // -// Parallel iteration is for the exclusive use of the GC. Other iteration -// clients must use serial iteration. -// // Concurrent Iteration // // Iteration involves the _active_array (an ActiveArray), which contains all // of the blocks owned by a storage object. // -// At most one concurrent ParState can exist at a time for a given storage -// object. -// -// A concurrent ParState sets the associated storage's -// _concurrent_iteration_active flag true when the state is constructed, and -// sets it false when the state is destroyed. These assignments are made with +// A concurrent ParState increments the associated storage's +// _concurrent_iteration_active count when the state is constructed, and +// decrements it when the state is destroyed. These assignments are made with // _active_mutex locked. Meanwhile, empty block deletion is not done while -// _concurrent_iteration_active is true. The flag check and the dependent +// _concurrent_iteration_active is non-zero. The counter check and the dependent // removal of a block from the _active_array is performed with _active_mutex // locked. This prevents concurrent iteration and empty block deletion from // interfering with with each other. @@ -83,8 +77,8 @@ // scheduling both operations to run at the same time. // // ParState -// concurrent must be true if iteration is concurrent with the -// mutator, false if iteration is at a safepoint. +// concurrent must be true if iteration may be concurrent with the +// mutators. // // is_const must be true if the iteration is over a constant storage // object, false if the iteration may modify the storage object. @@ -92,8 +86,7 @@ // ParState([const] OopStorage* storage) // Construct an object for managing an iteration over storage. For a // concurrent ParState, empty block deletion for the associated storage -// is inhibited for the life of the ParState. There can be no more -// than one live concurrent ParState at a time for a given storage object. +// is inhibited for the life of the ParState. // // template void iterate(F f) // Repeatedly claims a block from the associated storage that has @@ -152,7 +145,7 @@ class OopStorage::BasicParState { struct IterationData; - void update_iteration_state(bool value); + void update_iteration_state(int value); bool claim_next_segment(IterationData* data); bool finish_iteration(const IterationData* data) const;