comparison src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp @ 2132:4947ee68d19c

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