1 /* 2 * Copyright 2008-2010, 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 #ifndef OBJECT_CACHE_H 8 #define OBJECT_CACHE_H 9 10 11 #include <condition_variable.h> 12 #include <lock.h> 13 #include <slab/ObjectDepot.h> 14 #include <slab/Slab.h> 15 #include <util/DoublyLinkedList.h> 16 17 #include "kernel_debug_config.h" 18 #include "slab_debug.h" 19 20 21 class AllocationTrackingInfo; 22 struct ResizeRequest; 23 24 25 struct object_link { 26 struct object_link* next; 27 }; 28 29 struct slab : DoublyLinkedListLinkImpl<slab> { 30 void* pages; 31 size_t size; // total number of objects 32 size_t count; // free objects 33 size_t offset; 34 object_link* free; 35 #if SLAB_OBJECT_CACHE_ALLOCATION_TRACKING 36 AllocationTrackingInfo* tracking; 37 #endif 38 }; 39 40 typedef DoublyLinkedList<slab> SlabList; 41 42 struct ObjectCacheResizeEntry { 43 ConditionVariable condition; 44 thread_id thread; 45 }; 46 47 struct ObjectCache : DoublyLinkedListLinkImpl<ObjectCache> { 48 char name[32]; 49 mutex lock; 50 size_t object_size; 51 size_t alignment; 52 size_t cache_color_cycle; 53 SlabList empty; 54 SlabList partial; 55 SlabList full; 56 size_t total_objects; // total number of objects 57 size_t used_count; // used objects 58 size_t empty_count; // empty slabs 59 size_t pressure; 60 size_t min_object_reserve; 61 // minimum number of free objects 62 63 size_t slab_size; 64 size_t usage; 65 size_t maximum; 66 uint32 flags; 67 68 ResizeRequest* resize_request; 69 70 ObjectCacheResizeEntry* resize_entry_can_wait; 71 ObjectCacheResizeEntry* resize_entry_dont_wait; 72 73 DoublyLinkedListLink<ObjectCache> maintenance_link; 74 bool maintenance_pending; 75 bool maintenance_in_progress; 76 bool maintenance_resize; 77 bool maintenance_delete; 78 79 void* cookie; 80 object_cache_constructor constructor; 81 object_cache_destructor destructor; 82 object_cache_reclaimer reclaimer; 83 84 object_depot depot; 85 86 public: 87 virtual ~ObjectCache(); 88 89 status_t Init(const char* name, size_t objectSize, 90 size_t alignment, size_t maximum, 91 size_t magazineCapacity, 92 size_t maxMagazineCount, uint32 flags, 93 void* cookie, 94 object_cache_constructor constructor, 95 object_cache_destructor destructor, 96 object_cache_reclaimer reclaimer); 97 virtual void Delete() = 0; 98 99 virtual slab* CreateSlab(uint32 flags) = 0; 100 virtual void ReturnSlab(slab* slab, uint32 flags) = 0; 101 virtual slab* ObjectSlab(void* object) const = 0; 102 103 slab* InitSlab(slab* slab, void* pages, 104 size_t byteCount, uint32 flags); 105 void UninitSlab(slab* slab); 106 107 void ReturnObjectToSlab(slab* source, void* object, 108 uint32 flags); 109 void* ObjectAtIndex(slab* source, int32 index) const; 110 111 bool Lock() { return mutex_lock(&lock) == B_OK; } 112 void Unlock() { mutex_unlock(&lock); } 113 114 status_t AllocatePages(void** pages, uint32 flags); 115 void FreePages(void* pages); 116 status_t EarlyAllocatePages(void** pages, uint32 flags); 117 void EarlyFreePages(void* pages); 118 119 #if PARANOID_KERNEL_FREE 120 bool AssertObjectNotFreed(void* object); 121 #endif 122 123 status_t AllocateTrackingInfos(slab* slab, 124 size_t byteCount, uint32 flags); 125 void FreeTrackingInfos(slab* slab, uint32 flags); 126 127 #if SLAB_OBJECT_CACHE_ALLOCATION_TRACKING 128 AllocationTrackingInfo* 129 TrackingInfoFor(void* object) const; 130 #endif 131 }; 132 133 134 static inline void* 135 link_to_object(object_link* link, size_t objectSize) 136 { 137 return ((uint8*)link) - (objectSize - sizeof(object_link)); 138 } 139 140 141 static inline object_link* 142 object_to_link(void* object, size_t objectSize) 143 { 144 return (object_link*)(((uint8*)object) 145 + (objectSize - sizeof(object_link))); 146 } 147 148 149 static inline void* 150 lower_boundary(const void* object, size_t byteCount) 151 { 152 return (void*)((addr_t)object & ~(byteCount - 1)); 153 } 154 155 156 static inline bool 157 check_cache_quota(ObjectCache* cache) 158 { 159 if (cache->maximum == 0) 160 return true; 161 162 return (cache->usage + cache->slab_size) <= cache->maximum; 163 } 164 165 166 #if !SLAB_OBJECT_CACHE_ALLOCATION_TRACKING 167 168 inline status_t 169 ObjectCache::AllocateTrackingInfos(slab* slab, size_t byteCount, uint32 flags) 170 { 171 return B_OK; 172 } 173 174 175 inline void 176 ObjectCache::FreeTrackingInfos(slab* slab, uint32 flags) 177 { 178 } 179 180 #endif // !SLAB_OBJECT_CACHE_ALLOCATION_TRACKING 181 182 #endif // OBJECT_CACHE_H 183