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;
19 LIST_ENTRY CmpFreeKCBListHead;
20
21 KGUARDED_MUTEX CmpDelayAllocBucketLock;
22 LIST_ENTRY CmpFreeDelayItemsListHead;
23
24 /* FUNCTIONS *****************************************************************/
25
26 CODE_SEG("INIT")
27 VOID
28 NTAPI
CmpInitCmPrivateAlloc(VOID)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 CODE_SEG("INIT")
42 VOID
43 NTAPI
CmpInitCmPrivateDelayAlloc(VOID)44 CmpInitCmPrivateDelayAlloc(VOID)
45 {
46 /* Initialize the delay allocation list and lock */
47 KeInitializeGuardedMutex(&CmpDelayAllocBucketLock);
48 InitializeListHead(&CmpFreeDelayItemsListHead);
49 }
50
51 VOID
52 NTAPI
CmpFreeKeyControlBlock(IN PCM_KEY_CONTROL_BLOCK Kcb)53 CmpFreeKeyControlBlock(IN PCM_KEY_CONTROL_BLOCK Kcb)
54 {
55 ULONG i;
56 PCM_ALLOC_PAGE AllocPage;
57 PAGED_CODE();
58
59 /* Sanity checks */
60 ASSERT(IsListEmpty(&Kcb->KeyBodyListHead) == TRUE);
61 for (i = 0; i < 4; i++) ASSERT(Kcb->KeyBodyArray[i] == NULL);
62
63 /* Check if it wasn't privately allocated */
64 if (!Kcb->PrivateAlloc)
65 {
66 /* Free it from the pool */
67 CmpFree(Kcb, TAG_KCB);
68 return;
69 }
70
71 /* Acquire the private allocation lock */
72 KeAcquireGuardedMutex(&CmpAllocBucketLock);
73
74 /* Sanity check on lock ownership */
75 CMP_ASSERT_HASH_ENTRY_LOCK(Kcb->ConvKey);
76
77 /* Add us to the free list */
78 InsertTailList(&CmpFreeKCBListHead, &Kcb->FreeListEntry);
79
80 /* Get the allocation page */
81 AllocPage = CmpGetAllocPageFromKcb(Kcb);
82
83 /* Sanity check */
84 ASSERT(AllocPage->FreeCount != CM_KCBS_PER_PAGE);
85
86 /* Increase free count */
87 if (++AllocPage->FreeCount == CM_KCBS_PER_PAGE)
88 {
89 /* Loop all the entries */
90 for (i = 0; i < CM_KCBS_PER_PAGE; i++)
91 {
92 /* Get the KCB */
93 Kcb = (PVOID)((ULONG_PTR)AllocPage +
94 FIELD_OFFSET(CM_ALLOC_PAGE, AllocPage) +
95 i * sizeof(CM_KEY_CONTROL_BLOCK));
96
97 /* Remove the entry */
98 RemoveEntryList(&Kcb->FreeListEntry);
99 }
100
101 /* Free the page */
102 CmpFree(AllocPage, TAG_KCB);
103 }
104
105 /* Release the lock */
106 KeReleaseGuardedMutex(&CmpAllocBucketLock);
107 }
108
109 PCM_KEY_CONTROL_BLOCK
110 NTAPI
CmpAllocateKeyControlBlock(VOID)111 CmpAllocateKeyControlBlock(VOID)
112 {
113 PLIST_ENTRY NextEntry;
114 PCM_KEY_CONTROL_BLOCK CurrentKcb;
115 PCM_ALLOC_PAGE AllocPage;
116 ULONG i;
117 PAGED_CODE();
118
119 /* Check if private allocations are initialized */
120 if (CmpAllocInited)
121 {
122 /* They are, acquire the bucket lock */
123 KeAcquireGuardedMutex(&CmpAllocBucketLock);
124
125 /* See if there's something on the free KCB list */
126 SearchKcbList:
127 if (!IsListEmpty(&CmpFreeKCBListHead))
128 {
129 /* Remove the entry */
130 NextEntry = RemoveHeadList(&CmpFreeKCBListHead);
131
132 /* Get the KCB */
133 CurrentKcb = CONTAINING_RECORD(NextEntry,
134 CM_KEY_CONTROL_BLOCK,
135 FreeListEntry);
136
137 /* Get the allocation page */
138 AllocPage = CmpGetAllocPageFromKcb(CurrentKcb);
139
140 /* Decrease the free count */
141 ASSERT(AllocPage->FreeCount != 0);
142 AllocPage->FreeCount--;
143
144 /* Make sure this KCB is privately allocated */
145 ASSERT(CurrentKcb->PrivateAlloc == 1);
146
147 /* Release the allocation lock */
148 KeReleaseGuardedMutex(&CmpAllocBucketLock);
149
150 /* Return the KCB */
151 return CurrentKcb;
152 }
153
154 /* Allocate an allocation page */
155 AllocPage = CmpAllocate(PAGE_SIZE, TRUE, TAG_KCB);
156 if (AllocPage)
157 {
158 /* Set default entries */
159 AllocPage->FreeCount = CM_KCBS_PER_PAGE;
160
161 /* Loop each entry */
162 for (i = 0; i < CM_KCBS_PER_PAGE; i++)
163 {
164 /* Get this entry */
165 CurrentKcb = (PVOID)((ULONG_PTR)AllocPage +
166 FIELD_OFFSET(CM_ALLOC_PAGE, AllocPage) +
167 i * sizeof(CM_KEY_CONTROL_BLOCK));
168
169 /* Set it up */
170 CurrentKcb->PrivateAlloc = TRUE;
171 CurrentKcb->DelayCloseEntry = NULL;
172 InsertTailList(&CmpFreeKCBListHead,
173 &CurrentKcb->FreeListEntry);
174 }
175
176 /* Now go back and search the list */
177 goto SearchKcbList;
178 }
179
180 /* Release the allocation lock */
181 KeReleaseGuardedMutex(&CmpAllocBucketLock);
182 }
183
184 /* Allocate a KCB only */
185 CurrentKcb = CmpAllocate(sizeof(CM_KEY_CONTROL_BLOCK), TRUE, TAG_KCB);
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
CmpAllocateDelayItem(VOID)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 = CmpGetAllocPageFromDelayAlloc(Entry);
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 = CmpAllocate(PAGE_SIZE, TRUE, 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 /* Do the search again */
257 goto SearchList;
258 }
259
260 /* Release the lock */
261 KeReleaseGuardedMutex(&CmpDelayAllocBucketLock);
262 return NULL;
263 }
264
265 VOID
266 NTAPI
CmpFreeDelayItem(PVOID Entry)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 = CmpGetAllocPageFromDelayAlloc(Entry);
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, TAG_CM);
299 }
300
301 /* Release the lock */
302 KeReleaseGuardedMutex(&CmpDelayAllocBucketLock);
303 }
304