diff --git a/compiler-rt/lib/scudo/standalone/primary64.h b/compiler-rt/lib/scudo/standalone/primary64.h --- a/compiler-rt/lib/scudo/standalone/primary64.h +++ b/compiler-rt/lib/scudo/standalone/primary64.h @@ -101,17 +101,39 @@ TransferBatch *popBatch(CacheT *C, uptr ClassId) { DCHECK_LT(ClassId, NumClasses); RegionInfo *Region = getRegionInfo(ClassId); - ScopedLock L(Region->Mutex); - TransferBatch *B = popBatchImpl(C, ClassId, Region); - if (UNLIKELY(!B)) { - if (UNLIKELY(!populateFreeList(C, ClassId, Region))) - return nullptr; - B = popBatchImpl(C, ClassId, Region); - // if `populateFreeList` succeeded, we are supposed to get free blocks. - DCHECK_NE(B, nullptr); + bool PrintStats = false; + { + ScopedLock L(Region->Mutex); + TransferBatch *B = popBatchImpl(C, ClassId, Region); + if (LIKELY(B)) { + Region->Stats.PoppedBlocks += B->getCount(); + return B; + } + + bool RegionHasExhausted = Region->Exhausted; + if (UNLIKELY(RegionHasExhausted || + !populateFreeList(C, ClassId, Region))) { + PrintStats = !RegionHasExhausted && Region->Exhausted; + } else { + B = popBatchImpl(C, ClassId, Region); + // if `populateFreeList` succeeded, we are supposed to get free blocks. + DCHECK_NE(B, nullptr); + Region->Stats.PoppedBlocks += B->getCount(); + return B; + } } - Region->Stats.PoppedBlocks += B->getCount(); - return B; + + // Note that `getStats()` requires the lock of each region so we can't call + // it while locking the Region->Mutex in the above. + if (PrintStats) { + ScopedString Str; + getStats(&Str); + Str.append( + "Scudo OOM: The process has exhausted %zuM for size class %zu.\n", + RegionSize >> 20, getSizeByClassId(ClassId)); + Str.output(); + } + return nullptr; } // Push the array of free blocks to the designated batch group. @@ -121,17 +143,40 @@ RegionInfo *Region = getRegionInfo(ClassId); if (ClassId == SizeClassMap::BatchClassId) { - ScopedLock L(Region->Mutex); - // Constructing a batch group in the free list will use two blocks in - // BatchClassId. If we are pushing BatchClassId blocks, we will use the - // blocks in the array directly (can't delegate local cache which will - // cause a recursive allocation). However, The number of free blocks may - // be less than two. Therefore, populate the free list before inserting - // the blocks. - if (Size == 1 && UNLIKELY(!populateFreeList(C, ClassId, Region))) - return; - pushBlocksImpl(C, ClassId, Region, Array, Size); - Region->Stats.PushedBlocks += Size; + bool PrintStats = false; + ; + { + ScopedLock L(Region->Mutex); + // Constructing a batch group in the free list will use two blocks in + // BatchClassId. If we are pushing BatchClassId blocks, we will use the + // blocks in the array directly (can't delegate local cache which will + // cause a recursive allocation). However, The number of free blocks may + // be less than two. Therefore, populate the free list before inserting + // the blocks. + if (Size >= 2U) { + pushBlocksImpl(C, SizeClassMap::BatchClassId, Region, Array, Size); + Region->Stats.PushedBlocks += Size; + } else { + bool RegionHasExhausted = Region->Exhausted; + if (UNLIKELY( + RegionHasExhausted || + !populateFreeList(C, SizeClassMap::BatchClassId, Region))) { + PrintStats = !RegionHasExhausted && Region->Exhausted; + } + } + } + + // Note that `getStats()` requires the lock of each region so we can't + // call it while locking the Region->Mutex in the above. Besides, we may + // consider to abort because the exhaustion of BatchClass is critical. + if (PrintStats) { + ScopedString Str; + getStats(&Str); + Str.append( + "Scudo OOM: The process has exhausted %zuM for size class %zu.\n", + RegionSize >> 20, getSizeByClassId(ClassId)); + Str.output(); + } return; } @@ -594,19 +639,7 @@ roundUpTo(TotalUserBytes - MappedUser, MapSizeIncrement); const uptr RegionBase = RegionBeg - getRegionBaseByClassId(ClassId); if (UNLIKELY(RegionBase + MappedUser + MapSize > RegionSize)) { - if (!Region->Exhausted) { - Region->Exhausted = true; - ScopedString Str; - // FIXME: getStats() needs to go over all the regions and will take - // the locks of them. Which means we will try to recursively acquire - // the `Region->Mutex` which is not supported. It will be better to - // log this somewhere else. - // getStats(&Str); - Str.append( - "Scudo OOM: The process has exhausted %zuM for size class %zu.\n", - RegionSize >> 20, Size); - Str.output(); - } + Region->Exhausted = true; return false; } if (MappedUser == 0)