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