src/share/vm/gc_implementation/parallelScavenge/gcTaskManager.cpp

changeset 435
a61af66fc99e
child 1907
c18cbe5936b8
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/src/share/vm/gc_implementation/parallelScavenge/gcTaskManager.cpp	Sat Dec 01 00:00:00 2007 +0000
     1.3 @@ -0,0 +1,919 @@
     1.4 +/*
     1.5 + * Copyright 2002-2007 Sun Microsystems, Inc.  All Rights Reserved.
     1.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     1.7 + *
     1.8 + * This code is free software; you can redistribute it and/or modify it
     1.9 + * under the terms of the GNU General Public License version 2 only, as
    1.10 + * published by the Free Software Foundation.
    1.11 + *
    1.12 + * This code is distributed in the hope that it will be useful, but WITHOUT
    1.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    1.14 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    1.15 + * version 2 for more details (a copy is included in the LICENSE file that
    1.16 + * accompanied this code).
    1.17 + *
    1.18 + * You should have received a copy of the GNU General Public License version
    1.19 + * 2 along with this work; if not, write to the Free Software Foundation,
    1.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    1.21 + *
    1.22 + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
    1.23 + * CA 95054 USA or visit www.sun.com if you need additional information or
    1.24 + * have any questions.
    1.25 + *
    1.26 + */
    1.27 +
    1.28 +#include "incls/_precompiled.incl"
    1.29 +#include "incls/_gcTaskManager.cpp.incl"
    1.30 +
    1.31 +//
    1.32 +// GCTask
    1.33 +//
    1.34 +
    1.35 +const char* GCTask::Kind::to_string(kind value) {
    1.36 +  const char* result = "unknown GCTask kind";
    1.37 +  switch (value) {
    1.38 +  default:
    1.39 +    result = "unknown GCTask kind";
    1.40 +    break;
    1.41 +  case unknown_task:
    1.42 +    result = "unknown task";
    1.43 +    break;
    1.44 +  case ordinary_task:
    1.45 +    result = "ordinary task";
    1.46 +    break;
    1.47 +  case barrier_task:
    1.48 +    result = "barrier task";
    1.49 +    break;
    1.50 +  case noop_task:
    1.51 +    result = "noop task";
    1.52 +    break;
    1.53 +  }
    1.54 +  return result;
    1.55 +};
    1.56 +
    1.57 +GCTask::GCTask() :
    1.58 +  _kind(Kind::ordinary_task),
    1.59 +  _affinity(GCTaskManager::sentinel_worker()){
    1.60 +  initialize();
    1.61 +}
    1.62 +
    1.63 +GCTask::GCTask(Kind::kind kind) :
    1.64 +  _kind(kind),
    1.65 +  _affinity(GCTaskManager::sentinel_worker()) {
    1.66 +  initialize();
    1.67 +}
    1.68 +
    1.69 +GCTask::GCTask(uint affinity) :
    1.70 +  _kind(Kind::ordinary_task),
    1.71 +  _affinity(affinity) {
    1.72 +  initialize();
    1.73 +}
    1.74 +
    1.75 +GCTask::GCTask(Kind::kind kind, uint affinity) :
    1.76 +  _kind(kind),
    1.77 +  _affinity(affinity) {
    1.78 +  initialize();
    1.79 +}
    1.80 +
    1.81 +void GCTask::initialize() {
    1.82 +  _older = NULL;
    1.83 +  _newer = NULL;
    1.84 +}
    1.85 +
    1.86 +void GCTask::destruct() {
    1.87 +  assert(older() == NULL, "shouldn't have an older task");
    1.88 +  assert(newer() == NULL, "shouldn't have a newer task");
    1.89 +  // Nothing to do.
    1.90 +}
    1.91 +
    1.92 +NOT_PRODUCT(
    1.93 +void GCTask::print(const char* message) const {
    1.94 +  tty->print(INTPTR_FORMAT " <- " INTPTR_FORMAT "(%u) -> " INTPTR_FORMAT,
    1.95 +             newer(), this, affinity(), older());
    1.96 +}
    1.97 +)
    1.98 +
    1.99 +//
   1.100 +// GCTaskQueue
   1.101 +//
   1.102 +
   1.103 +GCTaskQueue* GCTaskQueue::create() {
   1.104 +  GCTaskQueue* result = new GCTaskQueue(false);
   1.105 +  if (TraceGCTaskQueue) {
   1.106 +    tty->print_cr("GCTaskQueue::create()"
   1.107 +                  " returns " INTPTR_FORMAT, result);
   1.108 +  }
   1.109 +  return result;
   1.110 +}
   1.111 +
   1.112 +GCTaskQueue* GCTaskQueue::create_on_c_heap() {
   1.113 +  GCTaskQueue* result = new(ResourceObj::C_HEAP) GCTaskQueue(true);
   1.114 +  if (TraceGCTaskQueue) {
   1.115 +    tty->print_cr("GCTaskQueue::create_on_c_heap()"
   1.116 +                  " returns " INTPTR_FORMAT,
   1.117 +                  result);
   1.118 +  }
   1.119 +  return result;
   1.120 +}
   1.121 +
   1.122 +GCTaskQueue::GCTaskQueue(bool on_c_heap) :
   1.123 +  _is_c_heap_obj(on_c_heap) {
   1.124 +  initialize();
   1.125 +  if (TraceGCTaskQueue) {
   1.126 +    tty->print_cr("[" INTPTR_FORMAT "]"
   1.127 +                  " GCTaskQueue::GCTaskQueue() constructor",
   1.128 +                  this);
   1.129 +  }
   1.130 +}
   1.131 +
   1.132 +void GCTaskQueue::destruct() {
   1.133 +  // Nothing to do.
   1.134 +}
   1.135 +
   1.136 +void GCTaskQueue::destroy(GCTaskQueue* that) {
   1.137 +  if (TraceGCTaskQueue) {
   1.138 +    tty->print_cr("[" INTPTR_FORMAT "]"
   1.139 +                  " GCTaskQueue::destroy()"
   1.140 +                  "  is_c_heap_obj:  %s",
   1.141 +                  that,
   1.142 +                  that->is_c_heap_obj() ? "true" : "false");
   1.143 +  }
   1.144 +  // That instance may have been allocated as a CHeapObj,
   1.145 +  // in which case we have to free it explicitly.
   1.146 +  if (that != NULL) {
   1.147 +    that->destruct();
   1.148 +    assert(that->is_empty(), "should be empty");
   1.149 +    if (that->is_c_heap_obj()) {
   1.150 +      FreeHeap(that);
   1.151 +    }
   1.152 +  }
   1.153 +}
   1.154 +
   1.155 +void GCTaskQueue::initialize() {
   1.156 +  set_insert_end(NULL);
   1.157 +  set_remove_end(NULL);
   1.158 +  set_length(0);
   1.159 +}
   1.160 +
   1.161 +// Enqueue one task.
   1.162 +void GCTaskQueue::enqueue(GCTask* task) {
   1.163 +  if (TraceGCTaskQueue) {
   1.164 +    tty->print_cr("[" INTPTR_FORMAT "]"
   1.165 +                  " GCTaskQueue::enqueue(task: "
   1.166 +                  INTPTR_FORMAT ")",
   1.167 +                  this, task);
   1.168 +    print("before:");
   1.169 +  }
   1.170 +  assert(task != NULL, "shouldn't have null task");
   1.171 +  assert(task->older() == NULL, "shouldn't be on queue");
   1.172 +  assert(task->newer() == NULL, "shouldn't be on queue");
   1.173 +  task->set_newer(NULL);
   1.174 +  task->set_older(insert_end());
   1.175 +  if (is_empty()) {
   1.176 +    set_remove_end(task);
   1.177 +  } else {
   1.178 +    insert_end()->set_newer(task);
   1.179 +  }
   1.180 +  set_insert_end(task);
   1.181 +  increment_length();
   1.182 +  if (TraceGCTaskQueue) {
   1.183 +    print("after:");
   1.184 +  }
   1.185 +}
   1.186 +
   1.187 +// Enqueue a whole list of tasks.  Empties the argument list.
   1.188 +void GCTaskQueue::enqueue(GCTaskQueue* list) {
   1.189 +  if (TraceGCTaskQueue) {
   1.190 +    tty->print_cr("[" INTPTR_FORMAT "]"
   1.191 +                  " GCTaskQueue::enqueue(list: "
   1.192 +                  INTPTR_FORMAT ")",
   1.193 +                  this);
   1.194 +    print("before:");
   1.195 +    list->print("list:");
   1.196 +  }
   1.197 +  if (list->is_empty()) {
   1.198 +    // Enqueuing the empty list: nothing to do.
   1.199 +    return;
   1.200 +  }
   1.201 +  uint list_length = list->length();
   1.202 +  if (is_empty()) {
   1.203 +    // Enqueuing to empty list: just acquire elements.
   1.204 +    set_insert_end(list->insert_end());
   1.205 +    set_remove_end(list->remove_end());
   1.206 +    set_length(list_length);
   1.207 +  } else {
   1.208 +    // Prepend argument list to our queue.
   1.209 +    list->remove_end()->set_older(insert_end());
   1.210 +    insert_end()->set_newer(list->remove_end());
   1.211 +    set_insert_end(list->insert_end());
   1.212 +    // empty the argument list.
   1.213 +  }
   1.214 +  set_length(length() + list_length);
   1.215 +  list->initialize();
   1.216 +  if (TraceGCTaskQueue) {
   1.217 +    print("after:");
   1.218 +    list->print("list:");
   1.219 +  }
   1.220 +}
   1.221 +
   1.222 +// Dequeue one task.
   1.223 +GCTask* GCTaskQueue::dequeue() {
   1.224 +  if (TraceGCTaskQueue) {
   1.225 +    tty->print_cr("[" INTPTR_FORMAT "]"
   1.226 +                  " GCTaskQueue::dequeue()", this);
   1.227 +    print("before:");
   1.228 +  }
   1.229 +  assert(!is_empty(), "shouldn't dequeue from empty list");
   1.230 +  GCTask* result = remove();
   1.231 +  assert(result != NULL, "shouldn't have NULL task");
   1.232 +  if (TraceGCTaskQueue) {
   1.233 +    tty->print_cr("    return: " INTPTR_FORMAT, result);
   1.234 +    print("after:");
   1.235 +  }
   1.236 +  return result;
   1.237 +}
   1.238 +
   1.239 +// Dequeue one task, preferring one with affinity.
   1.240 +GCTask* GCTaskQueue::dequeue(uint affinity) {
   1.241 +  if (TraceGCTaskQueue) {
   1.242 +    tty->print_cr("[" INTPTR_FORMAT "]"
   1.243 +                  " GCTaskQueue::dequeue(%u)", this, affinity);
   1.244 +    print("before:");
   1.245 +  }
   1.246 +  assert(!is_empty(), "shouldn't dequeue from empty list");
   1.247 +  // Look down to the next barrier for a task with this affinity.
   1.248 +  GCTask* result = NULL;
   1.249 +  for (GCTask* element = remove_end();
   1.250 +       element != NULL;
   1.251 +       element = element->newer()) {
   1.252 +    if (element->is_barrier_task()) {
   1.253 +      // Don't consider barrier tasks, nor past them.
   1.254 +      result = NULL;
   1.255 +      break;
   1.256 +    }
   1.257 +    if (element->affinity() == affinity) {
   1.258 +      result = remove(element);
   1.259 +      break;
   1.260 +    }
   1.261 +  }
   1.262 +  // If we didn't find anything with affinity, just take the next task.
   1.263 +  if (result == NULL) {
   1.264 +    result = remove();
   1.265 +  }
   1.266 +  if (TraceGCTaskQueue) {
   1.267 +    tty->print_cr("    return: " INTPTR_FORMAT, result);
   1.268 +    print("after:");
   1.269 +  }
   1.270 +  return result;
   1.271 +}
   1.272 +
   1.273 +GCTask* GCTaskQueue::remove() {
   1.274 +  // Dequeue from remove end.
   1.275 +  GCTask* result = remove_end();
   1.276 +  assert(result != NULL, "shouldn't have null task");
   1.277 +  assert(result->older() == NULL, "not the remove_end");
   1.278 +  set_remove_end(result->newer());
   1.279 +  if (remove_end() == NULL) {
   1.280 +    assert(insert_end() == result, "not a singleton");
   1.281 +    set_insert_end(NULL);
   1.282 +  } else {
   1.283 +    remove_end()->set_older(NULL);
   1.284 +  }
   1.285 +  result->set_newer(NULL);
   1.286 +  decrement_length();
   1.287 +  assert(result->newer() == NULL, "shouldn't be on queue");
   1.288 +  assert(result->older() == NULL, "shouldn't be on queue");
   1.289 +  return result;
   1.290 +}
   1.291 +
   1.292 +GCTask* GCTaskQueue::remove(GCTask* task) {
   1.293 +  // This is slightly more work, and has slightly fewer asserts
   1.294 +  // than removing from the remove end.
   1.295 +  assert(task != NULL, "shouldn't have null task");
   1.296 +  GCTask* result = task;
   1.297 +  if (result->newer() != NULL) {
   1.298 +    result->newer()->set_older(result->older());
   1.299 +  } else {
   1.300 +    assert(insert_end() == result, "not youngest");
   1.301 +    set_insert_end(result->older());
   1.302 +  }
   1.303 +  if (result->older() != NULL) {
   1.304 +    result->older()->set_newer(result->newer());
   1.305 +  } else {
   1.306 +    assert(remove_end() == result, "not oldest");
   1.307 +    set_remove_end(result->newer());
   1.308 +  }
   1.309 +  result->set_newer(NULL);
   1.310 +  result->set_older(NULL);
   1.311 +  decrement_length();
   1.312 +  return result;
   1.313 +}
   1.314 +
   1.315 +NOT_PRODUCT(
   1.316 +void GCTaskQueue::print(const char* message) const {
   1.317 +  tty->print_cr("[" INTPTR_FORMAT "] GCTaskQueue:"
   1.318 +                "  insert_end: " INTPTR_FORMAT
   1.319 +                "  remove_end: " INTPTR_FORMAT
   1.320 +                "  %s",
   1.321 +                this, insert_end(), remove_end(), message);
   1.322 +  for (GCTask* element = insert_end();
   1.323 +       element != NULL;
   1.324 +       element = element->older()) {
   1.325 +    element->print("    ");
   1.326 +    tty->cr();
   1.327 +  }
   1.328 +}
   1.329 +)
   1.330 +
   1.331 +//
   1.332 +// SynchronizedGCTaskQueue
   1.333 +//
   1.334 +
   1.335 +SynchronizedGCTaskQueue::SynchronizedGCTaskQueue(GCTaskQueue* queue_arg,
   1.336 +                                                 Monitor *       lock_arg) :
   1.337 +  _unsynchronized_queue(queue_arg),
   1.338 +  _lock(lock_arg) {
   1.339 +  assert(unsynchronized_queue() != NULL, "null queue");
   1.340 +  assert(lock() != NULL, "null lock");
   1.341 +}
   1.342 +
   1.343 +SynchronizedGCTaskQueue::~SynchronizedGCTaskQueue() {
   1.344 +  // Nothing to do.
   1.345 +}
   1.346 +
   1.347 +//
   1.348 +// GCTaskManager
   1.349 +//
   1.350 +GCTaskManager::GCTaskManager(uint workers) :
   1.351 +  _workers(workers),
   1.352 +  _ndc(NULL) {
   1.353 +  initialize();
   1.354 +}
   1.355 +
   1.356 +GCTaskManager::GCTaskManager(uint workers, NotifyDoneClosure* ndc) :
   1.357 +  _workers(workers),
   1.358 +  _ndc(ndc) {
   1.359 +  initialize();
   1.360 +}
   1.361 +
   1.362 +void GCTaskManager::initialize() {
   1.363 +  if (TraceGCTaskManager) {
   1.364 +    tty->print_cr("GCTaskManager::initialize: workers: %u", workers());
   1.365 +  }
   1.366 +  assert(workers() != 0, "no workers");
   1.367 +  _monitor = new Monitor(Mutex::barrier,                // rank
   1.368 +                         "GCTaskManager monitor",       // name
   1.369 +                         Mutex::_allow_vm_block_flag);  // allow_vm_block
   1.370 +  // The queue for the GCTaskManager must be a CHeapObj.
   1.371 +  GCTaskQueue* unsynchronized_queue = GCTaskQueue::create_on_c_heap();
   1.372 +  _queue = SynchronizedGCTaskQueue::create(unsynchronized_queue, lock());
   1.373 +  _noop_task = NoopGCTask::create_on_c_heap();
   1.374 +  _resource_flag = NEW_C_HEAP_ARRAY(bool, workers());
   1.375 +  {
   1.376 +    // Set up worker threads.
   1.377 +    //     Distribute the workers among the available processors,
   1.378 +    //     unless we were told not to, or if the os doesn't want to.
   1.379 +    uint* processor_assignment = NEW_C_HEAP_ARRAY(uint, workers());
   1.380 +    if (!BindGCTaskThreadsToCPUs ||
   1.381 +        !os::distribute_processes(workers(), processor_assignment)) {
   1.382 +      for (uint a = 0; a < workers(); a += 1) {
   1.383 +        processor_assignment[a] = sentinel_worker();
   1.384 +      }
   1.385 +    }
   1.386 +    _thread = NEW_C_HEAP_ARRAY(GCTaskThread*, workers());
   1.387 +    for (uint t = 0; t < workers(); t += 1) {
   1.388 +      set_thread(t, GCTaskThread::create(this, t, processor_assignment[t]));
   1.389 +    }
   1.390 +    if (TraceGCTaskThread) {
   1.391 +      tty->print("GCTaskManager::initialize: distribution:");
   1.392 +      for (uint t = 0; t < workers(); t += 1) {
   1.393 +        tty->print("  %u", processor_assignment[t]);
   1.394 +      }
   1.395 +      tty->cr();
   1.396 +    }
   1.397 +    FREE_C_HEAP_ARRAY(uint, processor_assignment);
   1.398 +  }
   1.399 +  reset_busy_workers();
   1.400 +  set_unblocked();
   1.401 +  for (uint w = 0; w < workers(); w += 1) {
   1.402 +    set_resource_flag(w, false);
   1.403 +  }
   1.404 +  reset_delivered_tasks();
   1.405 +  reset_completed_tasks();
   1.406 +  reset_noop_tasks();
   1.407 +  reset_barriers();
   1.408 +  reset_emptied_queue();
   1.409 +  for (uint s = 0; s < workers(); s += 1) {
   1.410 +    thread(s)->start();
   1.411 +  }
   1.412 +}
   1.413 +
   1.414 +GCTaskManager::~GCTaskManager() {
   1.415 +  assert(busy_workers() == 0, "still have busy workers");
   1.416 +  assert(queue()->is_empty(), "still have queued work");
   1.417 +  NoopGCTask::destroy(_noop_task);
   1.418 +  _noop_task = NULL;
   1.419 +  if (_thread != NULL) {
   1.420 +    for (uint i = 0; i < workers(); i += 1) {
   1.421 +      GCTaskThread::destroy(thread(i));
   1.422 +      set_thread(i, NULL);
   1.423 +    }
   1.424 +    FREE_C_HEAP_ARRAY(GCTaskThread*, _thread);
   1.425 +    _thread = NULL;
   1.426 +  }
   1.427 +  if (_resource_flag != NULL) {
   1.428 +    FREE_C_HEAP_ARRAY(bool, _resource_flag);
   1.429 +    _resource_flag = NULL;
   1.430 +  }
   1.431 +  if (queue() != NULL) {
   1.432 +    GCTaskQueue* unsynchronized_queue = queue()->unsynchronized_queue();
   1.433 +    GCTaskQueue::destroy(unsynchronized_queue);
   1.434 +    SynchronizedGCTaskQueue::destroy(queue());
   1.435 +    _queue = NULL;
   1.436 +  }
   1.437 +  if (monitor() != NULL) {
   1.438 +    delete monitor();
   1.439 +    _monitor = NULL;
   1.440 +  }
   1.441 +}
   1.442 +
   1.443 +void GCTaskManager::print_task_time_stamps() {
   1.444 +  for(uint i=0; i<ParallelGCThreads; i++) {
   1.445 +    GCTaskThread* t = thread(i);
   1.446 +    t->print_task_time_stamps();
   1.447 +  }
   1.448 +}
   1.449 +
   1.450 +void GCTaskManager::print_threads_on(outputStream* st) {
   1.451 +  uint num_thr = workers();
   1.452 +  for (uint i = 0; i < num_thr; i++) {
   1.453 +    thread(i)->print_on(st);
   1.454 +    st->cr();
   1.455 +  }
   1.456 +}
   1.457 +
   1.458 +void GCTaskManager::threads_do(ThreadClosure* tc) {
   1.459 +  assert(tc != NULL, "Null ThreadClosure");
   1.460 +  uint num_thr = workers();
   1.461 +  for (uint i = 0; i < num_thr; i++) {
   1.462 +    tc->do_thread(thread(i));
   1.463 +  }
   1.464 +}
   1.465 +
   1.466 +GCTaskThread* GCTaskManager::thread(uint which) {
   1.467 +  assert(which < workers(), "index out of bounds");
   1.468 +  assert(_thread[which] != NULL, "shouldn't have null thread");
   1.469 +  return _thread[which];
   1.470 +}
   1.471 +
   1.472 +void GCTaskManager::set_thread(uint which, GCTaskThread* value) {
   1.473 +  assert(which < workers(), "index out of bounds");
   1.474 +  assert(value != NULL, "shouldn't have null thread");
   1.475 +  _thread[which] = value;
   1.476 +}
   1.477 +
   1.478 +void GCTaskManager::add_task(GCTask* task) {
   1.479 +  assert(task != NULL, "shouldn't have null task");
   1.480 +  MutexLockerEx ml(monitor(), Mutex::_no_safepoint_check_flag);
   1.481 +  if (TraceGCTaskManager) {
   1.482 +    tty->print_cr("GCTaskManager::add_task(" INTPTR_FORMAT " [%s])",
   1.483 +                  task, GCTask::Kind::to_string(task->kind()));
   1.484 +  }
   1.485 +  queue()->enqueue(task);
   1.486 +  // Notify with the lock held to avoid missed notifies.
   1.487 +  if (TraceGCTaskManager) {
   1.488 +    tty->print_cr("    GCTaskManager::add_task (%s)->notify_all",
   1.489 +                  monitor()->name());
   1.490 +  }
   1.491 +  (void) monitor()->notify_all();
   1.492 +  // Release monitor().
   1.493 +}
   1.494 +
   1.495 +void GCTaskManager::add_list(GCTaskQueue* list) {
   1.496 +  assert(list != NULL, "shouldn't have null task");
   1.497 +  MutexLockerEx ml(monitor(), Mutex::_no_safepoint_check_flag);
   1.498 +  if (TraceGCTaskManager) {
   1.499 +    tty->print_cr("GCTaskManager::add_list(%u)", list->length());
   1.500 +  }
   1.501 +  queue()->enqueue(list);
   1.502 +  // Notify with the lock held to avoid missed notifies.
   1.503 +  if (TraceGCTaskManager) {
   1.504 +    tty->print_cr("    GCTaskManager::add_list (%s)->notify_all",
   1.505 +                  monitor()->name());
   1.506 +  }
   1.507 +  (void) monitor()->notify_all();
   1.508 +  // Release monitor().
   1.509 +}
   1.510 +
   1.511 +GCTask* GCTaskManager::get_task(uint which) {
   1.512 +  GCTask* result = NULL;
   1.513 +  // Grab the queue lock.
   1.514 +  MutexLockerEx ml(monitor(), Mutex::_no_safepoint_check_flag);
   1.515 +  // Wait while the queue is block or
   1.516 +  // there is nothing to do, except maybe release resources.
   1.517 +  while (is_blocked() ||
   1.518 +         (queue()->is_empty() && !should_release_resources(which))) {
   1.519 +    if (TraceGCTaskManager) {
   1.520 +      tty->print_cr("GCTaskManager::get_task(%u)"
   1.521 +                    "  blocked: %s"
   1.522 +                    "  empty: %s"
   1.523 +                    "  release: %s",
   1.524 +                    which,
   1.525 +                    is_blocked() ? "true" : "false",
   1.526 +                    queue()->is_empty() ? "true" : "false",
   1.527 +                    should_release_resources(which) ? "true" : "false");
   1.528 +      tty->print_cr("    => (%s)->wait()",
   1.529 +                    monitor()->name());
   1.530 +    }
   1.531 +    monitor()->wait(Mutex::_no_safepoint_check_flag, 0);
   1.532 +  }
   1.533 +  // We've reacquired the queue lock here.
   1.534 +  // Figure out which condition caused us to exit the loop above.
   1.535 +  if (!queue()->is_empty()) {
   1.536 +    if (UseGCTaskAffinity) {
   1.537 +      result = queue()->dequeue(which);
   1.538 +    } else {
   1.539 +      result = queue()->dequeue();
   1.540 +    }
   1.541 +    if (result->is_barrier_task()) {
   1.542 +      assert(which != sentinel_worker(),
   1.543 +             "blocker shouldn't be bogus");
   1.544 +      set_blocking_worker(which);
   1.545 +    }
   1.546 +  } else {
   1.547 +    // The queue is empty, but we were woken up.
   1.548 +    // Just hand back a Noop task,
   1.549 +    // in case someone wanted us to release resources, or whatever.
   1.550 +    result = noop_task();
   1.551 +    increment_noop_tasks();
   1.552 +  }
   1.553 +  assert(result != NULL, "shouldn't have null task");
   1.554 +  if (TraceGCTaskManager) {
   1.555 +    tty->print_cr("GCTaskManager::get_task(%u) => " INTPTR_FORMAT " [%s]",
   1.556 +                  which, result, GCTask::Kind::to_string(result->kind()));
   1.557 +    tty->print_cr("     %s", result->name());
   1.558 +  }
   1.559 +  increment_busy_workers();
   1.560 +  increment_delivered_tasks();
   1.561 +  return result;
   1.562 +  // Release monitor().
   1.563 +}
   1.564 +
   1.565 +void GCTaskManager::note_completion(uint which) {
   1.566 +  MutexLockerEx ml(monitor(), Mutex::_no_safepoint_check_flag);
   1.567 +  if (TraceGCTaskManager) {
   1.568 +    tty->print_cr("GCTaskManager::note_completion(%u)", which);
   1.569 +  }
   1.570 +  // If we are blocked, check if the completing thread is the blocker.
   1.571 +  if (blocking_worker() == which) {
   1.572 +    assert(blocking_worker() != sentinel_worker(),
   1.573 +           "blocker shouldn't be bogus");
   1.574 +    increment_barriers();
   1.575 +    set_unblocked();
   1.576 +  }
   1.577 +  increment_completed_tasks();
   1.578 +  uint active = decrement_busy_workers();
   1.579 +  if ((active == 0) && (queue()->is_empty())) {
   1.580 +    increment_emptied_queue();
   1.581 +    if (TraceGCTaskManager) {
   1.582 +      tty->print_cr("    GCTaskManager::note_completion(%u) done", which);
   1.583 +    }
   1.584 +    // Notify client that we are done.
   1.585 +    NotifyDoneClosure* ndc = notify_done_closure();
   1.586 +    if (ndc != NULL) {
   1.587 +      ndc->notify(this);
   1.588 +    }
   1.589 +  }
   1.590 +  if (TraceGCTaskManager) {
   1.591 +    tty->print_cr("    GCTaskManager::note_completion(%u) (%s)->notify_all",
   1.592 +                  which, monitor()->name());
   1.593 +    tty->print_cr("  "
   1.594 +                  "  blocked: %s"
   1.595 +                  "  empty: %s"
   1.596 +                  "  release: %s",
   1.597 +                  is_blocked() ? "true" : "false",
   1.598 +                  queue()->is_empty() ? "true" : "false",
   1.599 +                  should_release_resources(which) ? "true" : "false");
   1.600 +    tty->print_cr("  "
   1.601 +                  "  delivered: %u"
   1.602 +                  "  completed: %u"
   1.603 +                  "  barriers: %u"
   1.604 +                  "  emptied: %u",
   1.605 +                  delivered_tasks(),
   1.606 +                  completed_tasks(),
   1.607 +                  barriers(),
   1.608 +                  emptied_queue());
   1.609 +  }
   1.610 +  // Tell everyone that a task has completed.
   1.611 +  (void) monitor()->notify_all();
   1.612 +  // Release monitor().
   1.613 +}
   1.614 +
   1.615 +uint GCTaskManager::increment_busy_workers() {
   1.616 +  assert(queue()->own_lock(), "don't own the lock");
   1.617 +  _busy_workers += 1;
   1.618 +  return _busy_workers;
   1.619 +}
   1.620 +
   1.621 +uint GCTaskManager::decrement_busy_workers() {
   1.622 +  assert(queue()->own_lock(), "don't own the lock");
   1.623 +  _busy_workers -= 1;
   1.624 +  return _busy_workers;
   1.625 +}
   1.626 +
   1.627 +void GCTaskManager::release_all_resources() {
   1.628 +  // If you want this to be done atomically, do it in a BarrierGCTask.
   1.629 +  for (uint i = 0; i < workers(); i += 1) {
   1.630 +    set_resource_flag(i, true);
   1.631 +  }
   1.632 +}
   1.633 +
   1.634 +bool GCTaskManager::should_release_resources(uint which) {
   1.635 +  // This can be done without a lock because each thread reads one element.
   1.636 +  return resource_flag(which);
   1.637 +}
   1.638 +
   1.639 +void GCTaskManager::note_release(uint which) {
   1.640 +  // This can be done without a lock because each thread writes one element.
   1.641 +  set_resource_flag(which, false);
   1.642 +}
   1.643 +
   1.644 +void GCTaskManager::execute_and_wait(GCTaskQueue* list) {
   1.645 +  WaitForBarrierGCTask* fin = WaitForBarrierGCTask::create();
   1.646 +  list->enqueue(fin);
   1.647 +  add_list(list);
   1.648 +  fin->wait_for();
   1.649 +  // We have to release the barrier tasks!
   1.650 +  WaitForBarrierGCTask::destroy(fin);
   1.651 +}
   1.652 +
   1.653 +bool GCTaskManager::resource_flag(uint which) {
   1.654 +  assert(which < workers(), "index out of bounds");
   1.655 +  return _resource_flag[which];
   1.656 +}
   1.657 +
   1.658 +void GCTaskManager::set_resource_flag(uint which, bool value) {
   1.659 +  assert(which < workers(), "index out of bounds");
   1.660 +  _resource_flag[which] = value;
   1.661 +}
   1.662 +
   1.663 +//
   1.664 +// NoopGCTask
   1.665 +//
   1.666 +
   1.667 +NoopGCTask* NoopGCTask::create() {
   1.668 +  NoopGCTask* result = new NoopGCTask(false);
   1.669 +  return result;
   1.670 +}
   1.671 +
   1.672 +NoopGCTask* NoopGCTask::create_on_c_heap() {
   1.673 +  NoopGCTask* result = new(ResourceObj::C_HEAP) NoopGCTask(true);
   1.674 +  return result;
   1.675 +}
   1.676 +
   1.677 +void NoopGCTask::destroy(NoopGCTask* that) {
   1.678 +  if (that != NULL) {
   1.679 +    that->destruct();
   1.680 +    if (that->is_c_heap_obj()) {
   1.681 +      FreeHeap(that);
   1.682 +    }
   1.683 +  }
   1.684 +}
   1.685 +
   1.686 +void NoopGCTask::destruct() {
   1.687 +  // This has to know it's superclass structure, just like the constructor.
   1.688 +  this->GCTask::destruct();
   1.689 +  // Nothing else to do.
   1.690 +}
   1.691 +
   1.692 +//
   1.693 +// BarrierGCTask
   1.694 +//
   1.695 +
   1.696 +void BarrierGCTask::do_it(GCTaskManager* manager, uint which) {
   1.697 +  // Wait for this to be the only busy worker.
   1.698 +  // ??? I thought of having a StackObj class
   1.699 +  //     whose constructor would grab the lock and come to the barrier,
   1.700 +  //     and whose destructor would release the lock,
   1.701 +  //     but that seems like too much mechanism for two lines of code.
   1.702 +  MutexLockerEx ml(manager->lock(), Mutex::_no_safepoint_check_flag);
   1.703 +  do_it_internal(manager, which);
   1.704 +  // Release manager->lock().
   1.705 +}
   1.706 +
   1.707 +void BarrierGCTask::do_it_internal(GCTaskManager* manager, uint which) {
   1.708 +  // Wait for this to be the only busy worker.
   1.709 +  assert(manager->monitor()->owned_by_self(), "don't own the lock");
   1.710 +  assert(manager->is_blocked(), "manager isn't blocked");
   1.711 +  while (manager->busy_workers() > 1) {
   1.712 +    if (TraceGCTaskManager) {
   1.713 +      tty->print_cr("BarrierGCTask::do_it(%u) waiting on %u workers",
   1.714 +                    which, manager->busy_workers());
   1.715 +    }
   1.716 +    manager->monitor()->wait(Mutex::_no_safepoint_check_flag, 0);
   1.717 +  }
   1.718 +}
   1.719 +
   1.720 +void BarrierGCTask::destruct() {
   1.721 +  this->GCTask::destruct();
   1.722 +  // Nothing else to do.
   1.723 +}
   1.724 +
   1.725 +//
   1.726 +// ReleasingBarrierGCTask
   1.727 +//
   1.728 +
   1.729 +void ReleasingBarrierGCTask::do_it(GCTaskManager* manager, uint which) {
   1.730 +  MutexLockerEx ml(manager->lock(), Mutex::_no_safepoint_check_flag);
   1.731 +  do_it_internal(manager, which);
   1.732 +  manager->release_all_resources();
   1.733 +  // Release manager->lock().
   1.734 +}
   1.735 +
   1.736 +void ReleasingBarrierGCTask::destruct() {
   1.737 +  this->BarrierGCTask::destruct();
   1.738 +  // Nothing else to do.
   1.739 +}
   1.740 +
   1.741 +//
   1.742 +// NotifyingBarrierGCTask
   1.743 +//
   1.744 +
   1.745 +void NotifyingBarrierGCTask::do_it(GCTaskManager* manager, uint which) {
   1.746 +  MutexLockerEx ml(manager->lock(), Mutex::_no_safepoint_check_flag);
   1.747 +  do_it_internal(manager, which);
   1.748 +  NotifyDoneClosure* ndc = notify_done_closure();
   1.749 +  if (ndc != NULL) {
   1.750 +    ndc->notify(manager);
   1.751 +  }
   1.752 +  // Release manager->lock().
   1.753 +}
   1.754 +
   1.755 +void NotifyingBarrierGCTask::destruct() {
   1.756 +  this->BarrierGCTask::destruct();
   1.757 +  // Nothing else to do.
   1.758 +}
   1.759 +
   1.760 +//
   1.761 +// WaitForBarrierGCTask
   1.762 +//
   1.763 +WaitForBarrierGCTask* WaitForBarrierGCTask::create() {
   1.764 +  WaitForBarrierGCTask* result = new WaitForBarrierGCTask(false);
   1.765 +  return result;
   1.766 +}
   1.767 +
   1.768 +WaitForBarrierGCTask* WaitForBarrierGCTask::create_on_c_heap() {
   1.769 +  WaitForBarrierGCTask* result = new WaitForBarrierGCTask(true);
   1.770 +  return result;
   1.771 +}
   1.772 +
   1.773 +WaitForBarrierGCTask::WaitForBarrierGCTask(bool on_c_heap) :
   1.774 +  _is_c_heap_obj(on_c_heap) {
   1.775 +  _monitor = MonitorSupply::reserve();
   1.776 +  set_should_wait(true);
   1.777 +  if (TraceGCTaskManager) {
   1.778 +    tty->print_cr("[" INTPTR_FORMAT "]"
   1.779 +                  " WaitForBarrierGCTask::WaitForBarrierGCTask()"
   1.780 +                  "  monitor: " INTPTR_FORMAT,
   1.781 +                  this, monitor());
   1.782 +  }
   1.783 +}
   1.784 +
   1.785 +void WaitForBarrierGCTask::destroy(WaitForBarrierGCTask* that) {
   1.786 +  if (that != NULL) {
   1.787 +    if (TraceGCTaskManager) {
   1.788 +      tty->print_cr("[" INTPTR_FORMAT "]"
   1.789 +                    " WaitForBarrierGCTask::destroy()"
   1.790 +                    "  is_c_heap_obj: %s"
   1.791 +                    "  monitor: " INTPTR_FORMAT,
   1.792 +                    that,
   1.793 +                    that->is_c_heap_obj() ? "true" : "false",
   1.794 +                    that->monitor());
   1.795 +    }
   1.796 +    that->destruct();
   1.797 +    if (that->is_c_heap_obj()) {
   1.798 +      FreeHeap(that);
   1.799 +    }
   1.800 +  }
   1.801 +}
   1.802 +
   1.803 +void WaitForBarrierGCTask::destruct() {
   1.804 +  assert(monitor() != NULL, "monitor should not be NULL");
   1.805 +  if (TraceGCTaskManager) {
   1.806 +    tty->print_cr("[" INTPTR_FORMAT "]"
   1.807 +                  " WaitForBarrierGCTask::destruct()"
   1.808 +                  "  monitor: " INTPTR_FORMAT,
   1.809 +                  this, monitor());
   1.810 +  }
   1.811 +  this->BarrierGCTask::destruct();
   1.812 +  // Clean up that should be in the destructor,
   1.813 +  // except that ResourceMarks don't call destructors.
   1.814 +   if (monitor() != NULL) {
   1.815 +     MonitorSupply::release(monitor());
   1.816 +  }
   1.817 +  _monitor = (Monitor*) 0xDEAD000F;
   1.818 +}
   1.819 +
   1.820 +void WaitForBarrierGCTask::do_it(GCTaskManager* manager, uint which) {
   1.821 +  if (TraceGCTaskManager) {
   1.822 +    tty->print_cr("[" INTPTR_FORMAT "]"
   1.823 +                  " WaitForBarrierGCTask::do_it() waiting for idle"
   1.824 +                  "  monitor: " INTPTR_FORMAT,
   1.825 +                  this, monitor());
   1.826 +  }
   1.827 +  {
   1.828 +    // First, wait for the barrier to arrive.
   1.829 +    MutexLockerEx ml(manager->lock(), Mutex::_no_safepoint_check_flag);
   1.830 +    do_it_internal(manager, which);
   1.831 +    // Release manager->lock().
   1.832 +  }
   1.833 +  {
   1.834 +    // Then notify the waiter.
   1.835 +    MutexLockerEx ml(monitor(), Mutex::_no_safepoint_check_flag);
   1.836 +    set_should_wait(false);
   1.837 +    // Waiter doesn't miss the notify in the wait_for method
   1.838 +    // since it checks the flag after grabbing the monitor.
   1.839 +    if (TraceGCTaskManager) {
   1.840 +      tty->print_cr("[" INTPTR_FORMAT "]"
   1.841 +                    " WaitForBarrierGCTask::do_it()"
   1.842 +                    "  [" INTPTR_FORMAT "] (%s)->notify_all()",
   1.843 +                    this, monitor(), monitor()->name());
   1.844 +    }
   1.845 +    monitor()->notify_all();
   1.846 +    // Release monitor().
   1.847 +  }
   1.848 +}
   1.849 +
   1.850 +void WaitForBarrierGCTask::wait_for() {
   1.851 +  if (TraceGCTaskManager) {
   1.852 +    tty->print_cr("[" INTPTR_FORMAT "]"
   1.853 +                  " WaitForBarrierGCTask::wait_for()"
   1.854 +      "  should_wait: %s",
   1.855 +      this, should_wait() ? "true" : "false");
   1.856 +  }
   1.857 +  {
   1.858 +    // Grab the lock and check again.
   1.859 +    MutexLockerEx ml(monitor(), Mutex::_no_safepoint_check_flag);
   1.860 +    while (should_wait()) {
   1.861 +      if (TraceGCTaskManager) {
   1.862 +        tty->print_cr("[" INTPTR_FORMAT "]"
   1.863 +                      " WaitForBarrierGCTask::wait_for()"
   1.864 +          "  [" INTPTR_FORMAT "] (%s)->wait()",
   1.865 +          this, monitor(), monitor()->name());
   1.866 +      }
   1.867 +      monitor()->wait(Mutex::_no_safepoint_check_flag, 0);
   1.868 +    }
   1.869 +    // Reset the flag in case someone reuses this task.
   1.870 +    set_should_wait(true);
   1.871 +    if (TraceGCTaskManager) {
   1.872 +      tty->print_cr("[" INTPTR_FORMAT "]"
   1.873 +                    " WaitForBarrierGCTask::wait_for() returns"
   1.874 +        "  should_wait: %s",
   1.875 +        this, should_wait() ? "true" : "false");
   1.876 +    }
   1.877 +    // Release monitor().
   1.878 +  }
   1.879 +}
   1.880 +
   1.881 +Mutex*                   MonitorSupply::_lock     = NULL;
   1.882 +GrowableArray<Monitor*>* MonitorSupply::_freelist = NULL;
   1.883 +
   1.884 +Monitor* MonitorSupply::reserve() {
   1.885 +  Monitor* result = NULL;
   1.886 +  // Lazy initialization: possible race.
   1.887 +  if (lock() == NULL) {
   1.888 +    _lock = new Mutex(Mutex::barrier,                  // rank
   1.889 +                      "MonitorSupply mutex",           // name
   1.890 +                      Mutex::_allow_vm_block_flag);    // allow_vm_block
   1.891 +  }
   1.892 +  {
   1.893 +    MutexLockerEx ml(lock());
   1.894 +    // Lazy initialization.
   1.895 +    if (freelist() == NULL) {
   1.896 +      _freelist =
   1.897 +        new(ResourceObj::C_HEAP) GrowableArray<Monitor*>(ParallelGCThreads,
   1.898 +                                                         true);
   1.899 +    }
   1.900 +    if (! freelist()->is_empty()) {
   1.901 +      result = freelist()->pop();
   1.902 +    } else {
   1.903 +      result = new Monitor(Mutex::barrier,                  // rank
   1.904 +                           "MonitorSupply monitor",         // name
   1.905 +                           Mutex::_allow_vm_block_flag);    // allow_vm_block
   1.906 +    }
   1.907 +    guarantee(result != NULL, "shouldn't return NULL");
   1.908 +    assert(!result->is_locked(), "shouldn't be locked");
   1.909 +    // release lock().
   1.910 +  }
   1.911 +  return result;
   1.912 +}
   1.913 +
   1.914 +void MonitorSupply::release(Monitor* instance) {
   1.915 +  assert(instance != NULL, "shouldn't release NULL");
   1.916 +  assert(!instance->is_locked(), "shouldn't be locked");
   1.917 +  {
   1.918 +    MutexLockerEx ml(lock());
   1.919 +    freelist()->push(instance);
   1.920 +    // release lock().
   1.921 +  }
   1.922 +}

mercurial