src/share/vm/gc_implementation/g1/ptrQueue.cpp

Sat, 06 Oct 2012 01:17:44 -0700

author
johnc
date
Sat, 06 Oct 2012 01:17:44 -0700
changeset 4173
8a5ea0a9ccc4
parent 3900
d2a62e0f25eb
child 4153
b9a9ed0f8eeb
permissions
-rw-r--r--

7127708: G1: change task num types from int to uint in concurrent mark
Summary: Change the type of various task num fields, parameters etc to unsigned and rename them to be more consistent with the other collectors. Code changes were also reviewed by Vitaly Davidovich.
Reviewed-by: johnc
Contributed-by: Kaushik Srenevasan <kaushik@twitter.com>

     1 /*
     2  * Copyright (c) 2001, 2011, 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  */
    25 #include "precompiled.hpp"
    26 #include "gc_implementation/g1/ptrQueue.hpp"
    27 #include "memory/allocation.hpp"
    28 #include "memory/allocation.inline.hpp"
    29 #include "runtime/mutex.hpp"
    30 #include "runtime/mutexLocker.hpp"
    31 #ifdef TARGET_OS_FAMILY_linux
    32 # include "thread_linux.inline.hpp"
    33 #endif
    34 #ifdef TARGET_OS_FAMILY_solaris
    35 # include "thread_solaris.inline.hpp"
    36 #endif
    37 #ifdef TARGET_OS_FAMILY_windows
    38 # include "thread_windows.inline.hpp"
    39 #endif
    40 #ifdef TARGET_OS_FAMILY_bsd
    41 # include "thread_bsd.inline.hpp"
    42 #endif
    44 PtrQueue::PtrQueue(PtrQueueSet* qset, bool perm, bool active) :
    45   _qset(qset), _buf(NULL), _index(0), _active(active),
    46   _perm(perm), _lock(NULL)
    47 {}
    49 void PtrQueue::flush() {
    50   if (!_perm && _buf != NULL) {
    51     if (_index == _sz) {
    52       // No work to do.
    53       qset()->deallocate_buffer(_buf);
    54     } else {
    55       // We must NULL out the unused entries, then enqueue.
    56       for (size_t i = 0; i < _index; i += oopSize) {
    57         _buf[byte_index_to_index((int)i)] = NULL;
    58       }
    59       qset()->enqueue_complete_buffer(_buf);
    60     }
    61     _buf = NULL;
    62     _index = 0;
    63   }
    64 }
    67 static int byte_index_to_index(int ind) {
    68   assert((ind % oopSize) == 0, "Invariant.");
    69   return ind / oopSize;
    70 }
    72 static int index_to_byte_index(int byte_ind) {
    73   return byte_ind * oopSize;
    74 }
    76 void PtrQueue::enqueue_known_active(void* ptr) {
    77   assert(0 <= _index && _index <= _sz, "Invariant.");
    78   assert(_index == 0 || _buf != NULL, "invariant");
    80   while (_index == 0) {
    81     handle_zero_index();
    82   }
    84   assert(_index > 0, "postcondition");
    85   _index -= oopSize;
    86   _buf[byte_index_to_index((int)_index)] = ptr;
    87   assert(0 <= _index && _index <= _sz, "Invariant.");
    88 }
    90 void PtrQueue::locking_enqueue_completed_buffer(void** buf) {
    91   assert(_lock->owned_by_self(), "Required.");
    93   // We have to unlock _lock (which may be Shared_DirtyCardQ_lock) before
    94   // we acquire DirtyCardQ_CBL_mon inside enqeue_complete_buffer as they
    95   // have the same rank and we may get the "possible deadlock" message
    96   _lock->unlock();
    98   qset()->enqueue_complete_buffer(buf);
    99   // We must relock only because the caller will unlock, for the normal
   100   // case.
   101   _lock->lock_without_safepoint_check();
   102 }
   105 PtrQueueSet::PtrQueueSet(bool notify_when_complete) :
   106   _max_completed_queue(0),
   107   _cbl_mon(NULL), _fl_lock(NULL),
   108   _notify_when_complete(notify_when_complete),
   109   _sz(0),
   110   _completed_buffers_head(NULL),
   111   _completed_buffers_tail(NULL),
   112   _n_completed_buffers(0),
   113   _process_completed_threshold(0), _process_completed(false),
   114   _buf_free_list(NULL), _buf_free_list_sz(0)
   115 {
   116   _fl_owner = this;
   117 }
   119 void** PtrQueueSet::allocate_buffer() {
   120   assert(_sz > 0, "Didn't set a buffer size.");
   121   MutexLockerEx x(_fl_owner->_fl_lock, Mutex::_no_safepoint_check_flag);
   122   if (_fl_owner->_buf_free_list != NULL) {
   123     void** res = BufferNode::make_buffer_from_node(_fl_owner->_buf_free_list);
   124     _fl_owner->_buf_free_list = _fl_owner->_buf_free_list->next();
   125     _fl_owner->_buf_free_list_sz--;
   126     return res;
   127   } else {
   128     // Allocate space for the BufferNode in front of the buffer.
   129     char *b =  NEW_C_HEAP_ARRAY(char, _sz + BufferNode::aligned_size(), mtGC);
   130     return BufferNode::make_buffer_from_block(b);
   131   }
   132 }
   134 void PtrQueueSet::deallocate_buffer(void** buf) {
   135   assert(_sz > 0, "Didn't set a buffer size.");
   136   MutexLockerEx x(_fl_owner->_fl_lock, Mutex::_no_safepoint_check_flag);
   137   BufferNode *node = BufferNode::make_node_from_buffer(buf);
   138   node->set_next(_fl_owner->_buf_free_list);
   139   _fl_owner->_buf_free_list = node;
   140   _fl_owner->_buf_free_list_sz++;
   141 }
   143 void PtrQueueSet::reduce_free_list() {
   144   assert(_fl_owner == this, "Free list reduction is allowed only for the owner");
   145   // For now we'll adopt the strategy of deleting half.
   146   MutexLockerEx x(_fl_lock, Mutex::_no_safepoint_check_flag);
   147   size_t n = _buf_free_list_sz / 2;
   148   while (n > 0) {
   149     assert(_buf_free_list != NULL, "_buf_free_list_sz must be wrong.");
   150     void* b = BufferNode::make_block_from_node(_buf_free_list);
   151     _buf_free_list = _buf_free_list->next();
   152     FREE_C_HEAP_ARRAY(char, b, mtGC);
   153     _buf_free_list_sz --;
   154     n--;
   155   }
   156 }
   158 void PtrQueue::handle_zero_index() {
   159   assert(_index == 0, "Precondition.");
   161   // This thread records the full buffer and allocates a new one (while
   162   // holding the lock if there is one).
   163   if (_buf != NULL) {
   164     if (!should_enqueue_buffer()) {
   165       assert(_index > 0, "the buffer can only be re-used if it's not full");
   166       return;
   167     }
   169     if (_lock) {
   170       assert(_lock->owned_by_self(), "Required.");
   172       // The current PtrQ may be the shared dirty card queue and
   173       // may be being manipulated by more than one worker thread
   174       // during a pause. Since the enqueuing of the completed
   175       // buffer unlocks the Shared_DirtyCardQ_lock more than one
   176       // worker thread can 'race' on reading the shared queue attributes
   177       // (_buf and _index) and multiple threads can call into this
   178       // routine for the same buffer. This will cause the completed
   179       // buffer to be added to the CBL multiple times.
   181       // We "claim" the current buffer by caching value of _buf in
   182       // a local and clearing the field while holding _lock. When
   183       // _lock is released (while enqueueing the completed buffer)
   184       // the thread that acquires _lock will skip this code,
   185       // preventing the subsequent the multiple enqueue, and
   186       // install a newly allocated buffer below.
   188       void** buf = _buf;   // local pointer to completed buffer
   189       _buf = NULL;         // clear shared _buf field
   191       locking_enqueue_completed_buffer(buf);  // enqueue completed buffer
   193       // While the current thread was enqueuing the buffer another thread
   194       // may have a allocated a new buffer and inserted it into this pointer
   195       // queue. If that happens then we just return so that the current
   196       // thread doesn't overwrite the buffer allocated by the other thread
   197       // and potentially losing some dirtied cards.
   199       if (_buf != NULL) return;
   200     } else {
   201       if (qset()->process_or_enqueue_complete_buffer(_buf)) {
   202         // Recycle the buffer. No allocation.
   203         _sz = qset()->buffer_size();
   204         _index = _sz;
   205         return;
   206       }
   207     }
   208   }
   209   // Reallocate the buffer
   210   _buf = qset()->allocate_buffer();
   211   _sz = qset()->buffer_size();
   212   _index = _sz;
   213   assert(0 <= _index && _index <= _sz, "Invariant.");
   214 }
   216 bool PtrQueueSet::process_or_enqueue_complete_buffer(void** buf) {
   217   if (Thread::current()->is_Java_thread()) {
   218     // We don't lock. It is fine to be epsilon-precise here.
   219     if (_max_completed_queue == 0 || _max_completed_queue > 0 &&
   220         _n_completed_buffers >= _max_completed_queue + _completed_queue_padding) {
   221       bool b = mut_process_buffer(buf);
   222       if (b) {
   223         // True here means that the buffer hasn't been deallocated and the caller may reuse it.
   224         return true;
   225       }
   226     }
   227   }
   228   // The buffer will be enqueued. The caller will have to get a new one.
   229   enqueue_complete_buffer(buf);
   230   return false;
   231 }
   233 void PtrQueueSet::enqueue_complete_buffer(void** buf, size_t index) {
   234   MutexLockerEx x(_cbl_mon, Mutex::_no_safepoint_check_flag);
   235   BufferNode* cbn = BufferNode::new_from_buffer(buf);
   236   cbn->set_index(index);
   237   if (_completed_buffers_tail == NULL) {
   238     assert(_completed_buffers_head == NULL, "Well-formedness");
   239     _completed_buffers_head = cbn;
   240     _completed_buffers_tail = cbn;
   241   } else {
   242     _completed_buffers_tail->set_next(cbn);
   243     _completed_buffers_tail = cbn;
   244   }
   245   _n_completed_buffers++;
   247   if (!_process_completed && _process_completed_threshold >= 0 &&
   248       _n_completed_buffers >= _process_completed_threshold) {
   249     _process_completed = true;
   250     if (_notify_when_complete)
   251       _cbl_mon->notify();
   252   }
   253   debug_only(assert_completed_buffer_list_len_correct_locked());
   254 }
   256 int PtrQueueSet::completed_buffers_list_length() {
   257   int n = 0;
   258   BufferNode* cbn = _completed_buffers_head;
   259   while (cbn != NULL) {
   260     n++;
   261     cbn = cbn->next();
   262   }
   263   return n;
   264 }
   266 void PtrQueueSet::assert_completed_buffer_list_len_correct() {
   267   MutexLockerEx x(_cbl_mon, Mutex::_no_safepoint_check_flag);
   268   assert_completed_buffer_list_len_correct_locked();
   269 }
   271 void PtrQueueSet::assert_completed_buffer_list_len_correct_locked() {
   272   guarantee(completed_buffers_list_length() ==  _n_completed_buffers,
   273             "Completed buffer length is wrong.");
   274 }
   276 void PtrQueueSet::set_buffer_size(size_t sz) {
   277   assert(_sz == 0 && sz > 0, "Should be called only once.");
   278   _sz = sz * oopSize;
   279 }
   281 // Merge lists of buffers. Notify the processing threads.
   282 // The source queue is emptied as a result. The queues
   283 // must share the monitor.
   284 void PtrQueueSet::merge_bufferlists(PtrQueueSet *src) {
   285   assert(_cbl_mon == src->_cbl_mon, "Should share the same lock");
   286   MutexLockerEx x(_cbl_mon, Mutex::_no_safepoint_check_flag);
   287   if (_completed_buffers_tail == NULL) {
   288     assert(_completed_buffers_head == NULL, "Well-formedness");
   289     _completed_buffers_head = src->_completed_buffers_head;
   290     _completed_buffers_tail = src->_completed_buffers_tail;
   291   } else {
   292     assert(_completed_buffers_head != NULL, "Well formedness");
   293     if (src->_completed_buffers_head != NULL) {
   294       _completed_buffers_tail->set_next(src->_completed_buffers_head);
   295       _completed_buffers_tail = src->_completed_buffers_tail;
   296     }
   297   }
   298   _n_completed_buffers += src->_n_completed_buffers;
   300   src->_n_completed_buffers = 0;
   301   src->_completed_buffers_head = NULL;
   302   src->_completed_buffers_tail = NULL;
   304   assert(_completed_buffers_head == NULL && _completed_buffers_tail == NULL ||
   305          _completed_buffers_head != NULL && _completed_buffers_tail != NULL,
   306          "Sanity");
   307 }
   309 void PtrQueueSet::notify_if_necessary() {
   310   MutexLockerEx x(_cbl_mon, Mutex::_no_safepoint_check_flag);
   311   if (_n_completed_buffers >= _process_completed_threshold || _max_completed_queue == 0) {
   312     _process_completed = true;
   313     if (_notify_when_complete)
   314       _cbl_mon->notify();
   315   }
   316 }

mercurial