xref: /reactos/ntoskrnl/config/cmalloc.c (revision c84b5007)
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