- Rewrite CmiScanKeyList to use the NCB.
[reactos.git] / reactos / ntoskrnl / config / cmalloc.c
1 /*
2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/config/cmalloc.c
5 * PURPOSE: Routines for allocating and freeing registry structures
6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
7 */
8
9 /* INCLUDES ******************************************************************/
10
11 #include <ntoskrnl.h>
12 #define NDEBUG
13 #include <debug.h>
14 #include "cm.h"
15
16 /* GLOBALS *******************************************************************/
17
18 BOOLEAN CmpAllocInited;
19 KGUARDED_MUTEX CmpAllocBucketLock, CmpDelayAllocBucketLock;
20
21 LIST_ENTRY CmpFreeKCBListHead;
22 KGUARDED_MUTEX CmpDelayAllocBucketLock;
23 LIST_ENTRY CmpFreeDelayItemsListHead;
24
25 /* FUNCTIONS *****************************************************************/
26
27 VOID
28 NTAPI
29 CmpInitCmPrivateAlloc(VOID)
30 {
31 /* Make sure we didn't already do this */
32 if (!CmpAllocInited)
33 {
34 /* Setup the lock and list */
35 KeInitializeGuardedMutex(&CmpAllocBucketLock);
36 InitializeListHead(&CmpFreeKCBListHead);
37 CmpAllocInited = TRUE;
38 }
39 }
40
41 VOID
42 NTAPI
43 CmpInitCmPrivateDelayAlloc(VOID)
44 {
45 /* Initialize the delay allocation list and lock */
46 KeInitializeGuardedMutex(&CmpDelayAllocBucketLock);
47 InitializeListHead(&CmpFreeDelayItemsListHead);
48 }
49
50 VOID
51 NTAPI
52 CmpFreeKeyControlBlock(IN PCM_KEY_CONTROL_BLOCK Kcb)
53 {
54 ULONG i;
55 PCM_ALLOC_PAGE AllocPage;
56 PAGED_CODE();
57
58 /* Sanity checks */
59 ASSERT(IsListEmpty(&(Kcb->KeyBodyListHead)) == TRUE);
60 for (i = 0; i < 4; i++) ASSERT(Kcb->KeyBodyArray[i] == NULL);
61
62 /* Check if it wasn't privately allocated */
63 if (!Kcb->PrivateAlloc)
64 {
65 /* Free it from the pool */
66 ExFreePool(Kcb);
67 return;
68 }
69
70 /* Acquire the private allocation lock */
71 KeAcquireGuardedMutex(&CmpAllocBucketLock);
72
73 /* Sanity check on lock ownership */
74 ASSERT((GET_HASH_ENTRY(CmpCacheTable, Kcb->ConvKey).Owner ==
75 KeGetCurrentThread()) ||
76 (CmpTestRegistryLockExclusive() == TRUE));
77
78 /* Add us to the free list */
79 InsertTailList(&CmpFreeKCBListHead, &Kcb->FreeListEntry);
80
81 /* Get the allocation page */
82 AllocPage = (PCM_ALLOC_PAGE)((ULONG_PTR)Kcb & 0xFFFFF000);
83
84 /* Sanity check */
85 ASSERT(AllocPage->FreeCount != CM_KCBS_PER_PAGE);
86
87 /* Increase free count */
88 if (++AllocPage->FreeCount == CM_KCBS_PER_PAGE)
89 {
90 /* Loop all the entries */
91 for (i = CM_KCBS_PER_PAGE; i; i--)
92 {
93 /* Get the KCB */
94 Kcb = (PVOID)((ULONG_PTR)AllocPage +
95 FIELD_OFFSET(CM_ALLOC_PAGE, AllocPage) +
96 (i - 1) * sizeof(CM_KEY_CONTROL_BLOCK));
97
98 /* Remove the entry */
99 RemoveEntryList(&Kcb->FreeListEntry);
100 }
101
102 /* Free the page */
103 ExFreePool(AllocPage);
104 }
105
106 /* Release the lock */
107 KeReleaseGuardedMutex(&CmpAllocBucketLock);
108 }
109
110 PCM_KEY_CONTROL_BLOCK
111 NTAPI
112 CmpAllocateKeyControlBlock(VOID)
113 {
114 PLIST_ENTRY NextEntry;
115 PCM_KEY_CONTROL_BLOCK CurrentKcb;
116 PCM_ALLOC_PAGE AllocPage;
117 ULONG i;
118 PAGED_CODE();
119
120 /* Check if private allocations are initialized */
121 if (FALSE)
122 {
123 /* They are, acquire the bucket lock */
124 KeAcquireGuardedMutex(&CmpAllocBucketLock);
125
126 /* See if there's something on the free KCB list */
127 SearchKcbList:
128 if (!IsListEmpty(&CmpFreeKCBListHead))
129 {
130 /* Remove the entry */
131 NextEntry = RemoveHeadList(&CmpFreeKCBListHead);
132
133 /* Get the KCB */
134 CurrentKcb = CONTAINING_RECORD(NextEntry,
135 CM_KEY_CONTROL_BLOCK,
136 FreeListEntry);
137
138 /* Get the allocation page */
139 AllocPage = (PCM_ALLOC_PAGE)((ULONG_PTR)CurrentKcb & 0xFFFFF000);
140
141 /* Decrease the free count */
142 ASSERT(AllocPage->FreeCount != 0);
143 AllocPage->FreeCount--;
144
145 /* Make sure this KCB is privately allocated */
146 ASSERT(CurrentKcb->PrivateAlloc == 1);
147
148 /* Release the allocation lock */
149 KeReleaseGuardedMutex(&CmpAllocBucketLock);
150
151 /* Return the KCB */
152 return CurrentKcb;
153 }
154
155 /* Allocate an allocation page */
156 AllocPage = ExAllocatePoolWithTag(PagedPool, PAGE_SIZE, TAG_CM);
157 if (AllocPage)
158 {
159 /* Set default entries */
160 AllocPage->FreeCount = CM_KCBS_PER_PAGE;
161
162 /* Loop each entry */
163 for (i = 0; i < CM_KCBS_PER_PAGE; i++)
164 {
165 /* Get this entry */
166 CurrentKcb = (PVOID)((ULONG_PTR)AllocPage +
167 FIELD_OFFSET(CM_ALLOC_PAGE, AllocPage) +
168 i * sizeof(CM_KEY_CONTROL_BLOCK));
169
170 /* Set it up */
171 CurrentKcb->PrivateAlloc = TRUE;
172 CurrentKcb->DelayCloseEntry = NULL;
173 InsertHeadList(&CmpFreeKCBListHead,
174 &CurrentKcb->FreeListEntry);
175 }
176
177 /* Now go back and search the list */
178 goto SearchKcbList;
179 }
180 }
181
182 /* Allocate a KCB only */
183 CurrentKcb = ExAllocatePoolWithTag(PagedPool,
184 sizeof(CM_KEY_CONTROL_BLOCK),
185 TAG_CM);
186 if (CurrentKcb)
187 {
188 /* Set it up */
189 CurrentKcb->PrivateAlloc = 0;
190 CurrentKcb->DelayCloseEntry = NULL;
191 }
192
193 /* Return it */
194 return CurrentKcb;
195 }
196
197 PVOID
198 NTAPI
199 CmpAllocateDelayItem(VOID)
200 {
201 PCM_DELAY_ALLOC Entry;
202 PCM_ALLOC_PAGE AllocPage;
203 ULONG i;
204 PLIST_ENTRY NextEntry;
205 PAGED_CODE();
206
207 /* Lock the allocation buckets */
208 KeAcquireGuardedMutex(&CmpDelayAllocBucketLock);
209
210 /* Look for an item on the free list */
211 SearchList:
212 if (!IsListEmpty(&CmpFreeDelayItemsListHead))
213 {
214 /* Get the current entry in the list */
215 NextEntry = RemoveHeadList(&CmpFreeDelayItemsListHead);
216
217 /* Grab the item */
218 Entry = CONTAINING_RECORD(NextEntry, CM_DELAY_ALLOC, ListEntry);
219
220 /* Clear the list */
221 Entry->ListEntry.Flink = Entry->ListEntry.Blink = NULL;
222
223 /* Grab the alloc page */
224 AllocPage = (PCM_ALLOC_PAGE)((ULONG_PTR)Entry & 0xFFFFF000);
225
226 /* Decrease free entries */
227 ASSERT(AllocPage->FreeCount != 0);
228 AllocPage->FreeCount--;
229
230 /* Release the lock */
231 KeReleaseGuardedMutex(&CmpDelayAllocBucketLock);
232 return Entry;
233 }
234
235 /* Allocate an allocation page */
236 AllocPage = ExAllocatePoolWithTag(PagedPool, PAGE_SIZE, TAG_CM);
237 if (AllocPage)
238 {
239 /* Set default entries */
240 AllocPage->FreeCount = CM_DELAYS_PER_PAGE;
241
242 /* Loop each entry */
243 for (i = 0; i < CM_DELAYS_PER_PAGE; i++)
244 {
245 /* Get this entry and link it */
246 Entry = (PVOID)((ULONG_PTR)AllocPage +
247 FIELD_OFFSET(CM_ALLOC_PAGE, AllocPage) +
248 i * sizeof(CM_DELAY_ALLOC));
249 InsertTailList(&CmpFreeDelayItemsListHead,
250 &Entry->ListEntry);
251
252 /* Clear the KCB pointer */
253 Entry->Kcb = NULL;
254 }
255 }
256 else
257 {
258 /* Release the lock */
259 KeReleaseGuardedMutex(&CmpDelayAllocBucketLock);
260 return NULL;
261 }
262
263 /* Do the search again */
264 goto SearchList;
265 }
266
267 VOID
268 NTAPI
269 CmpFreeDelayItem(PVOID Entry)
270 {
271 PCM_DELAY_ALLOC AllocEntry = (PCM_DELAY_ALLOC)Entry;
272 PCM_ALLOC_PAGE AllocPage;
273 ULONG i;
274 PAGED_CODE();
275
276 /* Lock the table */
277 KeAcquireGuardedMutex(&CmpDelayAllocBucketLock);
278
279 /* Add the entry at the end */
280 InsertTailList(&CmpFreeDelayItemsListHead, &AllocEntry->ListEntry);
281
282 /* Get the alloc page */
283 AllocPage = (PCM_ALLOC_PAGE)((ULONG_PTR)Entry & 0xFFFFF000);
284 ASSERT(AllocPage->FreeCount != CM_DELAYS_PER_PAGE);
285
286 /* Increase the number of free items */
287 if (++AllocPage->FreeCount == CM_DELAYS_PER_PAGE)
288 {
289 /* Page is totally free now, loop each entry */
290 for (i = 0; i < CM_DELAYS_PER_PAGE; i++)
291 {
292 /* Get the entry and unlink it */
293 AllocEntry = (PVOID)((ULONG_PTR)AllocPage +
294 FIELD_OFFSET(CM_ALLOC_PAGE, AllocPage) +
295 i * sizeof(CM_DELAY_ALLOC));
296 RemoveEntryList(&AllocEntry->ListEntry);
297 }
298
299 /* Now free the page */
300 ExFreePool(AllocPage);
301 }
302
303 /* Release the lock */
304 KeReleaseGuardedMutex(&CmpDelayAllocBucketLock);
305 }