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