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
21struct ResizeRequest;
22
23
24struct object_link {
25	struct object_link* next;
26};
27
28struct 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
39typedef DoublyLinkedList<slab> SlabList;
40
41struct ObjectCacheResizeEntry {
42	ConditionVariable	condition;
43	thread_id			thread;
44};
45
46struct 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
85public:
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
133static inline void*
134link_to_object(object_link* link, size_t objectSize)
135{
136	return ((uint8*)link) - (objectSize - sizeof(object_link));
137}
138
139
140static inline object_link*
141object_to_link(void* object, size_t objectSize)
142{
143	return (object_link*)(((uint8*)object)
144		+ (objectSize - sizeof(object_link)));
145}
146
147
148static inline void*
149lower_boundary(const void* object, size_t byteCount)
150{
151	return (void*)((addr_t)object & ~(byteCount - 1));
152}
153
154
155static inline bool
156check_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
167inline status_t
168ObjectCache::AllocateTrackingInfos(slab* slab, size_t byteCount, uint32 flags)
169{
170	return B_OK;
171}
172
173
174inline void
175ObjectCache::FreeTrackingInfos(slab* slab, uint32 flags)
176{
177}
178
179#endif // !SLAB_OBJECT_CACHE_ALLOCATION_TRACKING
180
181#endif	// OBJECT_CACHE_H
182