8211718: Supporting multiple concurrent OopStorage iterators

Reviewed-by: pliden, kbarrett
This commit is contained in:
Erik Österlund 2018-10-08 14:48:12 +02:00
parent 90d6bbd01a
commit b658954d7e
3 changed files with 18 additions and 25 deletions

View File

@ -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_count(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_count > 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_count > 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_concurrent_iteration_count(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,14 @@ OopStorage::BasicParState::BasicParState(const OopStorage* storage,
OopStorage::BasicParState::~BasicParState() {
_storage->relinquish_block_array(_active_array);
update_iteration_state(false);
update_concurrent_iteration_count(-1);
}
void OopStorage::BasicParState::update_iteration_state(bool value) {
void OopStorage::BasicParState::update_concurrent_iteration_count(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_count += value;
assert(_storage->_concurrent_iteration_count >= 0, "invariant");
}
}
@ -954,7 +954,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_count > 0) {
st->print(", concurrent iteration active");
}
}

View File

@ -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_count;
Block* find_block_or_null(const oop* ptr) const;
void delete_empty_block(const Block& block);

View File

@ -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_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_count 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, is_const>
// 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<typename F> 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_concurrent_iteration_count(int value);
bool claim_next_segment(IterationData* data);
bool finish_iteration(const IterationData* data) const;