1 /* 2 * Copyright 2008, Axel Dörfler. All Rights Reserved. 3 * Copyright 2007, Hugo Santos. All Rights Reserved. 4 * 5 * Distributed under the terms of the MIT License. 6 */ 7 8 9 #include "HashedObjectCache.h" 10 11 #include "MemoryManager.h" 12 #include "slab_private.h" 13 14 15 static inline int 16 __fls0(size_t value) 17 { 18 if (value == 0) 19 return -1; 20 21 int bit; 22 for (bit = 0; value != 1; bit++) 23 value >>= 1; 24 return bit; 25 } 26 27 28 static HashedSlab* 29 allocate_slab(uint32 flags) 30 { 31 return (HashedSlab*)slab_internal_alloc(sizeof(HashedSlab), flags); 32 } 33 34 35 static void 36 free_slab(HashedSlab* slab, uint32 flags) 37 { 38 slab_internal_free(slab, flags); 39 } 40 41 42 // #pragma mark - 43 44 45 HashedObjectCache::HashedObjectCache() 46 : 47 hash_table(this) 48 { 49 } 50 51 52 /*static*/ HashedObjectCache* 53 HashedObjectCache::Create(const char* name, size_t object_size, 54 size_t alignment, size_t maximum, size_t magazineCapacity, 55 size_t maxMagazineCount, uint32 flags, void* cookie, 56 object_cache_constructor constructor, object_cache_destructor destructor, 57 object_cache_reclaimer reclaimer) 58 { 59 void* buffer = slab_internal_alloc(sizeof(HashedObjectCache), flags); 60 if (buffer == NULL) 61 return NULL; 62 63 HashedObjectCache* cache = new(buffer) HashedObjectCache(); 64 65 // init the hash table 66 size_t hashSize = cache->hash_table.ResizeNeeded(); 67 buffer = slab_internal_alloc(hashSize, flags); 68 if (buffer == NULL) { 69 cache->Delete(); 70 return NULL; 71 } 72 73 cache->hash_table.Resize(buffer, hashSize, true); 74 75 if (cache->Init(name, object_size, alignment, maximum, magazineCapacity, 76 maxMagazineCount, flags, cookie, constructor, destructor, 77 reclaimer) != B_OK) { 78 cache->Delete(); 79 return NULL; 80 } 81 82 if ((flags & CACHE_LARGE_SLAB) != 0) 83 cache->slab_size = 128 * object_size; 84 else 85 cache->slab_size = 8 * object_size; 86 87 cache->slab_size = MemoryManager::AcceptableChunkSize(cache->slab_size); 88 cache->lower_boundary = __fls0(cache->slab_size); 89 90 return cache; 91 } 92 93 94 void 95 HashedObjectCache::Delete() 96 { 97 this->~HashedObjectCache(); 98 slab_internal_free(this, 0); 99 } 100 101 102 slab* 103 HashedObjectCache::CreateSlab(uint32 flags) 104 { 105 if (!check_cache_quota(this)) 106 return NULL; 107 108 Unlock(); 109 110 HashedSlab* slab = allocate_slab(flags); 111 if (slab != NULL) { 112 void* pages; 113 if (MemoryManager::Allocate(this, flags, pages) == B_OK) { 114 Lock(); 115 if (InitSlab(slab, pages, slab_size, flags)) { 116 hash_table.InsertUnchecked(slab); 117 _ResizeHashTableIfNeeded(flags); 118 return slab; 119 } 120 Unlock(); 121 MemoryManager::Free(pages, flags); 122 } 123 124 free_slab(slab, flags); 125 } 126 127 Lock(); 128 return NULL; 129 } 130 131 132 void 133 HashedObjectCache::ReturnSlab(slab* _slab, uint32 flags) 134 { 135 HashedSlab* slab = static_cast<HashedSlab*>(_slab); 136 137 hash_table.RemoveUnchecked(slab); 138 _ResizeHashTableIfNeeded(flags); 139 140 UninitSlab(slab); 141 142 Unlock(); 143 MemoryManager::Free(slab->pages, flags); 144 free_slab(slab, flags); 145 Lock(); 146 } 147 148 149 slab* 150 HashedObjectCache::ObjectSlab(void* object) const 151 { 152 HashedSlab* slab = hash_table.Lookup(::lower_boundary(object, slab_size)); 153 if (slab == NULL) { 154 panic("hash object cache %p: unknown object %p", this, object); 155 return NULL; 156 } 157 return slab; 158 } 159 160 161 void 162 HashedObjectCache::_ResizeHashTableIfNeeded(uint32 flags) 163 { 164 size_t hashSize = hash_table.ResizeNeeded(); 165 if (hashSize != 0) { 166 Unlock(); 167 void* buffer = slab_internal_alloc(hashSize, flags); 168 Lock(); 169 170 if (buffer != NULL) { 171 if (hash_table.ResizeNeeded() == hashSize) { 172 void* oldHash; 173 hash_table.Resize(buffer, hashSize, true, &oldHash); 174 if (oldHash != NULL) { 175 Unlock(); 176 slab_internal_free(oldHash, flags); 177 Lock(); 178 } 179 } 180 } 181 } 182 } 183