Fri, 09 May 2008 08:55:13 -0700
6670684: 4/5 SA command universe did not print out CMS space information
Summary: Forward port of Yumin's fix for 6670684 from HSX-11; Yumin verified the port was correct.
Reviewed-by: dcubed
duke@435 | 1 | /* |
duke@435 | 2 | * Copyright 2001-2006 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/_concurrentMarkSweepThread.cpp.incl" |
duke@435 | 27 | |
duke@435 | 28 | // ======= Concurrent Mark Sweep Thread ======== |
duke@435 | 29 | |
duke@435 | 30 | // The CMS thread is created when Concurrent Mark Sweep is used in the |
duke@435 | 31 | // older of two generations in a generational memory system. |
duke@435 | 32 | |
duke@435 | 33 | ConcurrentMarkSweepThread* |
duke@435 | 34 | ConcurrentMarkSweepThread::_cmst = NULL; |
duke@435 | 35 | CMSCollector* ConcurrentMarkSweepThread::_collector = NULL; |
duke@435 | 36 | bool ConcurrentMarkSweepThread::_should_terminate = false; |
duke@435 | 37 | int ConcurrentMarkSweepThread::_CMS_flag = CMS_nil; |
duke@435 | 38 | |
duke@435 | 39 | volatile jint ConcurrentMarkSweepThread::_pending_yields = 0; |
duke@435 | 40 | volatile jint ConcurrentMarkSweepThread::_pending_decrements = 0; |
duke@435 | 41 | |
duke@435 | 42 | volatile bool ConcurrentMarkSweepThread::_icms_enabled = false; |
duke@435 | 43 | volatile bool ConcurrentMarkSweepThread::_should_run = false; |
duke@435 | 44 | // When icms is enabled, the icms thread is stopped until explicitly |
duke@435 | 45 | // started. |
duke@435 | 46 | volatile bool ConcurrentMarkSweepThread::_should_stop = true; |
duke@435 | 47 | |
duke@435 | 48 | SurrogateLockerThread* |
duke@435 | 49 | ConcurrentMarkSweepThread::_slt = NULL; |
duke@435 | 50 | SurrogateLockerThread::SLT_msg_type |
duke@435 | 51 | ConcurrentMarkSweepThread::_sltBuffer = SurrogateLockerThread::empty; |
duke@435 | 52 | Monitor* |
duke@435 | 53 | ConcurrentMarkSweepThread::_sltMonitor = NULL; |
duke@435 | 54 | |
duke@435 | 55 | ConcurrentMarkSweepThread::ConcurrentMarkSweepThread(CMSCollector* collector) |
duke@435 | 56 | : ConcurrentGCThread() { |
duke@435 | 57 | assert(UseConcMarkSweepGC, "UseConcMarkSweepGC should be set"); |
duke@435 | 58 | assert(_cmst == NULL, "CMS thread already created"); |
duke@435 | 59 | _cmst = this; |
duke@435 | 60 | assert(_collector == NULL, "Collector already set"); |
duke@435 | 61 | _collector = collector; |
duke@435 | 62 | |
duke@435 | 63 | set_name("Concurrent Mark-Sweep GC Thread"); |
duke@435 | 64 | |
duke@435 | 65 | if (os::create_thread(this, os::cgc_thread)) { |
duke@435 | 66 | // XXX: need to set this to low priority |
duke@435 | 67 | // unless "agressive mode" set; priority |
duke@435 | 68 | // should be just less than that of VMThread. |
duke@435 | 69 | os::set_priority(this, NearMaxPriority); |
duke@435 | 70 | if (!DisableStartThread) { |
duke@435 | 71 | os::start_thread(this); |
duke@435 | 72 | } |
duke@435 | 73 | } |
duke@435 | 74 | _sltMonitor = SLT_lock; |
duke@435 | 75 | set_icms_enabled(CMSIncrementalMode); |
duke@435 | 76 | } |
duke@435 | 77 | |
duke@435 | 78 | void ConcurrentMarkSweepThread::run() { |
duke@435 | 79 | assert(this == cmst(), "just checking"); |
duke@435 | 80 | |
duke@435 | 81 | this->record_stack_base_and_size(); |
duke@435 | 82 | this->initialize_thread_local_storage(); |
duke@435 | 83 | this->set_active_handles(JNIHandleBlock::allocate_block()); |
duke@435 | 84 | // From this time Thread::current() should be working. |
duke@435 | 85 | assert(this == Thread::current(), "just checking"); |
duke@435 | 86 | if (BindCMSThreadToCPU && !os::bind_to_processor(CPUForCMSThread)) { |
duke@435 | 87 | warning("Couldn't bind CMS thread to processor %u", CPUForCMSThread); |
duke@435 | 88 | } |
duke@435 | 89 | // Wait until Universe::is_fully_initialized() |
duke@435 | 90 | { |
duke@435 | 91 | CMSLoopCountWarn loopX("CMS::run", "waiting for " |
duke@435 | 92 | "Universe::is_fully_initialized()", 2); |
duke@435 | 93 | MutexLockerEx x(CGC_lock, true); |
duke@435 | 94 | set_CMS_flag(CMS_cms_wants_token); |
duke@435 | 95 | // Wait until Universe is initialized and all initialization is completed. |
duke@435 | 96 | while (!is_init_completed() && !Universe::is_fully_initialized() && |
duke@435 | 97 | !_should_terminate) { |
duke@435 | 98 | CGC_lock->wait(true, 200); |
duke@435 | 99 | loopX.tick(); |
duke@435 | 100 | } |
duke@435 | 101 | // Wait until the surrogate locker thread that will do |
duke@435 | 102 | // pending list locking on our behalf has been created. |
duke@435 | 103 | // We cannot start the SLT thread ourselves since we need |
duke@435 | 104 | // to be a JavaThread to do so. |
duke@435 | 105 | CMSLoopCountWarn loopY("CMS::run", "waiting for SLT installation", 2); |
duke@435 | 106 | while (_slt == NULL && !_should_terminate) { |
duke@435 | 107 | CGC_lock->wait(true, 200); |
duke@435 | 108 | loopY.tick(); |
duke@435 | 109 | } |
duke@435 | 110 | clear_CMS_flag(CMS_cms_wants_token); |
duke@435 | 111 | } |
duke@435 | 112 | |
duke@435 | 113 | while (!_should_terminate) { |
duke@435 | 114 | sleepBeforeNextCycle(); |
duke@435 | 115 | if (_should_terminate) break; |
duke@435 | 116 | _collector->collect_in_background(false); // !clear_all_soft_refs |
duke@435 | 117 | } |
duke@435 | 118 | assert(_should_terminate, "just checking"); |
duke@435 | 119 | // Check that the state of any protocol for synchronization |
duke@435 | 120 | // between background (CMS) and foreground collector is "clean" |
duke@435 | 121 | // (i.e. will not potentially block the foreground collector, |
duke@435 | 122 | // requiring action by us). |
duke@435 | 123 | verify_ok_to_terminate(); |
duke@435 | 124 | // Signal that it is terminated |
duke@435 | 125 | { |
duke@435 | 126 | MutexLockerEx mu(Terminator_lock, |
duke@435 | 127 | Mutex::_no_safepoint_check_flag); |
duke@435 | 128 | assert(_cmst == this, "Weird!"); |
duke@435 | 129 | _cmst = NULL; |
duke@435 | 130 | Terminator_lock->notify(); |
duke@435 | 131 | } |
duke@435 | 132 | |
duke@435 | 133 | // Thread destructor usually does this.. |
duke@435 | 134 | ThreadLocalStorage::set_thread(NULL); |
duke@435 | 135 | } |
duke@435 | 136 | |
duke@435 | 137 | #ifndef PRODUCT |
duke@435 | 138 | void ConcurrentMarkSweepThread::verify_ok_to_terminate() const { |
duke@435 | 139 | assert(!(CGC_lock->owned_by_self() || cms_thread_has_cms_token() || |
duke@435 | 140 | cms_thread_wants_cms_token()), |
duke@435 | 141 | "Must renounce all worldly possessions and desires for nirvana"); |
duke@435 | 142 | _collector->verify_ok_to_terminate(); |
duke@435 | 143 | } |
duke@435 | 144 | #endif |
duke@435 | 145 | |
duke@435 | 146 | // create and start a new ConcurrentMarkSweep Thread for given CMS generation |
duke@435 | 147 | ConcurrentMarkSweepThread* ConcurrentMarkSweepThread::start(CMSCollector* collector) { |
duke@435 | 148 | if (!_should_terminate) { |
duke@435 | 149 | assert(cmst() == NULL, "start() called twice?"); |
duke@435 | 150 | ConcurrentMarkSweepThread* th = new ConcurrentMarkSweepThread(collector); |
duke@435 | 151 | assert(cmst() == th, "Where did the just-created CMS thread go?"); |
duke@435 | 152 | return th; |
duke@435 | 153 | } |
duke@435 | 154 | return NULL; |
duke@435 | 155 | } |
duke@435 | 156 | |
duke@435 | 157 | void ConcurrentMarkSweepThread::stop() { |
duke@435 | 158 | if (CMSIncrementalMode) { |
duke@435 | 159 | // Disable incremental mode and wake up the thread so it notices the change. |
duke@435 | 160 | disable_icms(); |
duke@435 | 161 | start_icms(); |
duke@435 | 162 | } |
duke@435 | 163 | // it is ok to take late safepoints here, if needed |
duke@435 | 164 | { |
duke@435 | 165 | MutexLockerEx x(Terminator_lock); |
duke@435 | 166 | _should_terminate = true; |
duke@435 | 167 | } |
duke@435 | 168 | { // Now post a notify on CGC_lock so as to nudge |
duke@435 | 169 | // CMS thread(s) that might be slumbering in |
duke@435 | 170 | // sleepBeforeNextCycle. |
duke@435 | 171 | MutexLockerEx x(CGC_lock, Mutex::_no_safepoint_check_flag); |
duke@435 | 172 | CGC_lock->notify_all(); |
duke@435 | 173 | } |
duke@435 | 174 | { // Now wait until (all) CMS thread(s) have exited |
duke@435 | 175 | MutexLockerEx x(Terminator_lock); |
duke@435 | 176 | while(cmst() != NULL) { |
duke@435 | 177 | Terminator_lock->wait(); |
duke@435 | 178 | } |
duke@435 | 179 | } |
duke@435 | 180 | } |
duke@435 | 181 | |
duke@435 | 182 | void ConcurrentMarkSweepThread::threads_do(ThreadClosure* tc) { |
duke@435 | 183 | assert(tc != NULL, "Null ThreadClosure"); |
duke@435 | 184 | if (_cmst != NULL) { |
duke@435 | 185 | tc->do_thread(_cmst); |
duke@435 | 186 | } |
duke@435 | 187 | assert(Universe::is_fully_initialized(), |
duke@435 | 188 | "Called too early, make sure heap is fully initialized"); |
duke@435 | 189 | if (_collector != NULL) { |
duke@435 | 190 | AbstractWorkGang* gang = _collector->conc_workers(); |
duke@435 | 191 | if (gang != NULL) { |
duke@435 | 192 | gang->threads_do(tc); |
duke@435 | 193 | } |
duke@435 | 194 | } |
duke@435 | 195 | } |
duke@435 | 196 | |
duke@435 | 197 | void ConcurrentMarkSweepThread::print_on(outputStream* st) const { |
duke@435 | 198 | st->print("\"%s\" ", name()); |
duke@435 | 199 | Thread::print_on(st); |
duke@435 | 200 | st->cr(); |
duke@435 | 201 | } |
duke@435 | 202 | |
duke@435 | 203 | void ConcurrentMarkSweepThread::print_all_on(outputStream* st) { |
duke@435 | 204 | if (_cmst != NULL) { |
duke@435 | 205 | _cmst->print_on(st); |
duke@435 | 206 | } |
duke@435 | 207 | if (_collector != NULL) { |
duke@435 | 208 | AbstractWorkGang* gang = _collector->conc_workers(); |
duke@435 | 209 | if (gang != NULL) { |
duke@435 | 210 | gang->print_worker_threads_on(st); |
duke@435 | 211 | } |
duke@435 | 212 | } |
duke@435 | 213 | } |
duke@435 | 214 | |
duke@435 | 215 | void ConcurrentMarkSweepThread::synchronize(bool is_cms_thread) { |
duke@435 | 216 | assert(UseConcMarkSweepGC, "just checking"); |
duke@435 | 217 | |
duke@435 | 218 | MutexLockerEx x(CGC_lock, |
duke@435 | 219 | Mutex::_no_safepoint_check_flag); |
duke@435 | 220 | if (!is_cms_thread) { |
duke@435 | 221 | assert(Thread::current()->is_VM_thread(), "Not a VM thread"); |
duke@435 | 222 | CMSSynchronousYieldRequest yr; |
duke@435 | 223 | while (CMS_flag_is_set(CMS_cms_has_token)) { |
duke@435 | 224 | // indicate that we want to get the token |
duke@435 | 225 | set_CMS_flag(CMS_vm_wants_token); |
duke@435 | 226 | CGC_lock->wait(true); |
duke@435 | 227 | } |
duke@435 | 228 | // claim the token and proceed |
duke@435 | 229 | clear_CMS_flag(CMS_vm_wants_token); |
duke@435 | 230 | set_CMS_flag(CMS_vm_has_token); |
duke@435 | 231 | } else { |
duke@435 | 232 | assert(Thread::current()->is_ConcurrentGC_thread(), |
duke@435 | 233 | "Not a CMS thread"); |
duke@435 | 234 | // The following barrier assumes there's only one CMS thread. |
duke@435 | 235 | // This will need to be modified is there are more CMS threads than one. |
duke@435 | 236 | while (CMS_flag_is_set(CMS_vm_has_token | CMS_vm_wants_token)) { |
duke@435 | 237 | set_CMS_flag(CMS_cms_wants_token); |
duke@435 | 238 | CGC_lock->wait(true); |
duke@435 | 239 | } |
duke@435 | 240 | // claim the token |
duke@435 | 241 | clear_CMS_flag(CMS_cms_wants_token); |
duke@435 | 242 | set_CMS_flag(CMS_cms_has_token); |
duke@435 | 243 | } |
duke@435 | 244 | } |
duke@435 | 245 | |
duke@435 | 246 | void ConcurrentMarkSweepThread::desynchronize(bool is_cms_thread) { |
duke@435 | 247 | assert(UseConcMarkSweepGC, "just checking"); |
duke@435 | 248 | |
duke@435 | 249 | MutexLockerEx x(CGC_lock, |
duke@435 | 250 | Mutex::_no_safepoint_check_flag); |
duke@435 | 251 | if (!is_cms_thread) { |
duke@435 | 252 | assert(Thread::current()->is_VM_thread(), "Not a VM thread"); |
duke@435 | 253 | assert(CMS_flag_is_set(CMS_vm_has_token), "just checking"); |
duke@435 | 254 | clear_CMS_flag(CMS_vm_has_token); |
duke@435 | 255 | if (CMS_flag_is_set(CMS_cms_wants_token)) { |
duke@435 | 256 | // wake-up a waiting CMS thread |
duke@435 | 257 | CGC_lock->notify(); |
duke@435 | 258 | } |
duke@435 | 259 | assert(!CMS_flag_is_set(CMS_vm_has_token | CMS_vm_wants_token), |
duke@435 | 260 | "Should have been cleared"); |
duke@435 | 261 | } else { |
duke@435 | 262 | assert(Thread::current()->is_ConcurrentGC_thread(), |
duke@435 | 263 | "Not a CMS thread"); |
duke@435 | 264 | assert(CMS_flag_is_set(CMS_cms_has_token), "just checking"); |
duke@435 | 265 | clear_CMS_flag(CMS_cms_has_token); |
duke@435 | 266 | if (CMS_flag_is_set(CMS_vm_wants_token)) { |
duke@435 | 267 | // wake-up a waiting VM thread |
duke@435 | 268 | CGC_lock->notify(); |
duke@435 | 269 | } |
duke@435 | 270 | assert(!CMS_flag_is_set(CMS_cms_has_token | CMS_cms_wants_token), |
duke@435 | 271 | "Should have been cleared"); |
duke@435 | 272 | } |
duke@435 | 273 | } |
duke@435 | 274 | |
duke@435 | 275 | // Wait until the next synchronous GC or a timeout, whichever is earlier. |
duke@435 | 276 | void ConcurrentMarkSweepThread::wait_on_cms_lock(long t) { |
duke@435 | 277 | MutexLockerEx x(CGC_lock, |
duke@435 | 278 | Mutex::_no_safepoint_check_flag); |
duke@435 | 279 | set_CMS_flag(CMS_cms_wants_token); // to provoke notifies |
duke@435 | 280 | CGC_lock->wait(Mutex::_no_safepoint_check_flag, t); |
duke@435 | 281 | clear_CMS_flag(CMS_cms_wants_token); |
duke@435 | 282 | assert(!CMS_flag_is_set(CMS_cms_has_token | CMS_cms_wants_token), |
duke@435 | 283 | "Should not be set"); |
duke@435 | 284 | } |
duke@435 | 285 | |
duke@435 | 286 | void ConcurrentMarkSweepThread::sleepBeforeNextCycle() { |
duke@435 | 287 | while (!_should_terminate) { |
duke@435 | 288 | if (CMSIncrementalMode) { |
duke@435 | 289 | icms_wait(); |
duke@435 | 290 | return; |
duke@435 | 291 | } else { |
duke@435 | 292 | // Wait until the next synchronous GC or a timeout, whichever is earlier |
duke@435 | 293 | wait_on_cms_lock(CMSWaitDuration); |
duke@435 | 294 | } |
duke@435 | 295 | // Check if we should start a CMS collection cycle |
duke@435 | 296 | if (_collector->shouldConcurrentCollect()) { |
duke@435 | 297 | return; |
duke@435 | 298 | } |
duke@435 | 299 | // .. collection criterion not yet met, let's go back |
duke@435 | 300 | // and wait some more |
duke@435 | 301 | } |
duke@435 | 302 | } |
duke@435 | 303 | |
duke@435 | 304 | // Incremental CMS |
duke@435 | 305 | void ConcurrentMarkSweepThread::start_icms() { |
duke@435 | 306 | assert(UseConcMarkSweepGC && CMSIncrementalMode, "just checking"); |
duke@435 | 307 | MutexLockerEx x(iCMS_lock, Mutex::_no_safepoint_check_flag); |
duke@435 | 308 | trace_state("start_icms"); |
duke@435 | 309 | _should_run = true; |
duke@435 | 310 | iCMS_lock->notify_all(); |
duke@435 | 311 | } |
duke@435 | 312 | |
duke@435 | 313 | void ConcurrentMarkSweepThread::stop_icms() { |
duke@435 | 314 | assert(UseConcMarkSweepGC && CMSIncrementalMode, "just checking"); |
duke@435 | 315 | MutexLockerEx x(iCMS_lock, Mutex::_no_safepoint_check_flag); |
duke@435 | 316 | if (!_should_stop) { |
duke@435 | 317 | trace_state("stop_icms"); |
duke@435 | 318 | _should_stop = true; |
duke@435 | 319 | _should_run = false; |
duke@435 | 320 | asynchronous_yield_request(); |
duke@435 | 321 | iCMS_lock->notify_all(); |
duke@435 | 322 | } |
duke@435 | 323 | } |
duke@435 | 324 | |
duke@435 | 325 | void ConcurrentMarkSweepThread::icms_wait() { |
duke@435 | 326 | assert(UseConcMarkSweepGC && CMSIncrementalMode, "just checking"); |
duke@435 | 327 | if (_should_stop && icms_enabled()) { |
duke@435 | 328 | MutexLockerEx x(iCMS_lock, Mutex::_no_safepoint_check_flag); |
duke@435 | 329 | trace_state("pause_icms"); |
duke@435 | 330 | _collector->stats().stop_cms_timer(); |
duke@435 | 331 | while(!_should_run && icms_enabled()) { |
duke@435 | 332 | iCMS_lock->wait(Mutex::_no_safepoint_check_flag); |
duke@435 | 333 | } |
duke@435 | 334 | _collector->stats().start_cms_timer(); |
duke@435 | 335 | _should_stop = false; |
duke@435 | 336 | trace_state("pause_icms end"); |
duke@435 | 337 | } |
duke@435 | 338 | } |
duke@435 | 339 | |
duke@435 | 340 | // Note: this method, although exported by the ConcurrentMarkSweepThread, |
duke@435 | 341 | // which is a non-JavaThread, can only be called by a JavaThread. |
duke@435 | 342 | // Currently this is done at vm creation time (post-vm-init) by the |
duke@435 | 343 | // main/Primordial (Java)Thread. |
duke@435 | 344 | // XXX Consider changing this in the future to allow the CMS thread |
duke@435 | 345 | // itself to create this thread? |
duke@435 | 346 | void ConcurrentMarkSweepThread::makeSurrogateLockerThread(TRAPS) { |
duke@435 | 347 | assert(UseConcMarkSweepGC, "SLT thread needed only for CMS GC"); |
duke@435 | 348 | assert(_slt == NULL, "SLT already created"); |
duke@435 | 349 | _slt = SurrogateLockerThread::make(THREAD); |
duke@435 | 350 | } |