xref: /reactos/ntoskrnl/config/cmalloc.c (revision 5c7ce447)
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 CODE_SEG("INIT")
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 CODE_SEG("INIT")
42 VOID
43 NTAPI
44 CmpInitCmPrivateDelayAlloc(VOID)
45 {
46     /* Initialize the delay allocation list and lock */
47     KeInitializeGuardedMutex(&CmpDelayAllocBucketLock);
48     InitializeListHead(&CmpFreeDelayItemsListHead);
49 }
50 
51 VOID
52 NTAPI
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
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 
181     /* Allocate a KCB only */
182     CurrentKcb = CmpAllocate(sizeof(CM_KEY_CONTROL_BLOCK), TRUE, TAG_KCB);
183     if (CurrentKcb)
184     {
185         /* Set it up */
186         CurrentKcb->PrivateAlloc = 0;
187         CurrentKcb->DelayCloseEntry = NULL;
188     }
189 
190     /* Return it */
191     return CurrentKcb;
192 }
193 
194 PVOID
195 NTAPI
196 CmpAllocateDelayItem(VOID)
197 {
198     PCM_DELAY_ALLOC Entry;
199     PCM_ALLOC_PAGE AllocPage;
200     ULONG i;
201     PLIST_ENTRY NextEntry;
202     PAGED_CODE();
203 
204     /* Lock the allocation buckets */
205     KeAcquireGuardedMutex(&CmpDelayAllocBucketLock);
206 
207     /* Look for an item on the free list */
208 SearchList:
209     if (!IsListEmpty(&CmpFreeDelayItemsListHead))
210     {
211         /* Get the current entry in the list */
212         NextEntry = RemoveHeadList(&CmpFreeDelayItemsListHead);
213 
214         /* Grab the item */
215         Entry = CONTAINING_RECORD(NextEntry, CM_DELAY_ALLOC, ListEntry);
216 
217         /* Clear the list */
218         Entry->ListEntry.Flink = Entry->ListEntry.Blink = NULL;
219 
220         /* Grab the alloc page */
221         AllocPage = CmpGetAllocPageFromDelayAlloc(Entry);
222 
223         /* Decrease free entries */
224         ASSERT(AllocPage->FreeCount != 0);
225         AllocPage->FreeCount--;
226 
227         /* Release the lock */
228         KeReleaseGuardedMutex(&CmpDelayAllocBucketLock);
229         return Entry;
230     }
231 
232     /* Allocate an allocation page */
233     AllocPage = CmpAllocate(PAGE_SIZE, TRUE, TAG_CM);
234     if (AllocPage)
235     {
236         /* Set default entries */
237         AllocPage->FreeCount = CM_DELAYS_PER_PAGE;
238 
239         /* Loop each entry */
240         for (i = 0; i < CM_DELAYS_PER_PAGE; i++)
241         {
242             /* Get this entry and link it */
243             Entry = (PVOID)((ULONG_PTR)AllocPage +
244                             FIELD_OFFSET(CM_ALLOC_PAGE, AllocPage) +
245                             i * sizeof(CM_DELAY_ALLOC));
246             InsertTailList(&CmpFreeDelayItemsListHead,
247                            &Entry->ListEntry);
248 
249             /* Clear the KCB pointer */
250             Entry->Kcb = NULL;
251         }
252     }
253     else
254     {
255         /* Release the lock */
256         KeReleaseGuardedMutex(&CmpDelayAllocBucketLock);
257         return NULL;
258     }
259 
260     /* Do the search again */
261     goto SearchList;
262 }
263 
264 VOID
265 NTAPI
266 CmpFreeDelayItem(PVOID Entry)
267 {
268     PCM_DELAY_ALLOC AllocEntry = (PCM_DELAY_ALLOC)Entry;
269     PCM_ALLOC_PAGE AllocPage;
270     ULONG i;
271     PAGED_CODE();
272 
273     /* Lock the table */
274     KeAcquireGuardedMutex(&CmpDelayAllocBucketLock);
275 
276     /* Add the entry at the end */
277     InsertTailList(&CmpFreeDelayItemsListHead, &AllocEntry->ListEntry);
278 
279     /* Get the alloc page */
280     AllocPage = CmpGetAllocPageFromDelayAlloc(Entry);
281     ASSERT(AllocPage->FreeCount != CM_DELAYS_PER_PAGE);
282 
283     /* Increase the number of free items */
284     if (++AllocPage->FreeCount == CM_DELAYS_PER_PAGE)
285     {
286         /* Page is totally free now, loop each entry */
287         for (i = 0; i < CM_DELAYS_PER_PAGE; i++)
288         {
289             /* Get the entry and unlink it */
290             AllocEntry = (PVOID)((ULONG_PTR)AllocPage +
291                                  FIELD_OFFSET(CM_ALLOC_PAGE, AllocPage) +
292                                  i * sizeof(CM_DELAY_ALLOC));
293             RemoveEntryList(&AllocEntry->ListEntry);
294         }
295 
296         /* Now free the page */
297         CmpFree(AllocPage, TAG_CM);
298     }
299 
300     /* Release the lock */
301     KeReleaseGuardedMutex(&CmpDelayAllocBucketLock);
302 }
303