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
LockObjectCache110 bool Lock() { return mutex_lock(&lock) == B_OK; }
UnlockObjectCache111 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*
link_to_object(object_link * link,size_t objectSize)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*
object_to_link(void * object,size_t objectSize)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*
lower_boundary(const void * object,size_t byteCount)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
check_cache_quota(ObjectCache * cache)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
AllocateTrackingInfos(slab * slab,size_t byteCount,uint32 flags)168 ObjectCache::AllocateTrackingInfos(slab* slab, size_t byteCount, uint32 flags)
169 {
170 return B_OK;
171 }
172
173
174 inline void
FreeTrackingInfos(slab * slab,uint32 flags)175 ObjectCache::FreeTrackingInfos(slab* slab, uint32 flags)
176 {
177 }
178
179 #endif // !SLAB_OBJECT_CACHE_ALLOCATION_TRACKING
180
181 #endif // OBJECT_CACHE_H
182