:pserver:cvsanon@mok.lvcm.com:/CVS/ReactOS reactos
[reactos.git] / ntoskrnl / ex / lookas.c
1 /* $Id$
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 PVOID
106 STDCALL
107 ExAllocateFromPagedLookasideList (
108         PPAGED_LOOKASIDE_LIST   Lookaside
109         )
110 {
111   PVOID Entry;
112
113   /* Try to obtain an entry from the lookaside list. If that fails, try to
114      allocate a new entry with the allocate method for the lookaside list */
115
116   Lookaside->TotalAllocates++;
117
118 //  ExAcquireFastMutex(&Lookaside->Lock);
119
120   Entry = PopEntrySList(&Lookaside->ListHead);
121
122 //  ExReleaseFastMutex(&Lookaside->Lock);
123
124   if (Entry)
125     return Entry;
126
127   Lookaside->AllocateMisses++;
128
129   Entry = (*Lookaside->Allocate)(Lookaside->Type,
130     Lookaside->Size,
131     Lookaside->Tag);
132
133   return Entry;
134 }
135
136 VOID
137 STDCALL
138 ExDeleteNPagedLookasideList (
139         PNPAGED_LOOKASIDE_LIST  Lookaside
140         )
141 {
142   KIRQL OldIrql;
143   PVOID Entry;
144
145   /* Pop all entries off the stack and release the resources allocated
146      for them */
147   while ((Entry = ExInterlockedPopEntrySList(
148     &Lookaside->ListHead,
149     &Lookaside->Lock)) != NULL)
150   {
151     (*Lookaside->Free)(Entry);
152   }
153
154   KeAcquireSpinLock(&ExpNonPagedLookasideListLock, &OldIrql);
155   RemoveEntryList(&Lookaside->ListEntry);
156   KeReleaseSpinLock(&ExpNonPagedLookasideListLock, OldIrql);
157 }
158
159 VOID
160 STDCALL
161 ExDeletePagedLookasideList (
162         PPAGED_LOOKASIDE_LIST   Lookaside
163         )
164 {
165   KIRQL OldIrql;
166   PVOID Entry;
167
168   /* Pop all entries off the stack and release the resources allocated
169      for them */
170   for (;;)
171   {
172
173 //  ExAcquireFastMutex(&Lookaside->Lock);
174
175     Entry = PopEntrySList(&Lookaside->ListHead);
176     if (!Entry)
177       break;
178
179 //  ExReleaseFastMutex(&Lookaside->Lock);
180
181     (*Lookaside->Free)(Entry);
182   }
183
184   KeAcquireSpinLock(&ExpPagedLookasideListLock, &OldIrql);
185   RemoveEntryList(&Lookaside->ListEntry);
186   KeReleaseSpinLock(&ExpPagedLookasideListLock, OldIrql);
187 }
188
189 VOID
190 STDCALL
191 ExFreeToPagedLookasideList (
192         PPAGED_LOOKASIDE_LIST   Lookaside,
193         PVOID                   Entry
194         )
195 {
196         Lookaside->TotalFrees++;
197
198         if (ExQueryDepthSList(&Lookaside->ListHead) >= Lookaside->MinimumDepth)
199         {
200                 Lookaside->FreeMisses++;
201                 (*Lookaside->Free)(Entry);
202         }
203         else
204         {
205 //  ExAcquireFastMutex(&Lookaside->Lock);
206     PushEntrySList(&Lookaside->ListHead, (PSINGLE_LIST_ENTRY)Entry);
207 //  ExReleaseFastMutex(&Lookaside->Lock);
208         }
209 }
210
211 VOID
212 STDCALL
213 ExInitializeNPagedLookasideList (
214         PNPAGED_LOOKASIDE_LIST  Lookaside,
215         PALLOCATE_FUNCTION      Allocate,
216         PFREE_FUNCTION          Free,
217         ULONG                   Flags,
218         ULONG                   Size,
219         ULONG                   Tag,
220         USHORT                  Depth)
221 {
222   DPRINT("Initializing nonpaged lookaside list at 0x%X\n", Lookaside);
223
224   Lookaside->TotalAllocates = 0;
225   Lookaside->AllocateMisses = 0;
226   Lookaside->TotalFrees = 0;
227   Lookaside->FreeMisses = 0;
228   Lookaside->Type = NonPagedPool;
229   Lookaside->Tag = Tag;
230
231   /* We use a field of type SINGLE_LIST_ENTRY as a link to the next entry in
232      the lookaside list so we must allocate at least sizeof(SINGLE_LIST_ENTRY) */
233   if (Size < sizeof(SINGLE_LIST_ENTRY))
234     Lookaside->Size = sizeof(SINGLE_LIST_ENTRY);
235   else
236     Lookaside->Size = Size;
237
238   if (Allocate)
239     Lookaside->Allocate = Allocate;
240   else
241     Lookaside->Allocate = ExpDefaultAllocate;
242
243   if (Free)
244     Lookaside->Free = Free;
245   else
246     Lookaside->Free = ExpDefaultFree;
247
248   ExInitializeSListHead(&Lookaside->ListHead);
249   KeInitializeSpinLock(&Lookaside->Lock);
250
251   /* Determine minimum and maximum number of entries on the lookaside list
252      using the configured algorithm */
253   (*ExpMinMaxRoutine)(
254     NonPagedPool,
255     Lookaside->Size,
256     &Lookaside->MinimumDepth,
257     &Lookaside->MaximumDepth);
258
259   ExInterlockedInsertTailList(
260     &ExpNonPagedLookasideListHead,
261     &Lookaside->ListEntry,
262     &ExpNonPagedLookasideListLock);
263 }
264
265 VOID
266 STDCALL
267 ExInitializePagedLookasideList (
268         PPAGED_LOOKASIDE_LIST   Lookaside,
269         PALLOCATE_FUNCTION      Allocate,
270         PFREE_FUNCTION          Free,
271         ULONG                   Flags,
272         ULONG                   Size,
273         ULONG                   Tag,
274         USHORT                  Depth
275         )
276 {
277   DPRINT("Initializing paged lookaside list at 0x%X\n", Lookaside);
278
279   Lookaside->TotalAllocates = 0;
280   Lookaside->AllocateMisses = 0;
281   Lookaside->TotalFrees = 0;
282   Lookaside->FreeMisses = 0;
283   Lookaside->Type = PagedPool;
284   Lookaside->Tag = Tag;
285
286   /* We use a field of type SINGLE_LIST_ENTRY as a link to the next entry in
287      the lookaside list so we must allocate at least sizeof(SINGLE_LIST_ENTRY) */
288   if (Size < sizeof(SINGLE_LIST_ENTRY))
289     Lookaside->Size = sizeof(SINGLE_LIST_ENTRY);
290   else
291     Lookaside->Size = Size;
292
293   if (Allocate)
294     Lookaside->Allocate = Allocate;
295   else
296     Lookaside->Allocate = ExpDefaultAllocate;
297
298   if (Free)
299     Lookaside->Free = Free;
300   else
301     Lookaside->Free = ExpDefaultFree;
302
303   ExInitializeSListHead(&Lookaside->ListHead);
304   //ExInitializeFastMutex(&Lookaside->Lock);
305
306   /* Determine minimum and maximum number of entries on the lookaside list
307      using the configured algorithm */
308   (*ExpMinMaxRoutine)(
309     PagedPool,
310     Lookaside->Size,
311     &Lookaside->MinimumDepth,
312     &Lookaside->MaximumDepth);
313
314   ExInterlockedInsertTailList(
315     &ExpPagedLookasideListHead,
316     &Lookaside->ListEntry,
317     &ExpPagedLookasideListLock);
318 }
319
320 /* EOF */