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