comparison src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp @ 2137:ffd725ff6943

Merge
author johnc
date Thu, 13 Jan 2011 17:19:21 -0800
parents 7246a374a9f2 c91cc404ca46
children 9afee0b9fc1d
comparison
equal deleted inserted replaced
2131:856ecff79cf7 2137:ffd725ff6943
7877 gclog_or_tty->print("\n====================\nStarting new sweep\n"); 7877 gclog_or_tty->print("\n====================\nStarting new sweep\n");
7878 } 7878 }
7879 } 7879 }
7880 7880
7881 // We need this destructor to reclaim any space at the end 7881 // We need this destructor to reclaim any space at the end
7882 // of the space, which do_blk below may not have added back to 7882 // of the space, which do_blk below may not yet have added back to
7883 // the free lists. [basically dealing with the "fringe effect"] 7883 // the free lists.
7884 SweepClosure::~SweepClosure() { 7884 SweepClosure::~SweepClosure() {
7885 assert_lock_strong(_freelistLock); 7885 assert_lock_strong(_freelistLock);
7886 // this should be treated as the end of a free run if any 7886 assert(_limit >= _sp->bottom() && _limit <= _sp->end(),
7887 // The current free range should be returned to the free lists 7887 "sweep _limit out of bounds");
7888 // as one coalesced chunk. 7888 // Flush any remaining coterminal free run as a single
7889 // coalesced chunk to the appropriate free list.
7889 if (inFreeRange()) { 7890 if (inFreeRange()) {
7890 flushCurFreeChunk(freeFinger(), 7891 assert(freeFinger() < _limit, "freeFinger points too high");
7891 pointer_delta(_limit, freeFinger())); 7892 flush_cur_free_chunk(freeFinger(), pointer_delta(_limit, freeFinger()));
7892 assert(freeFinger() < _limit, "the finger pointeth off base");
7893 if (CMSTraceSweeper) { 7893 if (CMSTraceSweeper) {
7894 gclog_or_tty->print("destructor:"); 7894 gclog_or_tty->print("Sweep: last chunk: ");
7895 gclog_or_tty->print("Sweep:put_free_blk 0x%x ("SIZE_FORMAT") " 7895 gclog_or_tty->print("put_free_blk 0x%x ("SIZE_FORMAT") [coalesced:"SIZE_FORMAT"]\n",
7896 "[coalesced:"SIZE_FORMAT"]\n", 7896 freeFinger(), pointer_delta(_limit, freeFinger()), lastFreeRangeCoalesced());
7897 freeFinger(), pointer_delta(_limit, freeFinger()), 7897 }
7898 lastFreeRangeCoalesced()); 7898 } // else nothing to flush
7899 }
7900 }
7901 NOT_PRODUCT( 7899 NOT_PRODUCT(
7902 if (Verbose && PrintGC) { 7900 if (Verbose && PrintGC) {
7903 gclog_or_tty->print("Collected "SIZE_FORMAT" objects, " 7901 gclog_or_tty->print("Collected "SIZE_FORMAT" objects, "
7904 SIZE_FORMAT " bytes", 7902 SIZE_FORMAT " bytes",
7905 _numObjectsFreed, _numWordsFreed*sizeof(HeapWord)); 7903 _numObjectsFreed, _numWordsFreed*sizeof(HeapWord));
7932 } 7930 }
7933 7931
7934 void SweepClosure::initialize_free_range(HeapWord* freeFinger, 7932 void SweepClosure::initialize_free_range(HeapWord* freeFinger,
7935 bool freeRangeInFreeLists) { 7933 bool freeRangeInFreeLists) {
7936 if (CMSTraceSweeper) { 7934 if (CMSTraceSweeper) {
7937 gclog_or_tty->print("---- Start free range 0x%x with free block [%d] (%d)\n", 7935 gclog_or_tty->print("---- Start free range at 0x%x with free block (%d)\n",
7938 freeFinger, _sp->block_size(freeFinger), 7936 freeFinger, freeRangeInFreeLists);
7939 freeRangeInFreeLists);
7940 } 7937 }
7941 assert(!inFreeRange(), "Trampling existing free range"); 7938 assert(!inFreeRange(), "Trampling existing free range");
7942 set_inFreeRange(true); 7939 set_inFreeRange(true);
7943 set_lastFreeRangeCoalesced(false); 7940 set_lastFreeRangeCoalesced(false);
7944 7941
7989 // than "addr == _limit" because although _limit was a block boundary when 7986 // than "addr == _limit" because although _limit was a block boundary when
7990 // we started the sweep, it may no longer be one because heap expansion 7987 // we started the sweep, it may no longer be one because heap expansion
7991 // may have caused us to coalesce the block ending at the address _limit 7988 // may have caused us to coalesce the block ending at the address _limit
7992 // with a newly expanded chunk (this happens when _limit was set to the 7989 // with a newly expanded chunk (this happens when _limit was set to the
7993 // previous _end of the space), so we may have stepped past _limit; see CR 6977970. 7990 // previous _end of the space), so we may have stepped past _limit; see CR 6977970.
7994 if (addr >= _limit) { // we have swept up to or past the limit, do nothing more 7991 if (addr >= _limit) { // we have swept up to or past the limit: finish up
7995 assert(_limit >= _sp->bottom() && _limit <= _sp->end(), 7992 assert(_limit >= _sp->bottom() && _limit <= _sp->end(),
7996 "sweep _limit out of bounds"); 7993 "sweep _limit out of bounds");
7997 assert(addr < _sp->end(), "addr out of bounds"); 7994 assert(addr < _sp->end(), "addr out of bounds");
7998 // help the closure application finish 7995 // Flush any remaining coterminal free run as a single
7996 // coalesced chunk to the appropriate free list.
7997 if (inFreeRange()) {
7998 assert(freeFinger() < _limit, "finger points too high");
7999 flush_cur_free_chunk(freeFinger(),
8000 pointer_delta(addr, freeFinger()));
8001 if (CMSTraceSweeper) {
8002 gclog_or_tty->print("Sweep: last chunk: ");
8003 gclog_or_tty->print("put_free_blk 0x%x ("SIZE_FORMAT") "
8004 "[coalesced:"SIZE_FORMAT"]\n",
8005 freeFinger(), pointer_delta(addr, freeFinger()),
8006 lastFreeRangeCoalesced());
8007 }
8008 }
8009
8010 // help the iterator loop finish
7999 return pointer_delta(_sp->end(), addr); 8011 return pointer_delta(_sp->end(), addr);
8000 } 8012 }
8013
8001 assert(addr < _limit, "sweep invariant"); 8014 assert(addr < _limit, "sweep invariant");
8002
8003 // check if we should yield 8015 // check if we should yield
8004 do_yield_check(addr); 8016 do_yield_check(addr);
8005 if (fc->isFree()) { 8017 if (fc->isFree()) {
8006 // Chunk that is already free 8018 // Chunk that is already free
8007 res = fc->size(); 8019 res = fc->size();
8008 doAlreadyFreeChunk(fc); 8020 do_already_free_chunk(fc);
8009 debug_only(_sp->verifyFreeLists()); 8021 debug_only(_sp->verifyFreeLists());
8010 assert(res == fc->size(), "Don't expect the size to change"); 8022 assert(res == fc->size(), "Don't expect the size to change");
8011 NOT_PRODUCT( 8023 NOT_PRODUCT(
8012 _numObjectsAlreadyFree++; 8024 _numObjectsAlreadyFree++;
8013 _numWordsAlreadyFree += res; 8025 _numWordsAlreadyFree += res;
8014 ) 8026 )
8015 NOT_PRODUCT(_last_fc = fc;) 8027 NOT_PRODUCT(_last_fc = fc;)
8016 } else if (!_bitMap->isMarked(addr)) { 8028 } else if (!_bitMap->isMarked(addr)) {
8017 // Chunk is fresh garbage 8029 // Chunk is fresh garbage
8018 res = doGarbageChunk(fc); 8030 res = do_garbage_chunk(fc);
8019 debug_only(_sp->verifyFreeLists()); 8031 debug_only(_sp->verifyFreeLists());
8020 NOT_PRODUCT( 8032 NOT_PRODUCT(
8021 _numObjectsFreed++; 8033 _numObjectsFreed++;
8022 _numWordsFreed += res; 8034 _numWordsFreed += res;
8023 ) 8035 )
8024 } else { 8036 } else {
8025 // Chunk that is alive. 8037 // Chunk that is alive.
8026 res = doLiveChunk(fc); 8038 res = do_live_chunk(fc);
8027 debug_only(_sp->verifyFreeLists()); 8039 debug_only(_sp->verifyFreeLists());
8028 NOT_PRODUCT( 8040 NOT_PRODUCT(
8029 _numObjectsLive++; 8041 _numObjectsLive++;
8030 _numWordsLive += res; 8042 _numWordsLive += res;
8031 ) 8043 )
8074 // a chunk of an overpopulated (currently more chunks than desired) size may 8086 // a chunk of an overpopulated (currently more chunks than desired) size may
8075 // be chosen. The "hint" associated with a free list, if non-null, points 8087 // be chosen. The "hint" associated with a free list, if non-null, points
8076 // to a free list which may be overpopulated. 8088 // to a free list which may be overpopulated.
8077 // 8089 //
8078 8090
8079 void SweepClosure::doAlreadyFreeChunk(FreeChunk* fc) { 8091 void SweepClosure::do_already_free_chunk(FreeChunk* fc) {
8080 size_t size = fc->size(); 8092 size_t size = fc->size();
8081 // Chunks that cannot be coalesced are not in the 8093 // Chunks that cannot be coalesced are not in the
8082 // free lists. 8094 // free lists.
8083 if (CMSTestInFreeList && !fc->cantCoalesce()) { 8095 if (CMSTestInFreeList && !fc->cantCoalesce()) {
8084 assert(_sp->verifyChunkInFreeLists(fc), 8096 assert(_sp->verifyChunkInFreeLists(fc),
8090 assert(!_bitMap->isMarked(addr), "free chunk should be unmarked"); 8102 assert(!_bitMap->isMarked(addr), "free chunk should be unmarked");
8091 // Verify that the bit map has no bits marked between 8103 // Verify that the bit map has no bits marked between
8092 // addr and purported end of this block. 8104 // addr and purported end of this block.
8093 _bitMap->verifyNoOneBitsInRange(addr + 1, addr + size); 8105 _bitMap->verifyNoOneBitsInRange(addr + 1, addr + size);
8094 8106
8095 // Some chunks cannot be coalesced in under any circumstances. 8107 // Some chunks cannot be coalesced under any circumstances.
8096 // See the definition of cantCoalesce(). 8108 // See the definition of cantCoalesce().
8097 if (!fc->cantCoalesce()) { 8109 if (!fc->cantCoalesce()) {
8098 // This chunk can potentially be coalesced. 8110 // This chunk can potentially be coalesced.
8099 if (_sp->adaptive_freelists()) { 8111 if (_sp->adaptive_freelists()) {
8100 // All the work is done in 8112 // All the work is done in
8101 doPostIsFreeOrGarbageChunk(fc, size); 8113 do_post_free_or_garbage_chunk(fc, size);
8102 } else { // Not adaptive free lists 8114 } else { // Not adaptive free lists
8103 // this is a free chunk that can potentially be coalesced by the sweeper; 8115 // this is a free chunk that can potentially be coalesced by the sweeper;
8104 if (!inFreeRange()) { 8116 if (!inFreeRange()) {
8105 // if the next chunk is a free block that can't be coalesced 8117 // if the next chunk is a free block that can't be coalesced
8106 // it doesn't make sense to remove this chunk from the free lists 8118 // it doesn't make sense to remove this chunk from the free lists
8107 FreeChunk* nextChunk = (FreeChunk*)(addr + size); 8119 FreeChunk* nextChunk = (FreeChunk*)(addr + size);
8108 assert((HeapWord*)nextChunk <= _limit, "sweep invariant"); 8120 assert((HeapWord*)nextChunk <= _sp->end(), "Chunk size out of bounds?");
8109 if ((HeapWord*)nextChunk < _limit && // there's a next chunk... 8121 if ((HeapWord*)nextChunk < _sp->end() && // There is another free chunk to the right ...
8110 nextChunk->isFree() && // which is free... 8122 nextChunk->isFree() && // ... which is free...
8111 nextChunk->cantCoalesce()) { // ... but cant be coalesced 8123 nextChunk->cantCoalesce()) { // ... but can't be coalesced
8112 // nothing to do 8124 // nothing to do
8113 } else { 8125 } else {
8114 // Potentially the start of a new free range: 8126 // Potentially the start of a new free range:
8115 // Don't eagerly remove it from the free lists. 8127 // Don't eagerly remove it from the free lists.
8116 // No need to remove it if it will just be put 8128 // No need to remove it if it will just be put
8152 8164
8153 // cant coalesce with previous block; this should be treated 8165 // cant coalesce with previous block; this should be treated
8154 // as the end of a free run if any 8166 // as the end of a free run if any
8155 if (inFreeRange()) { 8167 if (inFreeRange()) {
8156 // we kicked some butt; time to pick up the garbage 8168 // we kicked some butt; time to pick up the garbage
8157 assert(freeFinger() < addr, "the finger pointeth off base"); 8169 assert(freeFinger() < addr, "freeFinger points too high");
8158 flushCurFreeChunk(freeFinger(), pointer_delta(addr, freeFinger())); 8170 flush_cur_free_chunk(freeFinger(), pointer_delta(addr, freeFinger()));
8159 } 8171 }
8160 // else, nothing to do, just continue 8172 // else, nothing to do, just continue
8161 } 8173 }
8162 } 8174 }
8163 8175
8164 size_t SweepClosure::doGarbageChunk(FreeChunk* fc) { 8176 size_t SweepClosure::do_garbage_chunk(FreeChunk* fc) {
8165 // This is a chunk of garbage. It is not in any free list. 8177 // This is a chunk of garbage. It is not in any free list.
8166 // Add it to a free list or let it possibly be coalesced into 8178 // Add it to a free list or let it possibly be coalesced into
8167 // a larger chunk. 8179 // a larger chunk.
8168 HeapWord* addr = (HeapWord*) fc; 8180 HeapWord* addr = (HeapWord*) fc;
8169 size_t size = CompactibleFreeListSpace::adjustObjectSize(oop(addr)->size()); 8181 size_t size = CompactibleFreeListSpace::adjustObjectSize(oop(addr)->size());
8171 if (_sp->adaptive_freelists()) { 8183 if (_sp->adaptive_freelists()) {
8172 // Verify that the bit map has no bits marked between 8184 // Verify that the bit map has no bits marked between
8173 // addr and purported end of just dead object. 8185 // addr and purported end of just dead object.
8174 _bitMap->verifyNoOneBitsInRange(addr + 1, addr + size); 8186 _bitMap->verifyNoOneBitsInRange(addr + 1, addr + size);
8175 8187
8176 doPostIsFreeOrGarbageChunk(fc, size); 8188 do_post_free_or_garbage_chunk(fc, size);
8177 } else { 8189 } else {
8178 if (!inFreeRange()) { 8190 if (!inFreeRange()) {
8179 // start of a new free range 8191 // start of a new free range
8180 assert(size > 0, "A free range should have a size"); 8192 assert(size > 0, "A free range should have a size");
8181 initialize_free_range(addr, false); 8193 initialize_free_range(addr, false);
8210 _bitMap->verifyNoOneBitsInRange(addr + 1, addr + size); 8222 _bitMap->verifyNoOneBitsInRange(addr + 1, addr + size);
8211 } 8223 }
8212 return size; 8224 return size;
8213 } 8225 }
8214 8226
8215 size_t SweepClosure::doLiveChunk(FreeChunk* fc) { 8227 size_t SweepClosure::do_live_chunk(FreeChunk* fc) {
8216 HeapWord* addr = (HeapWord*) fc; 8228 HeapWord* addr = (HeapWord*) fc;
8217 // The sweeper has just found a live object. Return any accumulated 8229 // The sweeper has just found a live object. Return any accumulated
8218 // left hand chunk to the free lists. 8230 // left hand chunk to the free lists.
8219 if (inFreeRange()) { 8231 if (inFreeRange()) {
8220 if (_sp->adaptive_freelists()) { 8232 assert(freeFinger() < addr, "freeFinger points too high");
8221 flushCurFreeChunk(freeFinger(), 8233 flush_cur_free_chunk(freeFinger(), pointer_delta(addr, freeFinger()));
8222 pointer_delta(addr, freeFinger())); 8234 }
8223 } else { // not adaptive freelists 8235
8224 set_inFreeRange(false); 8236 // This object is live: we'd normally expect this to be
8225 // Add the free range back to the free list if it is not already
8226 // there.
8227 if (!freeRangeInFreeLists()) {
8228 assert(freeFinger() < addr, "the finger pointeth off base");
8229 if (CMSTraceSweeper) {
8230 gclog_or_tty->print("Sweep:put_free_blk 0x%x (%d) "
8231 "[coalesced:%d]\n",
8232 freeFinger(), pointer_delta(addr, freeFinger()),
8233 lastFreeRangeCoalesced());
8234 }
8235 _sp->addChunkAndRepairOffsetTable(freeFinger(),
8236 pointer_delta(addr, freeFinger()), lastFreeRangeCoalesced());
8237 }
8238 }
8239 }
8240
8241 // Common code path for original and adaptive free lists.
8242
8243 // this object is live: we'd normally expect this to be
8244 // an oop, and like to assert the following: 8237 // an oop, and like to assert the following:
8245 // assert(oop(addr)->is_oop(), "live block should be an oop"); 8238 // assert(oop(addr)->is_oop(), "live block should be an oop");
8246 // However, as we commented above, this may be an object whose 8239 // However, as we commented above, this may be an object whose
8247 // header hasn't yet been initialized. 8240 // header hasn't yet been initialized.
8248 size_t size; 8241 size_t size;
8253 HeapWord* nextOneAddr = _bitMap->getNextMarkedWordAddress(addr + 2); 8246 HeapWord* nextOneAddr = _bitMap->getNextMarkedWordAddress(addr + 2);
8254 size = pointer_delta(nextOneAddr + 1, addr); 8247 size = pointer_delta(nextOneAddr + 1, addr);
8255 assert(size == CompactibleFreeListSpace::adjustObjectSize(size), 8248 assert(size == CompactibleFreeListSpace::adjustObjectSize(size),
8256 "alignment problem"); 8249 "alignment problem");
8257 8250
8258 #ifdef DEBUG 8251 #ifdef DEBUG
8259 if (oop(addr)->klass_or_null() != NULL && 8252 if (oop(addr)->klass_or_null() != NULL &&
8260 ( !_collector->should_unload_classes() 8253 ( !_collector->should_unload_classes()
8261 || (oop(addr)->is_parsable()) && 8254 || (oop(addr)->is_parsable()) &&
8262 oop(addr)->is_conc_safe())) { 8255 oop(addr)->is_conc_safe())) {
8263 // Ignore mark word because we are running concurrent with mutators 8256 // Ignore mark word because we are running concurrent with mutators
8267 // the return from size() correct. 8260 // the return from size() correct.
8268 assert(size == 8261 assert(size ==
8269 CompactibleFreeListSpace::adjustObjectSize(oop(addr)->size()), 8262 CompactibleFreeListSpace::adjustObjectSize(oop(addr)->size()),
8270 "P-mark and computed size do not agree"); 8263 "P-mark and computed size do not agree");
8271 } 8264 }
8272 #endif 8265 #endif
8273 8266
8274 } else { 8267 } else {
8275 // This should be an initialized object that's alive. 8268 // This should be an initialized object that's alive.
8276 assert(oop(addr)->klass_or_null() != NULL && 8269 assert(oop(addr)->klass_or_null() != NULL &&
8277 (!_collector->should_unload_classes() 8270 (!_collector->should_unload_classes()
8294 DEBUG_ONLY(_bitMap->verifyNoOneBitsInRange(addr+2, addr+size);) 8287 DEBUG_ONLY(_bitMap->verifyNoOneBitsInRange(addr+2, addr+size);)
8295 } 8288 }
8296 return size; 8289 return size;
8297 } 8290 }
8298 8291
8299 void SweepClosure::doPostIsFreeOrGarbageChunk(FreeChunk* fc, 8292 void SweepClosure::do_post_free_or_garbage_chunk(FreeChunk* fc,
8300 size_t chunkSize) { 8293 size_t chunkSize) {
8301 // doPostIsFreeOrGarbageChunk() should only be called in the smart allocation 8294 // do_post_free_or_garbage_chunk() should only be called in the case
8302 // scheme. 8295 // of the adaptive free list allocator.
8303 bool fcInFreeLists = fc->isFree(); 8296 bool fcInFreeLists = fc->isFree();
8304 assert(_sp->adaptive_freelists(), "Should only be used in this case."); 8297 assert(_sp->adaptive_freelists(), "Should only be used in this case.");
8305 assert((HeapWord*)fc <= _limit, "sweep invariant"); 8298 assert((HeapWord*)fc <= _limit, "sweep invariant");
8306 if (CMSTestInFreeList && fcInFreeLists) { 8299 if (CMSTestInFreeList && fcInFreeLists) {
8307 assert(_sp->verifyChunkInFreeLists(fc), 8300 assert(_sp->verifyChunkInFreeLists(fc), "free chunk is not in free lists");
8308 "free chunk is not in free lists"); 8301 }
8309 }
8310
8311 8302
8312 if (CMSTraceSweeper) { 8303 if (CMSTraceSweeper) {
8313 gclog_or_tty->print_cr(" -- pick up another chunk at 0x%x (%d)", fc, chunkSize); 8304 gclog_or_tty->print_cr(" -- pick up another chunk at 0x%x (%d)", fc, chunkSize);
8314 } 8305 }
8315 8306
8378 } else { // not in a free range and/or should not coalesce 8369 } else { // not in a free range and/or should not coalesce
8379 // Return the current free range and start a new one. 8370 // Return the current free range and start a new one.
8380 if (inFreeRange()) { 8371 if (inFreeRange()) {
8381 // In a free range but cannot coalesce with the right hand chunk. 8372 // In a free range but cannot coalesce with the right hand chunk.
8382 // Put the current free range into the free lists. 8373 // Put the current free range into the free lists.
8383 flushCurFreeChunk(freeFinger(), 8374 flush_cur_free_chunk(freeFinger(),
8384 pointer_delta(addr, freeFinger())); 8375 pointer_delta(addr, freeFinger()));
8385 } 8376 }
8386 // Set up for new free range. Pass along whether the right hand 8377 // Set up for new free range. Pass along whether the right hand
8387 // chunk is in the free lists. 8378 // chunk is in the free lists.
8388 initialize_free_range((HeapWord*)fc, fcInFreeLists); 8379 initialize_free_range((HeapWord*)fc, fcInFreeLists);
8389 } 8380 }
8390 } 8381 }
8391 void SweepClosure::flushCurFreeChunk(HeapWord* chunk, size_t size) { 8382
8383 void SweepClosure::flush_cur_free_chunk(HeapWord* chunk, size_t size) {
8392 assert(inFreeRange(), "Should only be called if currently in a free range."); 8384 assert(inFreeRange(), "Should only be called if currently in a free range.");
8393 assert(size > 0, 8385 assert(size > 0,
8394 "A zero sized chunk cannot be added to the free lists."); 8386 "A zero sized chunk cannot be added to the free lists.");
8395 if (!freeRangeInFreeLists()) { 8387 if (!freeRangeInFreeLists()) {
8396 if(CMSTestInFreeList) { 8388 if (CMSTestInFreeList) {
8397 FreeChunk* fc = (FreeChunk*) chunk; 8389 FreeChunk* fc = (FreeChunk*) chunk;
8398 fc->setSize(size); 8390 fc->setSize(size);
8399 assert(!_sp->verifyChunkInFreeLists(fc), 8391 assert(!_sp->verifyChunkInFreeLists(fc),
8400 "chunk should not be in free lists yet"); 8392 "chunk should not be in free lists yet");
8401 } 8393 }
8426 // free block encountered will start a coalescing range of 8418 // free block encountered will start a coalescing range of
8427 // free blocks. If the next free block is adjacent to the 8419 // free blocks. If the next free block is adjacent to the
8428 // chunk just flushed, they will need to wait for the next 8420 // chunk just flushed, they will need to wait for the next
8429 // sweep to be coalesced. 8421 // sweep to be coalesced.
8430 if (inFreeRange()) { 8422 if (inFreeRange()) {
8431 flushCurFreeChunk(freeFinger(), pointer_delta(addr, freeFinger())); 8423 flush_cur_free_chunk(freeFinger(), pointer_delta(addr, freeFinger()));
8432 } 8424 }
8433 8425
8434 // First give up the locks, then yield, then re-lock. 8426 // First give up the locks, then yield, then re-lock.
8435 // We should probably use a constructor/destructor idiom to 8427 // We should probably use a constructor/destructor idiom to
8436 // do this unlock/lock or modify the MutexUnlocker class to 8428 // do this unlock/lock or modify the MutexUnlocker class to