18b34fbe0b17b751cf17d928fff10dee0f35d730
[reactos.git] / reactos / ntoskrnl / ex / lookas.c
1 /* $Id: lookas.c,v 1.9 2003/07/11 01:23:14 royce Exp $
2 *
3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: ntoskrnl/ex/lookas.c
6 * PURPOSE: Lookaside lists
7 * PROGRAMMERS: David Welch (welch@mcmail.com)
8 * Casper S. Hornstrup (chorns@users.sourceforge.net)
9 * UPDATE HISTORY:
10 * 22-05-1998 DW Created
11 * 02-07-2001 CSH Implemented lookaside lists
12 */
13
14 /* INCLUDES *****************************************************************/
15
16 #include <ddk/ntddk.h>
17 #include <internal/ex.h>
18 #define NDEBUG
19 #include <internal/debug.h>
20
21 /* GLOBALS *******************************************************************/
22
23 LIST_ENTRY ExpNonPagedLookasideListHead;
24 KSPIN_LOCK ExpNonPagedLookasideListLock;
25
26 LIST_ENTRY ExpPagedLookasideListHead;
27 KSPIN_LOCK ExpPagedLookasideListLock;
28
29 PLOOKASIDE_MINMAX_ROUTINE ExpMinMaxRoutine;
30
31 /* FUNCTIONS *****************************************************************/
32
33 VOID ExpDefaultMinMax(
34 POOL_TYPE PoolType,
35 ULONG Size,
36 PUSHORT MinimumDepth,
37 PUSHORT MaximumDepth)
38 /*
39 * FUNCTION: Determines the minimum and maximum depth of a new lookaside list
40 * ARGUMENTS:
41 * Type = Type of executive pool
42 * Size = Size in bytes of each element in the new lookaside list
43 * MinimumDepth = Buffer to store minimum depth of the new lookaside list in
44 * MaximumDepth = Buffer to store maximum depth of the new lookaside list in
45 */
46 {
47 /* FIXME: Could probably do some serious computing here */
48 if ((PoolType == NonPagedPool) ||
49 (PoolType == NonPagedPoolMustSucceed))
50 {
51 *MinimumDepth = 10;
52 *MaximumDepth = 100;
53 }
54 else
55 {
56 *MinimumDepth = 20;
57 *MaximumDepth = 200;
58 }
59 }
60
61
62 PVOID STDCALL
63 ExpDefaultAllocate(POOL_TYPE PoolType,
64 ULONG NumberOfBytes,
65 ULONG Tag)
66 /*
67 * FUNCTION: Default allocate function for lookaside lists
68 * ARGUMENTS:
69 * Type = Type of executive pool
70 * NumberOfBytes = Number of bytes to allocate
71 * Tag = Tag to use
72 * RETURNS:
73 * Pointer to allocated memory, or NULL if there is not enough free resources
74 */
75 {
76 return ExAllocatePoolWithTag(PoolType, NumberOfBytes, Tag);
77 }
78
79
80 VOID STDCALL
81 ExpDefaultFree(PVOID Buffer)
82 /*
83 * FUNCTION: Default free function for lookaside lists
84 * ARGUMENTS:
85 * Buffer = Pointer to memory to free
86 */
87 {
88 return ExFreePool(Buffer);
89 }
90
91
92 VOID
93 ExpInitLookasideLists()
94 {
95 InitializeListHead(&ExpNonPagedLookasideListHead);
96 KeInitializeSpinLock(&ExpNonPagedLookasideListLock);
97
98 InitializeListHead(&ExpPagedLookasideListHead);
99 KeInitializeSpinLock(&ExpPagedLookasideListLock);
100
101 /* FIXME: Possibly configure the algorithm using the registry */
102 ExpMinMaxRoutine = ExpDefaultMinMax;
103 }
104
105 /*
106 * @implemented
107 */
108 PVOID
109 STDCALL
110 ExAllocateFromPagedLookasideList (
111 PPAGED_LOOKASIDE_LIST Lookaside
112 )
113 {
114 PVOID Entry;
115
116 /* Try to obtain an entry from the lookaside list. If that fails, try to
117 allocate a new entry with the allocate method for the lookaside list */
118
119 Lookaside->TotalAllocates++;
120
121 // ExAcquireFastMutex(&Lookaside->Lock);
122
123 Entry = PopEntrySList(&Lookaside->ListHead);
124
125 // ExReleaseFastMutex(&Lookaside->Lock);
126
127 if (Entry)
128 return Entry;
129
130 Lookaside->AllocateMisses++;
131
132 Entry = (*Lookaside->Allocate)(Lookaside->Type,
133 Lookaside->Size,
134 Lookaside->Tag);
135
136 return Entry;
137 }
138
139 /*
140 * @implemented
141 */
142 VOID
143 STDCALL
144 ExDeleteNPagedLookasideList (
145 PNPAGED_LOOKASIDE_LIST Lookaside
146 )
147 {
148 KIRQL OldIrql;
149 PVOID Entry;
150
151 /* Pop all entries off the stack and release the resources allocated
152 for them */
153 while ((Entry = ExInterlockedPopEntrySList(
154 &Lookaside->ListHead,
155 &Lookaside->Lock)) != NULL)
156 {
157 (*Lookaside->Free)(Entry);
158 }
159
160 KeAcquireSpinLock(&ExpNonPagedLookasideListLock, &OldIrql);
161 RemoveEntryList(&Lookaside->ListEntry);
162 KeReleaseSpinLock(&ExpNonPagedLookasideListLock, OldIrql);
163 }
164
165 /*
166 * @implemented
167 */
168 VOID
169 STDCALL
170 ExDeletePagedLookasideList (
171 PPAGED_LOOKASIDE_LIST Lookaside
172 )
173 {
174 KIRQL OldIrql;
175 PVOID Entry;
176
177 /* Pop all entries off the stack and release the resources allocated
178 for them */
179 for (;;)
180 {
181
182 // ExAcquireFastMutex(&Lookaside->Lock);
183
184 Entry = PopEntrySList(&Lookaside->ListHead);
185 if (!Entry)
186 break;
187
188 // ExReleaseFastMutex(&Lookaside->Lock);
189
190 (*Lookaside->Free)(Entry);
191 }
192
193 KeAcquireSpinLock(&ExpPagedLookasideListLock, &OldIrql);
194 RemoveEntryList(&Lookaside->ListEntry);
195 KeReleaseSpinLock(&ExpPagedLookasideListLock, OldIrql);
196 }
197
198 /*
199 * @implemented
200 */
201 VOID
202 STDCALL
203 ExFreeToPagedLookasideList (
204 PPAGED_LOOKASIDE_LIST Lookaside,
205 PVOID Entry
206 )
207 {
208 Lookaside->TotalFrees++;
209
210 if (ExQueryDepthSList(&Lookaside->ListHead) >= Lookaside->MinimumDepth)
211 {
212 Lookaside->FreeMisses++;
213 (*Lookaside->Free)(Entry);
214 }
215 else
216 {
217 // ExAcquireFastMutex(&Lookaside->Lock);
218 PushEntrySList(&Lookaside->ListHead, (PSINGLE_LIST_ENTRY)Entry);
219 // ExReleaseFastMutex(&Lookaside->Lock);
220 }
221 }
222
223 /*
224 * @implemented
225 */
226 VOID
227 STDCALL
228 ExInitializeNPagedLookasideList (
229 PNPAGED_LOOKASIDE_LIST Lookaside,
230 PALLOCATE_FUNCTION Allocate,
231 PFREE_FUNCTION Free,
232 ULONG Flags,
233 ULONG Size,
234 ULONG Tag,
235 USHORT Depth)
236 {
237 DPRINT("Initializing nonpaged lookaside list at 0x%X\n", Lookaside);
238
239 Lookaside->TotalAllocates = 0;
240 Lookaside->AllocateMisses = 0;
241 Lookaside->TotalFrees = 0;
242 Lookaside->FreeMisses = 0;
243 Lookaside->Type = NonPagedPool;
244 Lookaside->Tag = Tag;
245
246 /* We use a field of type SINGLE_LIST_ENTRY as a link to the next entry in
247 the lookaside list so we must allocate at least sizeof(SINGLE_LIST_ENTRY) */
248 if (Size < sizeof(SINGLE_LIST_ENTRY))
249 Lookaside->Size = sizeof(SINGLE_LIST_ENTRY);
250 else
251 Lookaside->Size = Size;
252
253 if (Allocate)
254 Lookaside->Allocate = Allocate;
255 else
256 Lookaside->Allocate = ExpDefaultAllocate;
257
258 if (Free)
259 Lookaside->Free = Free;
260 else
261 Lookaside->Free = ExpDefaultFree;
262
263 ExInitializeSListHead(&Lookaside->ListHead);
264 KeInitializeSpinLock(&Lookaside->Lock);
265
266 /* Determine minimum and maximum number of entries on the lookaside list
267 using the configured algorithm */
268 (*ExpMinMaxRoutine)(
269 NonPagedPool,
270 Lookaside->Size,
271 &Lookaside->MinimumDepth,
272 &Lookaside->MaximumDepth);
273
274 ExInterlockedInsertTailList(
275 &ExpNonPagedLookasideListHead,
276 &Lookaside->ListEntry,
277 &ExpNonPagedLookasideListLock);
278 }
279
280 /*
281 * @implemented
282 */
283 VOID
284 STDCALL
285 ExInitializePagedLookasideList (
286 PPAGED_LOOKASIDE_LIST Lookaside,
287 PALLOCATE_FUNCTION Allocate,
288 PFREE_FUNCTION Free,
289 ULONG Flags,
290 ULONG Size,
291 ULONG Tag,
292 USHORT Depth
293 )
294 {
295 DPRINT("Initializing paged lookaside list at 0x%X\n", Lookaside);
296
297 Lookaside->TotalAllocates = 0;
298 Lookaside->AllocateMisses = 0;
299 Lookaside->TotalFrees = 0;
300 Lookaside->FreeMisses = 0;
301 Lookaside->Type = PagedPool;
302 Lookaside->Tag = Tag;
303
304 /* We use a field of type SINGLE_LIST_ENTRY as a link to the next entry in
305 the lookaside list so we must allocate at least sizeof(SINGLE_LIST_ENTRY) */
306 if (Size < sizeof(SINGLE_LIST_ENTRY))
307 Lookaside->Size = sizeof(SINGLE_LIST_ENTRY);
308 else
309 Lookaside->Size = Size;
310
311 if (Allocate)
312 Lookaside->Allocate = Allocate;
313 else
314 Lookaside->Allocate = ExpDefaultAllocate;
315
316 if (Free)
317 Lookaside->Free = Free;
318 else
319 Lookaside->Free = ExpDefaultFree;
320
321 ExInitializeSListHead(&Lookaside->ListHead);
322 //ExInitializeFastMutex(&Lookaside->Lock);
323
324 /* Determine minimum and maximum number of entries on the lookaside list
325 using the configured algorithm */
326 (*ExpMinMaxRoutine)(
327 PagedPool,
328 Lookaside->Size,
329 &Lookaside->MinimumDepth,
330 &Lookaside->MaximumDepth);
331
332 ExInterlockedInsertTailList(
333 &ExpPagedLookasideListHead,
334 &Lookaside->ListEntry,
335 &ExpPagedLookasideListLock);
336 }
337
338 /* EOF */