1825566f8SIngo Weinhold/*
2ff59ce68SAxel Dörfler * Copyright 2008-2010, Axel D��rfler. All Rights Reserved.
3825566f8SIngo Weinhold * Copyright 2007, Hugo Santos. All Rights Reserved.
4825566f8SIngo Weinhold *
5825566f8SIngo Weinhold * Distributed under the terms of the MIT License.
6825566f8SIngo Weinhold */
7825566f8SIngo Weinhold#ifndef OBJECT_CACHE_H
8825566f8SIngo Weinhold#define OBJECT_CACHE_H
9825566f8SIngo Weinhold
10825566f8SIngo Weinhold
1108d66c12SIngo Weinhold#include <condition_variable.h>
12825566f8SIngo Weinhold#include <lock.h>
13825566f8SIngo Weinhold#include <slab/ObjectDepot.h>
14825566f8SIngo Weinhold#include <slab/Slab.h>
15825566f8SIngo Weinhold#include <util/DoublyLinkedList.h>
16825566f8SIngo Weinhold
17e1c6140eSIngo Weinhold#include "kernel_debug_config.h"
18e1c6140eSIngo Weinhold#include "slab_debug.h"
19825566f8SIngo Weinhold
20e1c6140eSIngo Weinhold
21825566f8SIngo Weinholdstruct ResizeRequest;
22825566f8SIngo Weinhold
23825566f8SIngo Weinhold
24825566f8SIngo Weinholdstruct object_link {
25825566f8SIngo Weinhold	struct object_link* next;
26825566f8SIngo Weinhold};
27825566f8SIngo Weinhold
28825566f8SIngo Weinholdstruct slab : DoublyLinkedListLinkImpl<slab> {
29825566f8SIngo Weinhold	void*			pages;
30825566f8SIngo Weinhold	size_t			size;		// total number of objects
31825566f8SIngo Weinhold	size_t			count;		// free objects
32825566f8SIngo Weinhold	size_t			offset;
33825566f8SIngo Weinhold	object_link*	free;
34e1c6140eSIngo Weinhold#if SLAB_OBJECT_CACHE_ALLOCATION_TRACKING
35e1c6140eSIngo Weinhold	AllocationTrackingInfo*	tracking;
36e1c6140eSIngo Weinhold#endif
37825566f8SIngo Weinhold};
38825566f8SIngo Weinhold
39825566f8SIngo Weinholdtypedef DoublyLinkedList<slab> SlabList;
40825566f8SIngo Weinhold
4108d66c12SIngo Weinholdstruct ObjectCacheResizeEntry {
4208d66c12SIngo Weinhold	ConditionVariable	condition;
43b4e5e498SIngo Weinhold	thread_id			thread;
4408d66c12SIngo Weinhold};
4508d66c12SIngo Weinhold
46825566f8SIngo Weinholdstruct ObjectCache : DoublyLinkedListLinkImpl<ObjectCache> {
47825566f8SIngo Weinhold			char				name[32];
48825566f8SIngo Weinhold			mutex				lock;
49825566f8SIngo Weinhold			size_t				object_size;
503aea1d4fSIngo Weinhold			size_t				alignment;
51825566f8SIngo Weinhold			size_t				cache_color_cycle;
52825566f8SIngo Weinhold			SlabList			empty;
53825566f8SIngo Weinhold			SlabList			partial;
54825566f8SIngo Weinhold			SlabList			full;
55825566f8SIngo Weinhold			size_t				total_objects;		// total number of objects
56825566f8SIngo Weinhold			size_t				used_count;			// used objects
57825566f8SIngo Weinhold			size_t				empty_count;		// empty slabs
58825566f8SIngo Weinhold			size_t				pressure;
59825566f8SIngo Weinhold			size_t				min_object_reserve;
60825566f8SIngo Weinhold									// minimum number of free objects
61825566f8SIngo Weinhold
62825566f8SIngo Weinhold			size_t				slab_size;
63825566f8SIngo Weinhold			size_t				usage;
64825566f8SIngo Weinhold			size_t				maximum;
65825566f8SIngo Weinhold			uint32				flags;
66825566f8SIngo Weinhold
67825566f8SIngo Weinhold			ResizeRequest*		resize_request;
68825566f8SIngo Weinhold
6908d66c12SIngo Weinhold			ObjectCacheResizeEntry* resize_entry_can_wait;
7008d66c12SIngo Weinhold			ObjectCacheResizeEntry* resize_entry_dont_wait;
7108d66c12SIngo Weinhold
72c2d63cfaSIngo Weinhold			DoublyLinkedListLink<ObjectCache> maintenance_link;
73c2d63cfaSIngo Weinhold			bool				maintenance_pending;
74c2d63cfaSIngo Weinhold			bool				maintenance_in_progress;
75c2d63cfaSIngo Weinhold			bool				maintenance_resize;
76c2d63cfaSIngo Weinhold			bool				maintenance_delete;
77c2d63cfaSIngo Weinhold
78825566f8SIngo Weinhold			void*				cookie;
79825566f8SIngo Weinhold			object_cache_constructor constructor;
80825566f8SIngo Weinhold			object_cache_destructor destructor;
81825566f8SIngo Weinhold			object_cache_reclaimer reclaimer;
82825566f8SIngo Weinhold
83825566f8SIngo Weinhold			object_depot		depot;
84825566f8SIngo Weinhold
85825566f8SIngo Weinholdpublic:
86825566f8SIngo Weinhold	virtual						~ObjectCache();
87825566f8SIngo Weinhold
88825566f8SIngo Weinhold			status_t			Init(const char* name, size_t objectSize,
89825566f8SIngo Weinhold									size_t alignment, size_t maximum,
90ff59ce68SAxel Dörfler									size_t magazineCapacity,
91ff59ce68SAxel Dörfler									size_t maxMagazineCount, uint32 flags,
92ff59ce68SAxel Dörfler									void* cookie,
93825566f8SIngo Weinhold									object_cache_constructor constructor,
94825566f8SIngo Weinhold									object_cache_destructor destructor,
95825566f8SIngo Weinhold									object_cache_reclaimer reclaimer);
9686c794e5SIngo Weinhold	virtual	void				Delete() = 0;
97825566f8SIngo Weinhold
9808d66c12SIngo Weinhold	virtual	slab*				CreateSlab(uint32 flags) = 0;
9986c794e5SIngo Weinhold	virtual	void				ReturnSlab(slab* slab, uint32 flags) = 0;
100825566f8SIngo Weinhold	virtual slab*				ObjectSlab(void* object) const = 0;
101825566f8SIngo Weinhold
102825566f8SIngo Weinhold			slab*				InitSlab(slab* slab, void* pages,
103bb439b87SIngo Weinhold									size_t byteCount, uint32 flags);
104825566f8SIngo Weinhold			void				UninitSlab(slab* slab);
105825566f8SIngo Weinhold
10686c794e5SIngo Weinhold			void				ReturnObjectToSlab(slab* source, void* object,
10786c794e5SIngo Weinhold									uint32 flags);
108e32699b4SIngo Weinhold			void*				ObjectAtIndex(slab* source, int32 index) const;
109825566f8SIngo Weinhold
110825566f8SIngo Weinhold			bool				Lock()	{ return mutex_lock(&lock) == B_OK; }
111825566f8SIngo Weinhold			void				Unlock()	{ mutex_unlock(&lock); }
112825566f8SIngo Weinhold
11308d66c12SIngo Weinhold			status_t			AllocatePages(void** pages, uint32 flags);
114825566f8SIngo Weinhold			void				FreePages(void* pages);
11508d66c12SIngo Weinhold			status_t			EarlyAllocatePages(void** pages, uint32 flags);
116825566f8SIngo Weinhold			void				EarlyFreePages(void* pages);
11772156a40SMichael Lotz
11872156a40SMichael Lotz#if PARANOID_KERNEL_FREE
11972156a40SMichael Lotz			bool				AssertObjectNotFreed(void* object);
12072156a40SMichael Lotz#endif
121e1c6140eSIngo Weinhold
122e1c6140eSIngo Weinhold			status_t			AllocateTrackingInfos(slab* slab,
123e1c6140eSIngo Weinhold									size_t byteCount, uint32 flags);
124e1c6140eSIngo Weinhold			void				FreeTrackingInfos(slab* slab, uint32 flags);
125e1c6140eSIngo Weinhold
126e1c6140eSIngo Weinhold#if SLAB_OBJECT_CACHE_ALLOCATION_TRACKING
127e1c6140eSIngo Weinhold			AllocationTrackingInfo*
128e1c6140eSIngo Weinhold								TrackingInfoFor(void* object) const;
129e1c6140eSIngo Weinhold#endif
130825566f8SIngo Weinhold};
131825566f8SIngo Weinhold
132825566f8SIngo Weinhold
133825566f8SIngo Weinholdstatic inline void*
134825566f8SIngo Weinholdlink_to_object(object_link* link, size_t objectSize)
135825566f8SIngo Weinhold{
136825566f8SIngo Weinhold	return ((uint8*)link) - (objectSize - sizeof(object_link));
137825566f8SIngo Weinhold}
138825566f8SIngo Weinhold
139825566f8SIngo Weinhold
140825566f8SIngo Weinholdstatic inline object_link*
141825566f8SIngo Weinholdobject_to_link(void* object, size_t objectSize)
142825566f8SIngo Weinhold{
143bec70b1eSAdrien Destugues	return (object_link*)(((uint8*)object)
144825566f8SIngo Weinhold		+ (objectSize - sizeof(object_link)));
145825566f8SIngo Weinhold}
146825566f8SIngo Weinhold
147825566f8SIngo Weinhold
148f1bdb8b9SIngo Weinholdstatic inline void*
149f1bdb8b9SIngo Weinholdlower_boundary(const void* object, size_t byteCount)
150825566f8SIngo Weinhold{
151f1bdb8b9SIngo Weinhold	return (void*)((addr_t)object & ~(byteCount - 1));
152825566f8SIngo Weinhold}
153825566f8SIngo Weinhold
154825566f8SIngo Weinhold
155825566f8SIngo Weinholdstatic inline bool
156f1bdb8b9SIngo Weinholdcheck_cache_quota(ObjectCache* cache)
157825566f8SIngo Weinhold{
158825566f8SIngo Weinhold	if (cache->maximum == 0)
159825566f8SIngo Weinhold		return true;
160825566f8SIngo Weinhold
161825566f8SIngo Weinhold	return (cache->usage + cache->slab_size) <= cache->maximum;
162825566f8SIngo Weinhold}
163825566f8SIngo Weinhold
164825566f8SIngo Weinhold
165e1c6140eSIngo Weinhold#if !SLAB_OBJECT_CACHE_ALLOCATION_TRACKING
166e1c6140eSIngo Weinhold
167e1c6140eSIngo Weinholdinline status_t
168e1c6140eSIngo WeinholdObjectCache::AllocateTrackingInfos(slab* slab, size_t byteCount, uint32 flags)
169e1c6140eSIngo Weinhold{
170e1c6140eSIngo Weinhold	return B_OK;
171e1c6140eSIngo Weinhold}
172e1c6140eSIngo Weinhold
173e1c6140eSIngo Weinhold
174e1c6140eSIngo Weinholdinline void
175e1c6140eSIngo WeinholdObjectCache::FreeTrackingInfos(slab* slab, uint32 flags)
176e1c6140eSIngo Weinhold{
177e1c6140eSIngo Weinhold}
178e1c6140eSIngo Weinhold
179e1c6140eSIngo Weinhold#endif // !SLAB_OBJECT_CACHE_ALLOCATION_TRACKING
180e1c6140eSIngo Weinhold
181825566f8SIngo Weinhold#endif	// OBJECT_CACHE_H
182