1*7c3d14c8STreehugger Robot //===-- sanitizer_quarantine.h ----------------------------------*- C++ -*-===// 2*7c3d14c8STreehugger Robot // 3*7c3d14c8STreehugger Robot // The LLVM Compiler Infrastructure 4*7c3d14c8STreehugger Robot // 5*7c3d14c8STreehugger Robot // This file is distributed under the University of Illinois Open Source 6*7c3d14c8STreehugger Robot // License. See LICENSE.TXT for details. 7*7c3d14c8STreehugger Robot // 8*7c3d14c8STreehugger Robot //===----------------------------------------------------------------------===// 9*7c3d14c8STreehugger Robot // 10*7c3d14c8STreehugger Robot // Memory quarantine for AddressSanitizer and potentially other tools. 11*7c3d14c8STreehugger Robot // Quarantine caches some specified amount of memory in per-thread caches, 12*7c3d14c8STreehugger Robot // then evicts to global FIFO queue. When the queue reaches specified threshold, 13*7c3d14c8STreehugger Robot // oldest memory is recycled. 14*7c3d14c8STreehugger Robot // 15*7c3d14c8STreehugger Robot //===----------------------------------------------------------------------===// 16*7c3d14c8STreehugger Robot 17*7c3d14c8STreehugger Robot #ifndef SANITIZER_QUARANTINE_H 18*7c3d14c8STreehugger Robot #define SANITIZER_QUARANTINE_H 19*7c3d14c8STreehugger Robot 20*7c3d14c8STreehugger Robot #include "sanitizer_internal_defs.h" 21*7c3d14c8STreehugger Robot #include "sanitizer_mutex.h" 22*7c3d14c8STreehugger Robot #include "sanitizer_list.h" 23*7c3d14c8STreehugger Robot 24*7c3d14c8STreehugger Robot namespace __sanitizer { 25*7c3d14c8STreehugger Robot 26*7c3d14c8STreehugger Robot template<typename Node> class QuarantineCache; 27*7c3d14c8STreehugger Robot 28*7c3d14c8STreehugger Robot struct QuarantineBatch { 29*7c3d14c8STreehugger Robot static const uptr kSize = 1021; 30*7c3d14c8STreehugger Robot QuarantineBatch *next; 31*7c3d14c8STreehugger Robot uptr size; 32*7c3d14c8STreehugger Robot uptr count; 33*7c3d14c8STreehugger Robot void *batch[kSize]; 34*7c3d14c8STreehugger Robot }; 35*7c3d14c8STreehugger Robot 36*7c3d14c8STreehugger Robot COMPILER_CHECK(sizeof(QuarantineBatch) <= (1 << 13)); // 8Kb. 37*7c3d14c8STreehugger Robot 38*7c3d14c8STreehugger Robot // The callback interface is: 39*7c3d14c8STreehugger Robot // void Callback::Recycle(Node *ptr); 40*7c3d14c8STreehugger Robot // void *cb.Allocate(uptr size); 41*7c3d14c8STreehugger Robot // void cb.Deallocate(void *ptr); 42*7c3d14c8STreehugger Robot template<typename Callback, typename Node> 43*7c3d14c8STreehugger Robot class Quarantine { 44*7c3d14c8STreehugger Robot public: 45*7c3d14c8STreehugger Robot typedef QuarantineCache<Callback> Cache; 46*7c3d14c8STreehugger Robot Quarantine(LinkerInitialized)47*7c3d14c8STreehugger Robot explicit Quarantine(LinkerInitialized) 48*7c3d14c8STreehugger Robot : cache_(LINKER_INITIALIZED) { 49*7c3d14c8STreehugger Robot } 50*7c3d14c8STreehugger Robot Init(uptr size,uptr cache_size)51*7c3d14c8STreehugger Robot void Init(uptr size, uptr cache_size) { 52*7c3d14c8STreehugger Robot atomic_store(&max_size_, size, memory_order_release); 53*7c3d14c8STreehugger Robot atomic_store(&min_size_, size / 10 * 9, 54*7c3d14c8STreehugger Robot memory_order_release); // 90% of max size. 55*7c3d14c8STreehugger Robot max_cache_size_ = cache_size; 56*7c3d14c8STreehugger Robot } 57*7c3d14c8STreehugger Robot GetSize()58*7c3d14c8STreehugger Robot uptr GetSize() const { return atomic_load(&max_size_, memory_order_acquire); } 59*7c3d14c8STreehugger Robot Put(Cache * c,Callback cb,Node * ptr,uptr size)60*7c3d14c8STreehugger Robot void Put(Cache *c, Callback cb, Node *ptr, uptr size) { 61*7c3d14c8STreehugger Robot c->Enqueue(cb, ptr, size); 62*7c3d14c8STreehugger Robot if (c->Size() > max_cache_size_) 63*7c3d14c8STreehugger Robot Drain(c, cb); 64*7c3d14c8STreehugger Robot } 65*7c3d14c8STreehugger Robot Drain(Cache * c,Callback cb)66*7c3d14c8STreehugger Robot void NOINLINE Drain(Cache *c, Callback cb) { 67*7c3d14c8STreehugger Robot { 68*7c3d14c8STreehugger Robot SpinMutexLock l(&cache_mutex_); 69*7c3d14c8STreehugger Robot cache_.Transfer(c); 70*7c3d14c8STreehugger Robot } 71*7c3d14c8STreehugger Robot if (cache_.Size() > GetSize() && recycle_mutex_.TryLock()) 72*7c3d14c8STreehugger Robot Recycle(cb); 73*7c3d14c8STreehugger Robot } 74*7c3d14c8STreehugger Robot 75*7c3d14c8STreehugger Robot private: 76*7c3d14c8STreehugger Robot // Read-only data. 77*7c3d14c8STreehugger Robot char pad0_[kCacheLineSize]; 78*7c3d14c8STreehugger Robot atomic_uintptr_t max_size_; 79*7c3d14c8STreehugger Robot atomic_uintptr_t min_size_; 80*7c3d14c8STreehugger Robot uptr max_cache_size_; 81*7c3d14c8STreehugger Robot char pad1_[kCacheLineSize]; 82*7c3d14c8STreehugger Robot SpinMutex cache_mutex_; 83*7c3d14c8STreehugger Robot SpinMutex recycle_mutex_; 84*7c3d14c8STreehugger Robot Cache cache_; 85*7c3d14c8STreehugger Robot char pad2_[kCacheLineSize]; 86*7c3d14c8STreehugger Robot Recycle(Callback cb)87*7c3d14c8STreehugger Robot void NOINLINE Recycle(Callback cb) { 88*7c3d14c8STreehugger Robot Cache tmp; 89*7c3d14c8STreehugger Robot uptr min_size = atomic_load(&min_size_, memory_order_acquire); 90*7c3d14c8STreehugger Robot { 91*7c3d14c8STreehugger Robot SpinMutexLock l(&cache_mutex_); 92*7c3d14c8STreehugger Robot while (cache_.Size() > min_size) { 93*7c3d14c8STreehugger Robot QuarantineBatch *b = cache_.DequeueBatch(); 94*7c3d14c8STreehugger Robot tmp.EnqueueBatch(b); 95*7c3d14c8STreehugger Robot } 96*7c3d14c8STreehugger Robot } 97*7c3d14c8STreehugger Robot recycle_mutex_.Unlock(); 98*7c3d14c8STreehugger Robot DoRecycle(&tmp, cb); 99*7c3d14c8STreehugger Robot } 100*7c3d14c8STreehugger Robot DoRecycle(Cache * c,Callback cb)101*7c3d14c8STreehugger Robot void NOINLINE DoRecycle(Cache *c, Callback cb) { 102*7c3d14c8STreehugger Robot while (QuarantineBatch *b = c->DequeueBatch()) { 103*7c3d14c8STreehugger Robot const uptr kPrefetch = 16; 104*7c3d14c8STreehugger Robot CHECK(kPrefetch <= ARRAY_SIZE(b->batch)); 105*7c3d14c8STreehugger Robot for (uptr i = 0; i < kPrefetch; i++) 106*7c3d14c8STreehugger Robot PREFETCH(b->batch[i]); 107*7c3d14c8STreehugger Robot for (uptr i = 0, count = b->count; i < count; i++) { 108*7c3d14c8STreehugger Robot if (i + kPrefetch < count) 109*7c3d14c8STreehugger Robot PREFETCH(b->batch[i + kPrefetch]); 110*7c3d14c8STreehugger Robot cb.Recycle((Node*)b->batch[i]); 111*7c3d14c8STreehugger Robot } 112*7c3d14c8STreehugger Robot cb.Deallocate(b); 113*7c3d14c8STreehugger Robot } 114*7c3d14c8STreehugger Robot } 115*7c3d14c8STreehugger Robot }; 116*7c3d14c8STreehugger Robot 117*7c3d14c8STreehugger Robot // Per-thread cache of memory blocks. 118*7c3d14c8STreehugger Robot template<typename Callback> 119*7c3d14c8STreehugger Robot class QuarantineCache { 120*7c3d14c8STreehugger Robot public: QuarantineCache(LinkerInitialized)121*7c3d14c8STreehugger Robot explicit QuarantineCache(LinkerInitialized) { 122*7c3d14c8STreehugger Robot } 123*7c3d14c8STreehugger Robot QuarantineCache()124*7c3d14c8STreehugger Robot QuarantineCache() 125*7c3d14c8STreehugger Robot : size_() { 126*7c3d14c8STreehugger Robot list_.clear(); 127*7c3d14c8STreehugger Robot } 128*7c3d14c8STreehugger Robot Size()129*7c3d14c8STreehugger Robot uptr Size() const { 130*7c3d14c8STreehugger Robot return atomic_load(&size_, memory_order_relaxed); 131*7c3d14c8STreehugger Robot } 132*7c3d14c8STreehugger Robot Enqueue(Callback cb,void * ptr,uptr size)133*7c3d14c8STreehugger Robot void Enqueue(Callback cb, void *ptr, uptr size) { 134*7c3d14c8STreehugger Robot if (list_.empty() || list_.back()->count == QuarantineBatch::kSize) { 135*7c3d14c8STreehugger Robot AllocBatch(cb); 136*7c3d14c8STreehugger Robot size += sizeof(QuarantineBatch); // Count the batch in Quarantine size. 137*7c3d14c8STreehugger Robot } 138*7c3d14c8STreehugger Robot QuarantineBatch *b = list_.back(); 139*7c3d14c8STreehugger Robot CHECK(b); 140*7c3d14c8STreehugger Robot b->batch[b->count++] = ptr; 141*7c3d14c8STreehugger Robot b->size += size; 142*7c3d14c8STreehugger Robot SizeAdd(size); 143*7c3d14c8STreehugger Robot } 144*7c3d14c8STreehugger Robot Transfer(QuarantineCache * c)145*7c3d14c8STreehugger Robot void Transfer(QuarantineCache *c) { 146*7c3d14c8STreehugger Robot list_.append_back(&c->list_); 147*7c3d14c8STreehugger Robot SizeAdd(c->Size()); 148*7c3d14c8STreehugger Robot atomic_store(&c->size_, 0, memory_order_relaxed); 149*7c3d14c8STreehugger Robot } 150*7c3d14c8STreehugger Robot EnqueueBatch(QuarantineBatch * b)151*7c3d14c8STreehugger Robot void EnqueueBatch(QuarantineBatch *b) { 152*7c3d14c8STreehugger Robot list_.push_back(b); 153*7c3d14c8STreehugger Robot SizeAdd(b->size); 154*7c3d14c8STreehugger Robot } 155*7c3d14c8STreehugger Robot DequeueBatch()156*7c3d14c8STreehugger Robot QuarantineBatch *DequeueBatch() { 157*7c3d14c8STreehugger Robot if (list_.empty()) 158*7c3d14c8STreehugger Robot return nullptr; 159*7c3d14c8STreehugger Robot QuarantineBatch *b = list_.front(); 160*7c3d14c8STreehugger Robot list_.pop_front(); 161*7c3d14c8STreehugger Robot SizeSub(b->size); 162*7c3d14c8STreehugger Robot return b; 163*7c3d14c8STreehugger Robot } 164*7c3d14c8STreehugger Robot 165*7c3d14c8STreehugger Robot private: 166*7c3d14c8STreehugger Robot IntrusiveList<QuarantineBatch> list_; 167*7c3d14c8STreehugger Robot atomic_uintptr_t size_; 168*7c3d14c8STreehugger Robot SizeAdd(uptr add)169*7c3d14c8STreehugger Robot void SizeAdd(uptr add) { 170*7c3d14c8STreehugger Robot atomic_store(&size_, Size() + add, memory_order_relaxed); 171*7c3d14c8STreehugger Robot } SizeSub(uptr sub)172*7c3d14c8STreehugger Robot void SizeSub(uptr sub) { 173*7c3d14c8STreehugger Robot atomic_store(&size_, Size() - sub, memory_order_relaxed); 174*7c3d14c8STreehugger Robot } 175*7c3d14c8STreehugger Robot AllocBatch(Callback cb)176*7c3d14c8STreehugger Robot NOINLINE QuarantineBatch* AllocBatch(Callback cb) { 177*7c3d14c8STreehugger Robot QuarantineBatch *b = (QuarantineBatch *)cb.Allocate(sizeof(*b)); 178*7c3d14c8STreehugger Robot CHECK(b); 179*7c3d14c8STreehugger Robot b->count = 0; 180*7c3d14c8STreehugger Robot b->size = 0; 181*7c3d14c8STreehugger Robot list_.push_back(b); 182*7c3d14c8STreehugger Robot return b; 183*7c3d14c8STreehugger Robot } 184*7c3d14c8STreehugger Robot }; 185*7c3d14c8STreehugger Robot } // namespace __sanitizer 186*7c3d14c8STreehugger Robot 187*7c3d14c8STreehugger Robot #endif // SANITIZER_QUARANTINE_H 188