diff -r d3a33953b936 -r e64383344f14 src/hotspot/share/gc/g1/g1DirtyCardQueue.cpp --- a/src/hotspot/share/gc/g1/g1DirtyCardQueue.cpp Wed Jun 26 09:06:32 2019 -0400 +++ b/src/hotspot/share/gc/g1/g1DirtyCardQueue.cpp Wed Jun 26 13:18:38 2019 -0400 @@ -78,7 +78,14 @@ } G1DirtyCardQueueSet::G1DirtyCardQueueSet(bool notify_when_complete) : - PtrQueueSet(notify_when_complete), + PtrQueueSet(), + _cbl_mon(NULL), + _completed_buffers_head(NULL), + _completed_buffers_tail(NULL), + _n_completed_buffers(0), + _process_completed_buffers_threshold(ProcessCompletedBuffersThresholdNever), + _process_completed_buffers(false), + _notify_when_complete(notify_when_complete), _max_completed_buffers(MaxCompletedBuffersUnlimited), _completed_buffers_padding(0), _free_ids(NULL), @@ -90,6 +97,7 @@ } G1DirtyCardQueueSet::~G1DirtyCardQueueSet() { + abandon_completed_buffers(); delete _free_ids; } @@ -101,7 +109,9 @@ void G1DirtyCardQueueSet::initialize(Monitor* cbl_mon, BufferNode::Allocator* allocator, bool init_free_ids) { - PtrQueueSet::initialize(cbl_mon, allocator); + PtrQueueSet::initialize(allocator); + assert(_cbl_mon == NULL, "Init order issue?"); + _cbl_mon = cbl_mon; if (init_free_ids) { _free_ids = new G1FreeIdSet(0, num_par_ids()); } @@ -111,6 +121,123 @@ G1ThreadLocalData::dirty_card_queue(t).handle_zero_index(); } +void G1DirtyCardQueueSet::enqueue_completed_buffer(BufferNode* cbn) { + MutexLocker x(_cbl_mon, Mutex::_no_safepoint_check_flag); + cbn->set_next(NULL); + if (_completed_buffers_tail == NULL) { + assert(_completed_buffers_head == NULL, "Well-formedness"); + _completed_buffers_head = cbn; + _completed_buffers_tail = cbn; + } else { + _completed_buffers_tail->set_next(cbn); + _completed_buffers_tail = cbn; + } + _n_completed_buffers++; + + if (!process_completed_buffers() && + (_n_completed_buffers > process_completed_buffers_threshold())) { + set_process_completed_buffers(true); + if (_notify_when_complete) { + _cbl_mon->notify_all(); + } + } + assert_completed_buffers_list_len_correct_locked(); +} + +BufferNode* G1DirtyCardQueueSet::get_completed_buffer(size_t stop_at) { + MutexLocker x(_cbl_mon, Mutex::_no_safepoint_check_flag); + + if (_n_completed_buffers <= stop_at) { + return NULL; + } + + assert(_n_completed_buffers > 0, "invariant"); + assert(_completed_buffers_head != NULL, "invariant"); + assert(_completed_buffers_tail != NULL, "invariant"); + + BufferNode* bn = _completed_buffers_head; + _n_completed_buffers--; + _completed_buffers_head = bn->next(); + if (_completed_buffers_head == NULL) { + assert(_n_completed_buffers == 0, "invariant"); + _completed_buffers_tail = NULL; + set_process_completed_buffers(false); + } + assert_completed_buffers_list_len_correct_locked(); + bn->set_next(NULL); + return bn; +} + +void G1DirtyCardQueueSet::abandon_completed_buffers() { + BufferNode* buffers_to_delete = NULL; + { + MutexLocker x(_cbl_mon, Mutex::_no_safepoint_check_flag); + buffers_to_delete = _completed_buffers_head; + _completed_buffers_head = NULL; + _completed_buffers_tail = NULL; + _n_completed_buffers = 0; + set_process_completed_buffers(false); + } + while (buffers_to_delete != NULL) { + BufferNode* bn = buffers_to_delete; + buffers_to_delete = bn->next(); + bn->set_next(NULL); + deallocate_buffer(bn); + } +} + +void G1DirtyCardQueueSet::notify_if_necessary() { + MutexLocker x(_cbl_mon, Mutex::_no_safepoint_check_flag); + if (_n_completed_buffers > process_completed_buffers_threshold()) { + set_process_completed_buffers(true); + if (_notify_when_complete) + _cbl_mon->notify(); + } +} + +#ifdef ASSERT +void G1DirtyCardQueueSet::assert_completed_buffers_list_len_correct_locked() { + assert_lock_strong(_cbl_mon); + size_t n = 0; + for (BufferNode* bn = _completed_buffers_head; bn != NULL; bn = bn->next()) { + ++n; + } + assert(n == _n_completed_buffers, + "Completed buffer length is wrong: counted: " SIZE_FORMAT + ", expected: " SIZE_FORMAT, n, _n_completed_buffers); +} +#endif // ASSERT + +// Merge lists of buffers. Notify the processing threads. +// The source queue is emptied as a result. The queues +// must share the monitor. +void G1DirtyCardQueueSet::merge_bufferlists(G1DirtyCardQueueSet *src) { + assert(_cbl_mon == src->_cbl_mon, "Should share the same lock"); + MutexLocker x(_cbl_mon, Mutex::_no_safepoint_check_flag); + if (_completed_buffers_tail == NULL) { + assert(_completed_buffers_head == NULL, "Well-formedness"); + _completed_buffers_head = src->_completed_buffers_head; + _completed_buffers_tail = src->_completed_buffers_tail; + } else { + assert(_completed_buffers_head != NULL, "Well formedness"); + if (src->_completed_buffers_head != NULL) { + _completed_buffers_tail->set_next(src->_completed_buffers_head); + _completed_buffers_tail = src->_completed_buffers_tail; + } + } + _n_completed_buffers += src->_n_completed_buffers; + + src->_n_completed_buffers = 0; + src->_completed_buffers_head = NULL; + src->_completed_buffers_tail = NULL; + src->set_process_completed_buffers(false); + + assert(_completed_buffers_head == NULL && _completed_buffers_tail == NULL || + _completed_buffers_head != NULL && _completed_buffers_tail != NULL, + "Sanity"); + assert_completed_buffers_list_len_correct_locked(); +} + bool G1DirtyCardQueueSet::apply_closure_to_buffer(G1CardTableEntryClosure* cl, BufferNode* node, bool consume,