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