src/share/vm/utilities/workgroup.cpp

Thu, 20 Nov 2008 16:56:09 -0800

author
ysr
date
Thu, 20 Nov 2008 16:56:09 -0800
changeset 888
c96030fff130
parent 777
37f87013dfd8
child 1907
c18cbe5936b8
permissions
-rw-r--r--

6684579: SoftReference processing can be made more efficient
Summary: For current soft-ref clearing policies, we can decide at marking time if a soft-reference will definitely not be cleared, postponing the decision of whether it will definitely be cleared to the final reference processing phase. This can be especially beneficial in the case of concurrent collectors where the marking is usually concurrent but reference processing is usually not.
Reviewed-by: jmasa

duke@435 1 /*
duke@435 2 * Copyright 2001-2007 Sun Microsystems, Inc. All Rights Reserved.
duke@435 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
duke@435 4 *
duke@435 5 * This code is free software; you can redistribute it and/or modify it
duke@435 6 * under the terms of the GNU General Public License version 2 only, as
duke@435 7 * published by the Free Software Foundation.
duke@435 8 *
duke@435 9 * This code is distributed in the hope that it will be useful, but WITHOUT
duke@435 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
duke@435 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
duke@435 12 * version 2 for more details (a copy is included in the LICENSE file that
duke@435 13 * accompanied this code).
duke@435 14 *
duke@435 15 * You should have received a copy of the GNU General Public License version
duke@435 16 * 2 along with this work; if not, write to the Free Software Foundation,
duke@435 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
duke@435 18 *
duke@435 19 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
duke@435 20 * CA 95054 USA or visit www.sun.com if you need additional information or
duke@435 21 * have any questions.
duke@435 22 *
duke@435 23 */
duke@435 24
duke@435 25 # include "incls/_precompiled.incl"
duke@435 26 # include "incls/_workgroup.cpp.incl"
duke@435 27
duke@435 28 // Definitions of WorkGang methods.
duke@435 29
duke@435 30 AbstractWorkGang::AbstractWorkGang(const char* name,
ysr@777 31 bool are_GC_task_threads,
ysr@777 32 bool are_ConcurrentGC_threads) :
duke@435 33 _name(name),
ysr@777 34 _are_GC_task_threads(are_GC_task_threads),
ysr@777 35 _are_ConcurrentGC_threads(are_ConcurrentGC_threads) {
ysr@777 36
ysr@777 37 assert(!(are_GC_task_threads && are_ConcurrentGC_threads),
ysr@777 38 "They cannot both be STW GC and Concurrent threads" );
ysr@777 39
duke@435 40 // Other initialization.
duke@435 41 _monitor = new Monitor(/* priority */ Mutex::leaf,
duke@435 42 /* name */ "WorkGroup monitor",
ysr@777 43 /* allow_vm_block */ are_GC_task_threads);
duke@435 44 assert(monitor() != NULL, "Failed to allocate monitor");
duke@435 45 _terminate = false;
duke@435 46 _task = NULL;
duke@435 47 _sequence_number = 0;
duke@435 48 _started_workers = 0;
duke@435 49 _finished_workers = 0;
duke@435 50 }
duke@435 51
duke@435 52 WorkGang::WorkGang(const char* name,
ysr@777 53 int workers,
ysr@777 54 bool are_GC_task_threads,
ysr@777 55 bool are_ConcurrentGC_threads) :
ysr@777 56 AbstractWorkGang(name, are_GC_task_threads, are_ConcurrentGC_threads)
ysr@777 57 {
duke@435 58 // Save arguments.
duke@435 59 _total_workers = workers;
ysr@777 60
duke@435 61 if (TraceWorkGang) {
duke@435 62 tty->print_cr("Constructing work gang %s with %d threads", name, workers);
duke@435 63 }
duke@435 64 _gang_workers = NEW_C_HEAP_ARRAY(GangWorker*, workers);
ysr@777 65 if (gang_workers() == NULL) {
ysr@777 66 vm_exit_out_of_memory(0, "Cannot create GangWorker array.");
ysr@777 67 }
duke@435 68 for (int worker = 0; worker < total_workers(); worker += 1) {
duke@435 69 GangWorker* new_worker = new GangWorker(this, worker);
duke@435 70 assert(new_worker != NULL, "Failed to allocate GangWorker");
duke@435 71 _gang_workers[worker] = new_worker;
duke@435 72 if (new_worker == NULL || !os::create_thread(new_worker, os::pgc_thread))
duke@435 73 vm_exit_out_of_memory(0, "Cannot create worker GC thread. Out of system resources.");
duke@435 74 if (!DisableStartThread) {
duke@435 75 os::start_thread(new_worker);
duke@435 76 }
duke@435 77 }
duke@435 78 }
duke@435 79
duke@435 80 AbstractWorkGang::~AbstractWorkGang() {
duke@435 81 if (TraceWorkGang) {
duke@435 82 tty->print_cr("Destructing work gang %s", name());
duke@435 83 }
duke@435 84 stop(); // stop all the workers
duke@435 85 for (int worker = 0; worker < total_workers(); worker += 1) {
duke@435 86 delete gang_worker(worker);
duke@435 87 }
duke@435 88 delete gang_workers();
duke@435 89 delete monitor();
duke@435 90 }
duke@435 91
duke@435 92 GangWorker* AbstractWorkGang::gang_worker(int i) const {
duke@435 93 // Array index bounds checking.
duke@435 94 GangWorker* result = NULL;
duke@435 95 assert(gang_workers() != NULL, "No workers for indexing");
duke@435 96 assert(((i >= 0) && (i < total_workers())), "Worker index out of bounds");
duke@435 97 result = _gang_workers[i];
duke@435 98 assert(result != NULL, "Indexing to null worker");
duke@435 99 return result;
duke@435 100 }
duke@435 101
duke@435 102 void WorkGang::run_task(AbstractGangTask* task) {
duke@435 103 // This thread is executed by the VM thread which does not block
duke@435 104 // on ordinary MutexLocker's.
duke@435 105 MutexLockerEx ml(monitor(), Mutex::_no_safepoint_check_flag);
duke@435 106 if (TraceWorkGang) {
duke@435 107 tty->print_cr("Running work gang %s task %s", name(), task->name());
duke@435 108 }
duke@435 109 // Tell all the workers to run a task.
duke@435 110 assert(task != NULL, "Running a null task");
duke@435 111 // Initialize.
duke@435 112 _task = task;
duke@435 113 _sequence_number += 1;
duke@435 114 _started_workers = 0;
duke@435 115 _finished_workers = 0;
duke@435 116 // Tell the workers to get to work.
duke@435 117 monitor()->notify_all();
duke@435 118 // Wait for them to be finished
duke@435 119 while (finished_workers() < total_workers()) {
duke@435 120 if (TraceWorkGang) {
duke@435 121 tty->print_cr("Waiting in work gang %s: %d/%d finished sequence %d",
duke@435 122 name(), finished_workers(), total_workers(),
duke@435 123 _sequence_number);
duke@435 124 }
duke@435 125 monitor()->wait(/* no_safepoint_check */ true);
duke@435 126 }
duke@435 127 _task = NULL;
duke@435 128 if (TraceWorkGang) {
duke@435 129 tty->print_cr("/nFinished work gang %s: %d/%d sequence %d",
duke@435 130 name(), finished_workers(), total_workers(),
duke@435 131 _sequence_number);
duke@435 132 }
duke@435 133 }
duke@435 134
duke@435 135 void AbstractWorkGang::stop() {
duke@435 136 // Tell all workers to terminate, then wait for them to become inactive.
duke@435 137 MutexLockerEx ml(monitor(), Mutex::_no_safepoint_check_flag);
duke@435 138 if (TraceWorkGang) {
duke@435 139 tty->print_cr("Stopping work gang %s task %s", name(), task()->name());
duke@435 140 }
duke@435 141 _task = NULL;
duke@435 142 _terminate = true;
duke@435 143 monitor()->notify_all();
duke@435 144 while (finished_workers() < total_workers()) {
duke@435 145 if (TraceWorkGang) {
duke@435 146 tty->print_cr("Waiting in work gang %s: %d/%d finished",
duke@435 147 name(), finished_workers(), total_workers());
duke@435 148 }
duke@435 149 monitor()->wait(/* no_safepoint_check */ true);
duke@435 150 }
duke@435 151 }
duke@435 152
duke@435 153 void AbstractWorkGang::internal_worker_poll(WorkData* data) const {
duke@435 154 assert(monitor()->owned_by_self(), "worker_poll is an internal method");
duke@435 155 assert(data != NULL, "worker data is null");
duke@435 156 data->set_terminate(terminate());
duke@435 157 data->set_task(task());
duke@435 158 data->set_sequence_number(sequence_number());
duke@435 159 }
duke@435 160
duke@435 161 void AbstractWorkGang::internal_note_start() {
duke@435 162 assert(monitor()->owned_by_self(), "note_finish is an internal method");
duke@435 163 _started_workers += 1;
duke@435 164 }
duke@435 165
duke@435 166 void AbstractWorkGang::internal_note_finish() {
duke@435 167 assert(monitor()->owned_by_self(), "note_finish is an internal method");
duke@435 168 _finished_workers += 1;
duke@435 169 }
duke@435 170
duke@435 171 void AbstractWorkGang::print_worker_threads_on(outputStream* st) const {
duke@435 172 uint num_thr = total_workers();
duke@435 173 for (uint i = 0; i < num_thr; i++) {
duke@435 174 gang_worker(i)->print_on(st);
duke@435 175 st->cr();
duke@435 176 }
duke@435 177 }
duke@435 178
duke@435 179 void AbstractWorkGang::threads_do(ThreadClosure* tc) const {
duke@435 180 assert(tc != NULL, "Null ThreadClosure");
duke@435 181 uint num_thr = total_workers();
duke@435 182 for (uint i = 0; i < num_thr; i++) {
duke@435 183 tc->do_thread(gang_worker(i));
duke@435 184 }
duke@435 185 }
duke@435 186
duke@435 187 // GangWorker methods.
duke@435 188
duke@435 189 GangWorker::GangWorker(AbstractWorkGang* gang, uint id) {
duke@435 190 _gang = gang;
duke@435 191 set_id(id);
duke@435 192 set_name("Gang worker#%d (%s)", id, gang->name());
duke@435 193 }
duke@435 194
duke@435 195 void GangWorker::run() {
duke@435 196 initialize();
duke@435 197 loop();
duke@435 198 }
duke@435 199
duke@435 200 void GangWorker::initialize() {
duke@435 201 this->initialize_thread_local_storage();
duke@435 202 assert(_gang != NULL, "No gang to run in");
duke@435 203 os::set_priority(this, NearMaxPriority);
duke@435 204 if (TraceWorkGang) {
duke@435 205 tty->print_cr("Running gang worker for gang %s id %d",
duke@435 206 gang()->name(), id());
duke@435 207 }
duke@435 208 // The VM thread should not execute here because MutexLocker's are used
duke@435 209 // as (opposed to MutexLockerEx's).
duke@435 210 assert(!Thread::current()->is_VM_thread(), "VM thread should not be part"
duke@435 211 " of a work gang");
duke@435 212 }
duke@435 213
duke@435 214 void GangWorker::loop() {
duke@435 215 int previous_sequence_number = 0;
duke@435 216 Monitor* gang_monitor = gang()->monitor();
duke@435 217 for ( ; /* !terminate() */; ) {
duke@435 218 WorkData data;
duke@435 219 int part; // Initialized below.
duke@435 220 {
duke@435 221 // Grab the gang mutex.
duke@435 222 MutexLocker ml(gang_monitor);
duke@435 223 // Wait for something to do.
duke@435 224 // Polling outside the while { wait } avoids missed notifies
duke@435 225 // in the outer loop.
duke@435 226 gang()->internal_worker_poll(&data);
duke@435 227 if (TraceWorkGang) {
duke@435 228 tty->print("Polled outside for work in gang %s worker %d",
duke@435 229 gang()->name(), id());
duke@435 230 tty->print(" terminate: %s",
duke@435 231 data.terminate() ? "true" : "false");
duke@435 232 tty->print(" sequence: %d (prev: %d)",
duke@435 233 data.sequence_number(), previous_sequence_number);
duke@435 234 if (data.task() != NULL) {
duke@435 235 tty->print(" task: %s", data.task()->name());
duke@435 236 } else {
duke@435 237 tty->print(" task: NULL");
duke@435 238 }
duke@435 239 tty->cr();
duke@435 240 }
duke@435 241 for ( ; /* break or return */; ) {
duke@435 242 // Terminate if requested.
duke@435 243 if (data.terminate()) {
duke@435 244 gang()->internal_note_finish();
duke@435 245 gang_monitor->notify_all();
duke@435 246 return;
duke@435 247 }
duke@435 248 // Check for new work.
duke@435 249 if ((data.task() != NULL) &&
duke@435 250 (data.sequence_number() != previous_sequence_number)) {
duke@435 251 gang()->internal_note_start();
duke@435 252 gang_monitor->notify_all();
duke@435 253 part = gang()->started_workers() - 1;
duke@435 254 break;
duke@435 255 }
duke@435 256 // Nothing to do.
duke@435 257 gang_monitor->wait(/* no_safepoint_check */ true);
duke@435 258 gang()->internal_worker_poll(&data);
duke@435 259 if (TraceWorkGang) {
duke@435 260 tty->print("Polled inside for work in gang %s worker %d",
duke@435 261 gang()->name(), id());
duke@435 262 tty->print(" terminate: %s",
duke@435 263 data.terminate() ? "true" : "false");
duke@435 264 tty->print(" sequence: %d (prev: %d)",
duke@435 265 data.sequence_number(), previous_sequence_number);
duke@435 266 if (data.task() != NULL) {
duke@435 267 tty->print(" task: %s", data.task()->name());
duke@435 268 } else {
duke@435 269 tty->print(" task: NULL");
duke@435 270 }
duke@435 271 tty->cr();
duke@435 272 }
duke@435 273 }
duke@435 274 // Drop gang mutex.
duke@435 275 }
duke@435 276 if (TraceWorkGang) {
duke@435 277 tty->print("Work for work gang %s id %d task %s part %d",
duke@435 278 gang()->name(), id(), data.task()->name(), part);
duke@435 279 }
duke@435 280 assert(data.task() != NULL, "Got null task");
duke@435 281 data.task()->work(part);
duke@435 282 {
duke@435 283 if (TraceWorkGang) {
duke@435 284 tty->print("Finish for work gang %s id %d task %s part %d",
duke@435 285 gang()->name(), id(), data.task()->name(), part);
duke@435 286 }
duke@435 287 // Grab the gang mutex.
duke@435 288 MutexLocker ml(gang_monitor);
duke@435 289 gang()->internal_note_finish();
duke@435 290 // Tell the gang you are done.
duke@435 291 gang_monitor->notify_all();
duke@435 292 // Drop the gang mutex.
duke@435 293 }
duke@435 294 previous_sequence_number = data.sequence_number();
duke@435 295 }
duke@435 296 }
duke@435 297
duke@435 298 bool GangWorker::is_GC_task_thread() const {
ysr@777 299 return gang()->are_GC_task_threads();
ysr@777 300 }
ysr@777 301
ysr@777 302 bool GangWorker::is_ConcurrentGC_thread() const {
ysr@777 303 return gang()->are_ConcurrentGC_threads();
duke@435 304 }
duke@435 305
duke@435 306 void GangWorker::print_on(outputStream* st) const {
duke@435 307 st->print("\"%s\" ", name());
duke@435 308 Thread::print_on(st);
duke@435 309 st->cr();
duke@435 310 }
duke@435 311
duke@435 312 // Printing methods
duke@435 313
duke@435 314 const char* AbstractWorkGang::name() const {
duke@435 315 return _name;
duke@435 316 }
duke@435 317
duke@435 318 #ifndef PRODUCT
duke@435 319
duke@435 320 const char* AbstractGangTask::name() const {
duke@435 321 return _name;
duke@435 322 }
duke@435 323
duke@435 324 #endif /* PRODUCT */
duke@435 325
duke@435 326 // *** WorkGangBarrierSync
duke@435 327
duke@435 328 WorkGangBarrierSync::WorkGangBarrierSync()
duke@435 329 : _monitor(Mutex::safepoint, "work gang barrier sync", true),
ysr@777 330 _n_workers(0), _n_completed(0), _should_reset(false) {
duke@435 331 }
duke@435 332
duke@435 333 WorkGangBarrierSync::WorkGangBarrierSync(int n_workers, const char* name)
duke@435 334 : _monitor(Mutex::safepoint, name, true),
ysr@777 335 _n_workers(n_workers), _n_completed(0), _should_reset(false) {
duke@435 336 }
duke@435 337
duke@435 338 void WorkGangBarrierSync::set_n_workers(int n_workers) {
duke@435 339 _n_workers = n_workers;
duke@435 340 _n_completed = 0;
ysr@777 341 _should_reset = false;
duke@435 342 }
duke@435 343
duke@435 344 void WorkGangBarrierSync::enter() {
duke@435 345 MutexLockerEx x(monitor(), Mutex::_no_safepoint_check_flag);
ysr@777 346 if (should_reset()) {
ysr@777 347 // The should_reset() was set and we are the first worker to enter
ysr@777 348 // the sync barrier. We will zero the n_completed() count which
ysr@777 349 // effectively resets the barrier.
ysr@777 350 zero_completed();
ysr@777 351 set_should_reset(false);
ysr@777 352 }
duke@435 353 inc_completed();
duke@435 354 if (n_completed() == n_workers()) {
ysr@777 355 // At this point we would like to reset the barrier to be ready in
ysr@777 356 // case it is used again. However, we cannot set n_completed() to
ysr@777 357 // 0, even after the notify_all(), given that some other workers
ysr@777 358 // might still be waiting for n_completed() to become ==
ysr@777 359 // n_workers(). So, if we set n_completed() to 0, those workers
ysr@777 360 // will get stuck (as they will wake up, see that n_completed() !=
ysr@777 361 // n_workers() and go back to sleep). Instead, we raise the
ysr@777 362 // should_reset() flag and the barrier will be reset the first
ysr@777 363 // time a worker enters it again.
ysr@777 364 set_should_reset(true);
duke@435 365 monitor()->notify_all();
ysr@777 366 } else {
duke@435 367 while (n_completed() != n_workers()) {
duke@435 368 monitor()->wait(/* no_safepoint_check */ true);
duke@435 369 }
duke@435 370 }
duke@435 371 }
duke@435 372
duke@435 373 // SubTasksDone functions.
duke@435 374
duke@435 375 SubTasksDone::SubTasksDone(int n) :
duke@435 376 _n_tasks(n), _n_threads(1), _tasks(NULL) {
duke@435 377 _tasks = NEW_C_HEAP_ARRAY(jint, n);
duke@435 378 guarantee(_tasks != NULL, "alloc failure");
duke@435 379 clear();
duke@435 380 }
duke@435 381
duke@435 382 bool SubTasksDone::valid() {
duke@435 383 return _tasks != NULL;
duke@435 384 }
duke@435 385
duke@435 386 void SubTasksDone::set_par_threads(int t) {
duke@435 387 #ifdef ASSERT
duke@435 388 assert(_claimed == 0 || _threads_completed == _n_threads,
duke@435 389 "should not be called while tasks are being processed!");
duke@435 390 #endif
duke@435 391 _n_threads = (t == 0 ? 1 : t);
duke@435 392 }
duke@435 393
duke@435 394 void SubTasksDone::clear() {
duke@435 395 for (int i = 0; i < _n_tasks; i++) {
duke@435 396 _tasks[i] = 0;
duke@435 397 }
duke@435 398 _threads_completed = 0;
duke@435 399 #ifdef ASSERT
duke@435 400 _claimed = 0;
duke@435 401 #endif
duke@435 402 }
duke@435 403
duke@435 404 bool SubTasksDone::is_task_claimed(int t) {
duke@435 405 assert(0 <= t && t < _n_tasks, "bad task id.");
duke@435 406 jint old = _tasks[t];
duke@435 407 if (old == 0) {
duke@435 408 old = Atomic::cmpxchg(1, &_tasks[t], 0);
duke@435 409 }
duke@435 410 assert(_tasks[t] == 1, "What else?");
duke@435 411 bool res = old != 0;
duke@435 412 #ifdef ASSERT
duke@435 413 if (!res) {
duke@435 414 assert(_claimed < _n_tasks, "Too many tasks claimed; missing clear?");
duke@435 415 Atomic::inc(&_claimed);
duke@435 416 }
duke@435 417 #endif
duke@435 418 return res;
duke@435 419 }
duke@435 420
duke@435 421 void SubTasksDone::all_tasks_completed() {
duke@435 422 jint observed = _threads_completed;
duke@435 423 jint old;
duke@435 424 do {
duke@435 425 old = observed;
duke@435 426 observed = Atomic::cmpxchg(old+1, &_threads_completed, old);
duke@435 427 } while (observed != old);
duke@435 428 // If this was the last thread checking in, clear the tasks.
duke@435 429 if (observed+1 == _n_threads) clear();
duke@435 430 }
duke@435 431
duke@435 432
duke@435 433 SubTasksDone::~SubTasksDone() {
duke@435 434 if (_tasks != NULL) FREE_C_HEAP_ARRAY(jint, _tasks);
duke@435 435 }
duke@435 436
duke@435 437 // *** SequentialSubTasksDone
duke@435 438
duke@435 439 void SequentialSubTasksDone::clear() {
duke@435 440 _n_tasks = _n_claimed = 0;
duke@435 441 _n_threads = _n_completed = 0;
duke@435 442 }
duke@435 443
duke@435 444 bool SequentialSubTasksDone::valid() {
duke@435 445 return _n_threads > 0;
duke@435 446 }
duke@435 447
duke@435 448 bool SequentialSubTasksDone::is_task_claimed(int& t) {
duke@435 449 jint* n_claimed_ptr = &_n_claimed;
duke@435 450 t = *n_claimed_ptr;
duke@435 451 while (t < _n_tasks) {
duke@435 452 jint res = Atomic::cmpxchg(t+1, n_claimed_ptr, t);
duke@435 453 if (res == t) {
duke@435 454 return false;
duke@435 455 }
duke@435 456 t = *n_claimed_ptr;
duke@435 457 }
duke@435 458 return true;
duke@435 459 }
duke@435 460
duke@435 461 bool SequentialSubTasksDone::all_tasks_completed() {
duke@435 462 jint* n_completed_ptr = &_n_completed;
duke@435 463 jint complete = *n_completed_ptr;
duke@435 464 while (true) {
duke@435 465 jint res = Atomic::cmpxchg(complete+1, n_completed_ptr, complete);
duke@435 466 if (res == complete) {
duke@435 467 break;
duke@435 468 }
duke@435 469 complete = res;
duke@435 470 }
duke@435 471 if (complete+1 == _n_threads) {
duke@435 472 clear();
duke@435 473 return true;
duke@435 474 }
duke@435 475 return false;
duke@435 476 }
ysr@777 477
ysr@777 478 bool FreeIdSet::_stat_init = false;
ysr@777 479 FreeIdSet* FreeIdSet::_sets[NSets];
ysr@777 480 bool FreeIdSet::_safepoint;
ysr@777 481
ysr@777 482 FreeIdSet::FreeIdSet(int sz, Monitor* mon) :
ysr@777 483 _sz(sz), _mon(mon), _hd(0), _waiters(0), _index(-1), _claimed(0)
ysr@777 484 {
ysr@777 485 _ids = new int[sz];
ysr@777 486 for (int i = 0; i < sz; i++) _ids[i] = i+1;
ysr@777 487 _ids[sz-1] = end_of_list; // end of list.
ysr@777 488 if (_stat_init) {
ysr@777 489 for (int j = 0; j < NSets; j++) _sets[j] = NULL;
ysr@777 490 _stat_init = true;
ysr@777 491 }
ysr@777 492 // Add to sets. (This should happen while the system is still single-threaded.)
ysr@777 493 for (int j = 0; j < NSets; j++) {
ysr@777 494 if (_sets[j] == NULL) {
ysr@777 495 _sets[j] = this;
ysr@777 496 _index = j;
ysr@777 497 break;
ysr@777 498 }
ysr@777 499 }
ysr@777 500 guarantee(_index != -1, "Too many FreeIdSets in use!");
ysr@777 501 }
ysr@777 502
ysr@777 503 FreeIdSet::~FreeIdSet() {
ysr@777 504 _sets[_index] = NULL;
ysr@777 505 }
ysr@777 506
ysr@777 507 void FreeIdSet::set_safepoint(bool b) {
ysr@777 508 _safepoint = b;
ysr@777 509 if (b) {
ysr@777 510 for (int j = 0; j < NSets; j++) {
ysr@777 511 if (_sets[j] != NULL && _sets[j]->_waiters > 0) {
ysr@777 512 Monitor* mon = _sets[j]->_mon;
ysr@777 513 mon->lock_without_safepoint_check();
ysr@777 514 mon->notify_all();
ysr@777 515 mon->unlock();
ysr@777 516 }
ysr@777 517 }
ysr@777 518 }
ysr@777 519 }
ysr@777 520
ysr@777 521 #define FID_STATS 0
ysr@777 522
ysr@777 523 int FreeIdSet::claim_par_id() {
ysr@777 524 #if FID_STATS
ysr@777 525 thread_t tslf = thr_self();
ysr@777 526 tty->print("claim_par_id[%d]: sz = %d, claimed = %d\n", tslf, _sz, _claimed);
ysr@777 527 #endif
ysr@777 528 MutexLockerEx x(_mon, Mutex::_no_safepoint_check_flag);
ysr@777 529 while (!_safepoint && _hd == end_of_list) {
ysr@777 530 _waiters++;
ysr@777 531 #if FID_STATS
ysr@777 532 if (_waiters > 5) {
ysr@777 533 tty->print("claim_par_id waiting[%d]: %d waiters, %d claimed.\n",
ysr@777 534 tslf, _waiters, _claimed);
ysr@777 535 }
ysr@777 536 #endif
ysr@777 537 _mon->wait(Mutex::_no_safepoint_check_flag);
ysr@777 538 _waiters--;
ysr@777 539 }
ysr@777 540 if (_hd == end_of_list) {
ysr@777 541 #if FID_STATS
ysr@777 542 tty->print("claim_par_id[%d]: returning EOL.\n", tslf);
ysr@777 543 #endif
ysr@777 544 return -1;
ysr@777 545 } else {
ysr@777 546 int res = _hd;
ysr@777 547 _hd = _ids[res];
ysr@777 548 _ids[res] = claimed; // For debugging.
ysr@777 549 _claimed++;
ysr@777 550 #if FID_STATS
ysr@777 551 tty->print("claim_par_id[%d]: returning %d, claimed = %d.\n",
ysr@777 552 tslf, res, _claimed);
ysr@777 553 #endif
ysr@777 554 return res;
ysr@777 555 }
ysr@777 556 }
ysr@777 557
ysr@777 558 bool FreeIdSet::claim_perm_id(int i) {
ysr@777 559 assert(0 <= i && i < _sz, "Out of range.");
ysr@777 560 MutexLockerEx x(_mon, Mutex::_no_safepoint_check_flag);
ysr@777 561 int prev = end_of_list;
ysr@777 562 int cur = _hd;
ysr@777 563 while (cur != end_of_list) {
ysr@777 564 if (cur == i) {
ysr@777 565 if (prev == end_of_list) {
ysr@777 566 _hd = _ids[cur];
ysr@777 567 } else {
ysr@777 568 _ids[prev] = _ids[cur];
ysr@777 569 }
ysr@777 570 _ids[cur] = claimed;
ysr@777 571 _claimed++;
ysr@777 572 return true;
ysr@777 573 } else {
ysr@777 574 prev = cur;
ysr@777 575 cur = _ids[cur];
ysr@777 576 }
ysr@777 577 }
ysr@777 578 return false;
ysr@777 579
ysr@777 580 }
ysr@777 581
ysr@777 582 void FreeIdSet::release_par_id(int id) {
ysr@777 583 MutexLockerEx x(_mon, Mutex::_no_safepoint_check_flag);
ysr@777 584 assert(_ids[id] == claimed, "Precondition.");
ysr@777 585 _ids[id] = _hd;
ysr@777 586 _hd = id;
ysr@777 587 _claimed--;
ysr@777 588 #if FID_STATS
ysr@777 589 tty->print("[%d] release_par_id(%d), waiters =%d, claimed = %d.\n",
ysr@777 590 thr_self(), id, _waiters, _claimed);
ysr@777 591 #endif
ysr@777 592 if (_waiters > 0)
ysr@777 593 // Notify all would be safer, but this is OK, right?
ysr@777 594 _mon->notify_all();
ysr@777 595 }

mercurial