1*76559068SAndroid Build Coastguard Worker //===-- quarantine.h --------------------------------------------*- C++ -*-===// 2*76559068SAndroid Build Coastguard Worker // 3*76559068SAndroid Build Coastguard Worker // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*76559068SAndroid Build Coastguard Worker // See https://llvm.org/LICENSE.txt for license information. 5*76559068SAndroid Build Coastguard Worker // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*76559068SAndroid Build Coastguard Worker // 7*76559068SAndroid Build Coastguard Worker //===----------------------------------------------------------------------===// 8*76559068SAndroid Build Coastguard Worker 9*76559068SAndroid Build Coastguard Worker #ifndef SCUDO_QUARANTINE_H_ 10*76559068SAndroid Build Coastguard Worker #define SCUDO_QUARANTINE_H_ 11*76559068SAndroid Build Coastguard Worker 12*76559068SAndroid Build Coastguard Worker #include "list.h" 13*76559068SAndroid Build Coastguard Worker #include "mutex.h" 14*76559068SAndroid Build Coastguard Worker #include "string_utils.h" 15*76559068SAndroid Build Coastguard Worker #include "thread_annotations.h" 16*76559068SAndroid Build Coastguard Worker 17*76559068SAndroid Build Coastguard Worker namespace scudo { 18*76559068SAndroid Build Coastguard Worker 19*76559068SAndroid Build Coastguard Worker struct QuarantineBatch { 20*76559068SAndroid Build Coastguard Worker // With the following count, a batch (and the header that protects it) occupy 21*76559068SAndroid Build Coastguard Worker // 4096 bytes on 32-bit platforms, and 8192 bytes on 64-bit. 22*76559068SAndroid Build Coastguard Worker static const u32 MaxCount = 1019; 23*76559068SAndroid Build Coastguard Worker QuarantineBatch *Next; 24*76559068SAndroid Build Coastguard Worker uptr Size; 25*76559068SAndroid Build Coastguard Worker u32 Count; 26*76559068SAndroid Build Coastguard Worker void *Batch[MaxCount]; 27*76559068SAndroid Build Coastguard Worker initQuarantineBatch28*76559068SAndroid Build Coastguard Worker void init(void *Ptr, uptr Size) { 29*76559068SAndroid Build Coastguard Worker Count = 1; 30*76559068SAndroid Build Coastguard Worker Batch[0] = Ptr; 31*76559068SAndroid Build Coastguard Worker this->Size = Size + sizeof(QuarantineBatch); // Account for the Batch Size. 32*76559068SAndroid Build Coastguard Worker } 33*76559068SAndroid Build Coastguard Worker 34*76559068SAndroid Build Coastguard Worker // The total size of quarantined nodes recorded in this batch. getQuarantinedSizeQuarantineBatch35*76559068SAndroid Build Coastguard Worker uptr getQuarantinedSize() const { return Size - sizeof(QuarantineBatch); } 36*76559068SAndroid Build Coastguard Worker push_backQuarantineBatch37*76559068SAndroid Build Coastguard Worker void push_back(void *Ptr, uptr Size) { 38*76559068SAndroid Build Coastguard Worker DCHECK_LT(Count, MaxCount); 39*76559068SAndroid Build Coastguard Worker Batch[Count++] = Ptr; 40*76559068SAndroid Build Coastguard Worker this->Size += Size; 41*76559068SAndroid Build Coastguard Worker } 42*76559068SAndroid Build Coastguard Worker canMergeQuarantineBatch43*76559068SAndroid Build Coastguard Worker bool canMerge(const QuarantineBatch *const From) const { 44*76559068SAndroid Build Coastguard Worker return Count + From->Count <= MaxCount; 45*76559068SAndroid Build Coastguard Worker } 46*76559068SAndroid Build Coastguard Worker mergeQuarantineBatch47*76559068SAndroid Build Coastguard Worker void merge(QuarantineBatch *const From) { 48*76559068SAndroid Build Coastguard Worker DCHECK_LE(Count + From->Count, MaxCount); 49*76559068SAndroid Build Coastguard Worker DCHECK_GE(Size, sizeof(QuarantineBatch)); 50*76559068SAndroid Build Coastguard Worker 51*76559068SAndroid Build Coastguard Worker for (uptr I = 0; I < From->Count; ++I) 52*76559068SAndroid Build Coastguard Worker Batch[Count + I] = From->Batch[I]; 53*76559068SAndroid Build Coastguard Worker Count += From->Count; 54*76559068SAndroid Build Coastguard Worker Size += From->getQuarantinedSize(); 55*76559068SAndroid Build Coastguard Worker 56*76559068SAndroid Build Coastguard Worker From->Count = 0; 57*76559068SAndroid Build Coastguard Worker From->Size = sizeof(QuarantineBatch); 58*76559068SAndroid Build Coastguard Worker } 59*76559068SAndroid Build Coastguard Worker shuffleQuarantineBatch60*76559068SAndroid Build Coastguard Worker void shuffle(u32 State) { ::scudo::shuffle(Batch, Count, &State); } 61*76559068SAndroid Build Coastguard Worker }; 62*76559068SAndroid Build Coastguard Worker 63*76559068SAndroid Build Coastguard Worker static_assert(sizeof(QuarantineBatch) <= (1U << 13), ""); // 8Kb. 64*76559068SAndroid Build Coastguard Worker 65*76559068SAndroid Build Coastguard Worker // Per-thread cache of memory blocks. 66*76559068SAndroid Build Coastguard Worker template <typename Callback> class QuarantineCache { 67*76559068SAndroid Build Coastguard Worker public: init()68*76559068SAndroid Build Coastguard Worker void init() { DCHECK_EQ(atomic_load_relaxed(&Size), 0U); } 69*76559068SAndroid Build Coastguard Worker 70*76559068SAndroid Build Coastguard Worker // Total memory used, including internal accounting. getSize()71*76559068SAndroid Build Coastguard Worker uptr getSize() const { return atomic_load_relaxed(&Size); } 72*76559068SAndroid Build Coastguard Worker // Memory used for internal accounting. getOverheadSize()73*76559068SAndroid Build Coastguard Worker uptr getOverheadSize() const { return List.size() * sizeof(QuarantineBatch); } 74*76559068SAndroid Build Coastguard Worker enqueue(Callback Cb,void * Ptr,uptr Size)75*76559068SAndroid Build Coastguard Worker void enqueue(Callback Cb, void *Ptr, uptr Size) { 76*76559068SAndroid Build Coastguard Worker if (List.empty() || List.back()->Count == QuarantineBatch::MaxCount) { 77*76559068SAndroid Build Coastguard Worker QuarantineBatch *B = 78*76559068SAndroid Build Coastguard Worker reinterpret_cast<QuarantineBatch *>(Cb.allocate(sizeof(*B))); 79*76559068SAndroid Build Coastguard Worker DCHECK(B); 80*76559068SAndroid Build Coastguard Worker B->init(Ptr, Size); 81*76559068SAndroid Build Coastguard Worker enqueueBatch(B); 82*76559068SAndroid Build Coastguard Worker } else { 83*76559068SAndroid Build Coastguard Worker List.back()->push_back(Ptr, Size); 84*76559068SAndroid Build Coastguard Worker addToSize(Size); 85*76559068SAndroid Build Coastguard Worker } 86*76559068SAndroid Build Coastguard Worker } 87*76559068SAndroid Build Coastguard Worker transfer(QuarantineCache * From)88*76559068SAndroid Build Coastguard Worker void transfer(QuarantineCache *From) { 89*76559068SAndroid Build Coastguard Worker List.append_back(&From->List); 90*76559068SAndroid Build Coastguard Worker addToSize(From->getSize()); 91*76559068SAndroid Build Coastguard Worker atomic_store_relaxed(&From->Size, 0); 92*76559068SAndroid Build Coastguard Worker } 93*76559068SAndroid Build Coastguard Worker enqueueBatch(QuarantineBatch * B)94*76559068SAndroid Build Coastguard Worker void enqueueBatch(QuarantineBatch *B) { 95*76559068SAndroid Build Coastguard Worker List.push_back(B); 96*76559068SAndroid Build Coastguard Worker addToSize(B->Size); 97*76559068SAndroid Build Coastguard Worker } 98*76559068SAndroid Build Coastguard Worker dequeueBatch()99*76559068SAndroid Build Coastguard Worker QuarantineBatch *dequeueBatch() { 100*76559068SAndroid Build Coastguard Worker if (List.empty()) 101*76559068SAndroid Build Coastguard Worker return nullptr; 102*76559068SAndroid Build Coastguard Worker QuarantineBatch *B = List.front(); 103*76559068SAndroid Build Coastguard Worker List.pop_front(); 104*76559068SAndroid Build Coastguard Worker subFromSize(B->Size); 105*76559068SAndroid Build Coastguard Worker return B; 106*76559068SAndroid Build Coastguard Worker } 107*76559068SAndroid Build Coastguard Worker mergeBatches(QuarantineCache * ToDeallocate)108*76559068SAndroid Build Coastguard Worker void mergeBatches(QuarantineCache *ToDeallocate) { 109*76559068SAndroid Build Coastguard Worker uptr ExtractedSize = 0; 110*76559068SAndroid Build Coastguard Worker QuarantineBatch *Current = List.front(); 111*76559068SAndroid Build Coastguard Worker while (Current && Current->Next) { 112*76559068SAndroid Build Coastguard Worker if (Current->canMerge(Current->Next)) { 113*76559068SAndroid Build Coastguard Worker QuarantineBatch *Extracted = Current->Next; 114*76559068SAndroid Build Coastguard Worker // Move all the chunks into the current batch. 115*76559068SAndroid Build Coastguard Worker Current->merge(Extracted); 116*76559068SAndroid Build Coastguard Worker DCHECK_EQ(Extracted->Count, 0); 117*76559068SAndroid Build Coastguard Worker DCHECK_EQ(Extracted->Size, sizeof(QuarantineBatch)); 118*76559068SAndroid Build Coastguard Worker // Remove the next batch From the list and account for its Size. 119*76559068SAndroid Build Coastguard Worker List.extract(Current, Extracted); 120*76559068SAndroid Build Coastguard Worker ExtractedSize += Extracted->Size; 121*76559068SAndroid Build Coastguard Worker // Add it to deallocation list. 122*76559068SAndroid Build Coastguard Worker ToDeallocate->enqueueBatch(Extracted); 123*76559068SAndroid Build Coastguard Worker } else { 124*76559068SAndroid Build Coastguard Worker Current = Current->Next; 125*76559068SAndroid Build Coastguard Worker } 126*76559068SAndroid Build Coastguard Worker } 127*76559068SAndroid Build Coastguard Worker subFromSize(ExtractedSize); 128*76559068SAndroid Build Coastguard Worker } 129*76559068SAndroid Build Coastguard Worker getStats(ScopedString * Str)130*76559068SAndroid Build Coastguard Worker void getStats(ScopedString *Str) const { 131*76559068SAndroid Build Coastguard Worker uptr BatchCount = 0; 132*76559068SAndroid Build Coastguard Worker uptr TotalOverheadBytes = 0; 133*76559068SAndroid Build Coastguard Worker uptr TotalBytes = 0; 134*76559068SAndroid Build Coastguard Worker uptr TotalQuarantineChunks = 0; 135*76559068SAndroid Build Coastguard Worker for (const QuarantineBatch &Batch : List) { 136*76559068SAndroid Build Coastguard Worker BatchCount++; 137*76559068SAndroid Build Coastguard Worker TotalBytes += Batch.Size; 138*76559068SAndroid Build Coastguard Worker TotalOverheadBytes += Batch.Size - Batch.getQuarantinedSize(); 139*76559068SAndroid Build Coastguard Worker TotalQuarantineChunks += Batch.Count; 140*76559068SAndroid Build Coastguard Worker } 141*76559068SAndroid Build Coastguard Worker const uptr QuarantineChunksCapacity = 142*76559068SAndroid Build Coastguard Worker BatchCount * QuarantineBatch::MaxCount; 143*76559068SAndroid Build Coastguard Worker const uptr ChunksUsagePercent = 144*76559068SAndroid Build Coastguard Worker (QuarantineChunksCapacity == 0) 145*76559068SAndroid Build Coastguard Worker ? 0 146*76559068SAndroid Build Coastguard Worker : TotalQuarantineChunks * 100 / QuarantineChunksCapacity; 147*76559068SAndroid Build Coastguard Worker const uptr TotalQuarantinedBytes = TotalBytes - TotalOverheadBytes; 148*76559068SAndroid Build Coastguard Worker const uptr MemoryOverheadPercent = 149*76559068SAndroid Build Coastguard Worker (TotalQuarantinedBytes == 0) 150*76559068SAndroid Build Coastguard Worker ? 0 151*76559068SAndroid Build Coastguard Worker : TotalOverheadBytes * 100 / TotalQuarantinedBytes; 152*76559068SAndroid Build Coastguard Worker Str->append( 153*76559068SAndroid Build Coastguard Worker "Stats: Quarantine: batches: %zu; bytes: %zu (user: %zu); chunks: %zu " 154*76559068SAndroid Build Coastguard Worker "(capacity: %zu); %zu%% chunks used; %zu%% memory overhead\n", 155*76559068SAndroid Build Coastguard Worker BatchCount, TotalBytes, TotalQuarantinedBytes, TotalQuarantineChunks, 156*76559068SAndroid Build Coastguard Worker QuarantineChunksCapacity, ChunksUsagePercent, MemoryOverheadPercent); 157*76559068SAndroid Build Coastguard Worker } 158*76559068SAndroid Build Coastguard Worker 159*76559068SAndroid Build Coastguard Worker private: 160*76559068SAndroid Build Coastguard Worker SinglyLinkedList<QuarantineBatch> List; 161*76559068SAndroid Build Coastguard Worker atomic_uptr Size = {}; 162*76559068SAndroid Build Coastguard Worker addToSize(uptr add)163*76559068SAndroid Build Coastguard Worker void addToSize(uptr add) { atomic_store_relaxed(&Size, getSize() + add); } subFromSize(uptr sub)164*76559068SAndroid Build Coastguard Worker void subFromSize(uptr sub) { atomic_store_relaxed(&Size, getSize() - sub); } 165*76559068SAndroid Build Coastguard Worker }; 166*76559068SAndroid Build Coastguard Worker 167*76559068SAndroid Build Coastguard Worker // The callback interface is: 168*76559068SAndroid Build Coastguard Worker // void Callback::recycle(Node *Ptr); 169*76559068SAndroid Build Coastguard Worker // void *Callback::allocate(uptr Size); 170*76559068SAndroid Build Coastguard Worker // void Callback::deallocate(void *Ptr); 171*76559068SAndroid Build Coastguard Worker template <typename Callback, typename Node> class GlobalQuarantine { 172*76559068SAndroid Build Coastguard Worker public: 173*76559068SAndroid Build Coastguard Worker typedef QuarantineCache<Callback> CacheT; 174*76559068SAndroid Build Coastguard Worker using ThisT = GlobalQuarantine<Callback, Node>; 175*76559068SAndroid Build Coastguard Worker init(uptr Size,uptr CacheSize)176*76559068SAndroid Build Coastguard Worker void init(uptr Size, uptr CacheSize) NO_THREAD_SAFETY_ANALYSIS { 177*76559068SAndroid Build Coastguard Worker DCHECK(isAligned(reinterpret_cast<uptr>(this), alignof(ThisT))); 178*76559068SAndroid Build Coastguard Worker DCHECK_EQ(atomic_load_relaxed(&MaxSize), 0U); 179*76559068SAndroid Build Coastguard Worker DCHECK_EQ(atomic_load_relaxed(&MinSize), 0U); 180*76559068SAndroid Build Coastguard Worker DCHECK_EQ(atomic_load_relaxed(&MaxCacheSize), 0U); 181*76559068SAndroid Build Coastguard Worker // Thread local quarantine size can be zero only when global quarantine size 182*76559068SAndroid Build Coastguard Worker // is zero (it allows us to perform just one atomic read per put() call). 183*76559068SAndroid Build Coastguard Worker CHECK((Size == 0 && CacheSize == 0) || CacheSize != 0); 184*76559068SAndroid Build Coastguard Worker 185*76559068SAndroid Build Coastguard Worker atomic_store_relaxed(&MaxSize, Size); 186*76559068SAndroid Build Coastguard Worker atomic_store_relaxed(&MinSize, Size / 10 * 9); // 90% of max size. 187*76559068SAndroid Build Coastguard Worker atomic_store_relaxed(&MaxCacheSize, CacheSize); 188*76559068SAndroid Build Coastguard Worker 189*76559068SAndroid Build Coastguard Worker Cache.init(); 190*76559068SAndroid Build Coastguard Worker } 191*76559068SAndroid Build Coastguard Worker getMaxSize()192*76559068SAndroid Build Coastguard Worker uptr getMaxSize() const { return atomic_load_relaxed(&MaxSize); } getCacheSize()193*76559068SAndroid Build Coastguard Worker uptr getCacheSize() const { return atomic_load_relaxed(&MaxCacheSize); } 194*76559068SAndroid Build Coastguard Worker 195*76559068SAndroid Build Coastguard Worker // This is supposed to be used in test only. isEmpty()196*76559068SAndroid Build Coastguard Worker bool isEmpty() { 197*76559068SAndroid Build Coastguard Worker ScopedLock L(CacheMutex); 198*76559068SAndroid Build Coastguard Worker return Cache.getSize() == 0U; 199*76559068SAndroid Build Coastguard Worker } 200*76559068SAndroid Build Coastguard Worker put(CacheT * C,Callback Cb,Node * Ptr,uptr Size)201*76559068SAndroid Build Coastguard Worker void put(CacheT *C, Callback Cb, Node *Ptr, uptr Size) { 202*76559068SAndroid Build Coastguard Worker C->enqueue(Cb, Ptr, Size); 203*76559068SAndroid Build Coastguard Worker if (C->getSize() > getCacheSize()) 204*76559068SAndroid Build Coastguard Worker drain(C, Cb); 205*76559068SAndroid Build Coastguard Worker } 206*76559068SAndroid Build Coastguard Worker drain(CacheT * C,Callback Cb)207*76559068SAndroid Build Coastguard Worker void NOINLINE drain(CacheT *C, Callback Cb) EXCLUDES(CacheMutex) { 208*76559068SAndroid Build Coastguard Worker bool needRecycle = false; 209*76559068SAndroid Build Coastguard Worker { 210*76559068SAndroid Build Coastguard Worker ScopedLock L(CacheMutex); 211*76559068SAndroid Build Coastguard Worker Cache.transfer(C); 212*76559068SAndroid Build Coastguard Worker needRecycle = Cache.getSize() > getMaxSize(); 213*76559068SAndroid Build Coastguard Worker } 214*76559068SAndroid Build Coastguard Worker 215*76559068SAndroid Build Coastguard Worker if (needRecycle && RecycleMutex.tryLock()) 216*76559068SAndroid Build Coastguard Worker recycle(atomic_load_relaxed(&MinSize), Cb); 217*76559068SAndroid Build Coastguard Worker } 218*76559068SAndroid Build Coastguard Worker drainAndRecycle(CacheT * C,Callback Cb)219*76559068SAndroid Build Coastguard Worker void NOINLINE drainAndRecycle(CacheT *C, Callback Cb) EXCLUDES(CacheMutex) { 220*76559068SAndroid Build Coastguard Worker { 221*76559068SAndroid Build Coastguard Worker ScopedLock L(CacheMutex); 222*76559068SAndroid Build Coastguard Worker Cache.transfer(C); 223*76559068SAndroid Build Coastguard Worker } 224*76559068SAndroid Build Coastguard Worker RecycleMutex.lock(); 225*76559068SAndroid Build Coastguard Worker recycle(0, Cb); 226*76559068SAndroid Build Coastguard Worker } 227*76559068SAndroid Build Coastguard Worker getStats(ScopedString * Str)228*76559068SAndroid Build Coastguard Worker void getStats(ScopedString *Str) EXCLUDES(CacheMutex) { 229*76559068SAndroid Build Coastguard Worker ScopedLock L(CacheMutex); 230*76559068SAndroid Build Coastguard Worker // It assumes that the world is stopped, just as the allocator's printStats. 231*76559068SAndroid Build Coastguard Worker Cache.getStats(Str); 232*76559068SAndroid Build Coastguard Worker Str->append("Quarantine limits: global: %zuK; thread local: %zuK\n", 233*76559068SAndroid Build Coastguard Worker getMaxSize() >> 10, getCacheSize() >> 10); 234*76559068SAndroid Build Coastguard Worker } 235*76559068SAndroid Build Coastguard Worker disable()236*76559068SAndroid Build Coastguard Worker void disable() NO_THREAD_SAFETY_ANALYSIS { 237*76559068SAndroid Build Coastguard Worker // RecycleMutex must be locked 1st since we grab CacheMutex within recycle. 238*76559068SAndroid Build Coastguard Worker RecycleMutex.lock(); 239*76559068SAndroid Build Coastguard Worker CacheMutex.lock(); 240*76559068SAndroid Build Coastguard Worker } 241*76559068SAndroid Build Coastguard Worker enable()242*76559068SAndroid Build Coastguard Worker void enable() NO_THREAD_SAFETY_ANALYSIS { 243*76559068SAndroid Build Coastguard Worker CacheMutex.unlock(); 244*76559068SAndroid Build Coastguard Worker RecycleMutex.unlock(); 245*76559068SAndroid Build Coastguard Worker } 246*76559068SAndroid Build Coastguard Worker 247*76559068SAndroid Build Coastguard Worker private: 248*76559068SAndroid Build Coastguard Worker // Read-only data. 249*76559068SAndroid Build Coastguard Worker alignas(SCUDO_CACHE_LINE_SIZE) HybridMutex CacheMutex; 250*76559068SAndroid Build Coastguard Worker CacheT Cache GUARDED_BY(CacheMutex); 251*76559068SAndroid Build Coastguard Worker alignas(SCUDO_CACHE_LINE_SIZE) HybridMutex RecycleMutex; 252*76559068SAndroid Build Coastguard Worker atomic_uptr MinSize = {}; 253*76559068SAndroid Build Coastguard Worker atomic_uptr MaxSize = {}; 254*76559068SAndroid Build Coastguard Worker alignas(SCUDO_CACHE_LINE_SIZE) atomic_uptr MaxCacheSize = {}; 255*76559068SAndroid Build Coastguard Worker recycle(uptr MinSize,Callback Cb)256*76559068SAndroid Build Coastguard Worker void NOINLINE recycle(uptr MinSize, Callback Cb) RELEASE(RecycleMutex) 257*76559068SAndroid Build Coastguard Worker EXCLUDES(CacheMutex) { 258*76559068SAndroid Build Coastguard Worker CacheT Tmp; 259*76559068SAndroid Build Coastguard Worker Tmp.init(); 260*76559068SAndroid Build Coastguard Worker { 261*76559068SAndroid Build Coastguard Worker ScopedLock L(CacheMutex); 262*76559068SAndroid Build Coastguard Worker // Go over the batches and merge partially filled ones to 263*76559068SAndroid Build Coastguard Worker // save some memory, otherwise batches themselves (since the memory used 264*76559068SAndroid Build Coastguard Worker // by them is counted against quarantine limit) can overcome the actual 265*76559068SAndroid Build Coastguard Worker // user's quarantined chunks, which diminishes the purpose of the 266*76559068SAndroid Build Coastguard Worker // quarantine. 267*76559068SAndroid Build Coastguard Worker const uptr CacheSize = Cache.getSize(); 268*76559068SAndroid Build Coastguard Worker const uptr OverheadSize = Cache.getOverheadSize(); 269*76559068SAndroid Build Coastguard Worker DCHECK_GE(CacheSize, OverheadSize); 270*76559068SAndroid Build Coastguard Worker // Do the merge only when overhead exceeds this predefined limit (might 271*76559068SAndroid Build Coastguard Worker // require some tuning). It saves us merge attempt when the batch list 272*76559068SAndroid Build Coastguard Worker // quarantine is unlikely to contain batches suitable for merge. 273*76559068SAndroid Build Coastguard Worker constexpr uptr OverheadThresholdPercents = 100; 274*76559068SAndroid Build Coastguard Worker if (CacheSize > OverheadSize && 275*76559068SAndroid Build Coastguard Worker OverheadSize * (100 + OverheadThresholdPercents) > 276*76559068SAndroid Build Coastguard Worker CacheSize * OverheadThresholdPercents) { 277*76559068SAndroid Build Coastguard Worker Cache.mergeBatches(&Tmp); 278*76559068SAndroid Build Coastguard Worker } 279*76559068SAndroid Build Coastguard Worker // Extract enough chunks from the quarantine to get below the max 280*76559068SAndroid Build Coastguard Worker // quarantine size and leave some leeway for the newly quarantined chunks. 281*76559068SAndroid Build Coastguard Worker while (Cache.getSize() > MinSize) 282*76559068SAndroid Build Coastguard Worker Tmp.enqueueBatch(Cache.dequeueBatch()); 283*76559068SAndroid Build Coastguard Worker } 284*76559068SAndroid Build Coastguard Worker RecycleMutex.unlock(); 285*76559068SAndroid Build Coastguard Worker doRecycle(&Tmp, Cb); 286*76559068SAndroid Build Coastguard Worker } 287*76559068SAndroid Build Coastguard Worker doRecycle(CacheT * C,Callback Cb)288*76559068SAndroid Build Coastguard Worker void NOINLINE doRecycle(CacheT *C, Callback Cb) { 289*76559068SAndroid Build Coastguard Worker while (QuarantineBatch *B = C->dequeueBatch()) { 290*76559068SAndroid Build Coastguard Worker const u32 Seed = static_cast<u32>( 291*76559068SAndroid Build Coastguard Worker (reinterpret_cast<uptr>(B) ^ reinterpret_cast<uptr>(C)) >> 4); 292*76559068SAndroid Build Coastguard Worker B->shuffle(Seed); 293*76559068SAndroid Build Coastguard Worker constexpr uptr NumberOfPrefetch = 8UL; 294*76559068SAndroid Build Coastguard Worker CHECK(NumberOfPrefetch <= ARRAY_SIZE(B->Batch)); 295*76559068SAndroid Build Coastguard Worker for (uptr I = 0; I < NumberOfPrefetch; I++) 296*76559068SAndroid Build Coastguard Worker PREFETCH(B->Batch[I]); 297*76559068SAndroid Build Coastguard Worker for (uptr I = 0, Count = B->Count; I < Count; I++) { 298*76559068SAndroid Build Coastguard Worker if (I + NumberOfPrefetch < Count) 299*76559068SAndroid Build Coastguard Worker PREFETCH(B->Batch[I + NumberOfPrefetch]); 300*76559068SAndroid Build Coastguard Worker Cb.recycle(reinterpret_cast<Node *>(B->Batch[I])); 301*76559068SAndroid Build Coastguard Worker } 302*76559068SAndroid Build Coastguard Worker Cb.deallocate(B); 303*76559068SAndroid Build Coastguard Worker } 304*76559068SAndroid Build Coastguard Worker } 305*76559068SAndroid Build Coastguard Worker }; 306*76559068SAndroid Build Coastguard Worker 307*76559068SAndroid Build Coastguard Worker } // namespace scudo 308*76559068SAndroid Build Coastguard Worker 309*76559068SAndroid Build Coastguard Worker #endif // SCUDO_QUARANTINE_H_ 310