ReactOS 0.4.15-dev-7842-g558ab78
gdipool.c
Go to the documentation of this file.
1/*
2 * PROJECT: ReactOS win32 kernel mode subsystem
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: win32ss/gdi/ntgdi/gdipool.c
5 * PURPOSE: Static size allocator for user mode object attributes
6 * PROGRAMMERS: Timo Kreuzer
7 */
8
9/* INCLUDES ******************************************************************/
10
11#include <win32k.h>
12#define NDEBUG
13#include <debug.h>
14
15typedef struct _GDI_POOL_SECTION
16{
19
21
24
28
29typedef struct _GDI_POOL
30{
33 ULONG cjSectionSize; // 32 * cjAllocSize, rounded up to pages
36 EX_PUSH_LOCK pushlock; // For pool growth
37#if DBG_ENABLE_EVENT_LOGGING
38 SLIST_HEADER slhLog;
39#endif
40
45
46#define GDI_POOL_ALLOCATION_GRANULARITY 64 * 1024
47
48static
51{
52 PGDI_POOL_SECTION pSection;
53 PVOID pvBaseAddress;
56
57 /* Allocate a section object */
58 cjSize = sizeof(GDI_POOL_SECTION) + pPool->cSlotsPerSection / sizeof(ULONG);
59 pSection = EngAllocMem(0, cjSize, pPool->ulTag);
60 if (!pSection)
61 {
62 return NULL;
63 }
64
65 /* Reserve user mode memory */
67 pvBaseAddress = NULL;
68 status = ZwAllocateVirtualMemory(NtCurrentProcess(),
69 &pvBaseAddress,
70 0,
71 &cjSize,
74 if (!NT_SUCCESS(status))
75 {
76 EngFreeMem(pSection);
77 return NULL;
78 }
79
80 /* Initialize the section */
81 pSection->pvBaseAddress = pvBaseAddress;
82 pSection->ulCommitBitmap = 0;
83 pSection->cAllocCount = 0;
84 RtlInitializeBitMap(&pSection->bitmap,
85 pSection->aulBits,
86 pPool->cSlotsPerSection);
87 RtlClearAllBits(&pSection->bitmap);
88
89 /* Return the section */
90 return pSection;
91}
92
93static
94VOID
96{
98 SIZE_T cjSize = 0;
99
100 /* Should not have any allocations */
101 if (pSection->cAllocCount != 0)
102 {
103 DPRINT1("There are %lu allocations left, section=%p, pool=%p\n",
104 pSection->cAllocCount, pSection, pPool);
105 DBG_DUMP_EVENT_LIST(&pPool->slhLog);
106 ASSERT(FALSE);
107 }
108
109 /* Release the virtual memory */
110 status = ZwFreeVirtualMemory(NtCurrentProcess(),
111 &pSection->pvBaseAddress,
112 &cjSize,
115
116 /* Free the section object */
117 EngFreeMem(pSection);
118}
119
120PVOID
121NTAPI
123 PGDI_POOL pPool)
124{
125 PGDI_POOL_SECTION pSection;
126 ULONG ulIndex, cjOffset, ulPageBit;
128 PVOID pvAlloc, pvBaseAddress;
131
132 /* Disable APCs and acquire the pool lock */
135
136 /* Check if we have a ready section */
137 if (!IsListEmpty(&pPool->leReadyList))
138 {
139 /* Get a free section */
140 ple = pPool->leReadyList.Flink;
141 pSection = CONTAINING_RECORD(ple, GDI_POOL_SECTION, leReadyLink);
142 if (pSection->cAllocCount >= pPool->cSlotsPerSection)
143 {
144 DPRINT1("pSection->cAllocCount=%lu, pPool->cSlotsPerSection=%lu\n",
145 pSection->cAllocCount, pPool->cSlotsPerSection);
146 DBG_DUMP_EVENT_LIST(&pPool->slhLog);
147 ASSERT(FALSE);
148 }
149 ASSERT(pSection->cAllocCount < pPool->cSlotsPerSection);
150 }
151 else
152 {
153 /* No, check if we have something on the empty list */
154 if (!IsListEmpty(&pPool->leEmptyList))
155 {
156 /* Yes, remove it from the empty list */
157 ple = RemoveHeadList(&pPool->leEmptyList);
158 pSection = CONTAINING_RECORD(ple, GDI_POOL_SECTION, leInUseLink);
159 pPool->cEmptySections--;
160 ASSERT(pSection->cAllocCount == 0);
161 }
162 else
163 {
164 /* No, allocate a new section */
165 pSection = GdiPoolAllocateSection(pPool);
166 if (!pSection)
167 {
168 DPRINT1("Couldn't allocate a section\n");
169 pvAlloc = NULL;
170 goto done;
171 }
172 }
173
174 /* Insert it into the in-use and ready list */
175 InsertHeadList(&pPool->leInUseList, &pSection->leInUseLink);
176 InsertHeadList(&pPool->leReadyList, &pSection->leReadyLink);
177 }
178
179 /* Find and set a single bit */
180 ulIndex = RtlFindClearBitsAndSet(&pSection->bitmap, 1, 0);
181 ASSERT(ulIndex != MAXULONG);
182
183 /* Calculate the allocation address */
184 cjOffset = ulIndex * pPool->cjAllocSize;
185 pvAlloc = (PVOID)((ULONG_PTR)pSection->pvBaseAddress + cjOffset);
186
187 /* Check if memory is committed */
188 ulPageBit = 1 << (cjOffset / PAGE_SIZE);
189 ulPageBit |= 1 << ((cjOffset + pPool->cjAllocSize - 1) / PAGE_SIZE);
190 if ((pSection->ulCommitBitmap & ulPageBit) != ulPageBit)
191 {
192 /* Commit the pages */
193 pvBaseAddress = PAGE_ALIGN(pvAlloc);
195 status = ZwAllocateVirtualMemory(NtCurrentProcess(),
196 &pvBaseAddress,
197 0,
198 &cjSize,
201 if (!NT_SUCCESS(status))
202 {
203 pvAlloc = NULL;
204 goto done;
205 }
206
207 pSection->ulCommitBitmap |= ulPageBit;
208 }
209
210 /* Increase alloc count */
211 pSection->cAllocCount++;
212 ASSERT(RtlNumberOfSetBits(&pSection->bitmap) == pSection->cAllocCount);
213 DBG_LOGEVENT(&pPool->slhLog, EVENT_ALLOCATE, pvAlloc);
214
215 /* Check if section is now busy */
216 if (pSection->cAllocCount == pPool->cSlotsPerSection)
217 {
218 /* Remove the section from the ready list */
219 RemoveEntryList(&pSection->leReadyLink);
220 }
221
222done:
223 /* Release the pool lock and enable APCs */
226
227 DPRINT("GdiPoolallocate: %p\n", pvAlloc);
228 return pvAlloc;
229}
230
231VOID
232NTAPI
234 PGDI_POOL pPool,
235 PVOID pvAlloc)
236{
238 PGDI_POOL_SECTION pSection = NULL;
239 ULONG_PTR cjOffset;
240 ULONG ulIndex;
241 DPRINT("GdiPoolFree: %p\n", pvAlloc);
242
243 /* Disable APCs and acquire the pool lock */
246
247 /* Loop all used sections */
248 for (ple = pPool->leInUseList.Flink;
249 ple != &pPool->leInUseList;
250 ple = ple->Flink)
251 {
252 /* Get the pointer to the section */
253 pSection = CONTAINING_RECORD(ple, GDI_POOL_SECTION, leInUseLink);
254
255 /* Calculate offset */
256 cjOffset = (ULONG_PTR)pvAlloc - (ULONG_PTR)pSection->pvBaseAddress;
257
258 /* Check if the allocation is from this section */
259 if (cjOffset < pPool->cjSectionSize)
260 {
261 /* Calculate the index of the allocation */
262 ulIndex = cjOffset / pPool->cjAllocSize;
263
264 /* Mark it as free */
265 ASSERT(RtlTestBit(&pSection->bitmap, ulIndex) == TRUE);
266 RtlClearBit(&pSection->bitmap, ulIndex);
267
268 /* Decrease allocation count */
269 pSection->cAllocCount--;
270 ASSERT(RtlNumberOfSetBits(&pSection->bitmap) == pSection->cAllocCount);
271 DBG_LOGEVENT(&pPool->slhLog, EVENT_FREE, pvAlloc);
272
273 /* Check if the section got valid now */
274 if (pSection->cAllocCount == pPool->cSlotsPerSection - 1)
275 {
276 /* Insert it into the ready list */
277 InsertTailList(&pPool->leReadyList, &pSection->leReadyLink);
278 }
279 /* Check if it got empty now */
280 else if (pSection->cAllocCount == 0)
281 {
282 /* Remove the section from the lists */
283 RemoveEntryList(&pSection->leInUseLink);
284 RemoveEntryList(&pSection->leReadyLink);
285
286 if (pPool->cEmptySections >= 1)
287 {
288 /* Delete the section */
289 GdiPoolDeleteSection(pPool, pSection);
290 }
291 else
292 {
293 /* Insert it into the empty list */
294 InsertHeadList(&pPool->leEmptyList, &pSection->leInUseLink);
295 pPool->cEmptySections++;
296 }
297 }
298
299 goto done;
300 }
301 }
302
303 DbgPrint("failed to free. pvAlloc=%p, base=%p, size=%lx\n",
304 pvAlloc, pSection ? pSection->pvBaseAddress : NULL, pPool->cjSectionSize);
305 ASSERT(FALSE);
306 // KeBugCheck()
307
308done:
309 /* Release the pool lock and enable APCs */
312}
313
315NTAPI
317 ULONG cjAllocSize,
318 ULONG ulTag)
319{
320 PGDI_POOL pPool;
321
322 /* Allocate a pool object */
323 pPool = EngAllocMem(0, sizeof(GDI_POOL), 'lopG');
324 if (!pPool) return NULL;
325
326 /* Initialize the object */
331 pPool->cEmptySections = 0;
332 pPool->cjAllocSize = cjAllocSize;
333 pPool->ulTag = ulTag;
335 pPool->cSlotsPerSection = pPool->cjSectionSize / cjAllocSize;
336 DBG_INITLOG(&pPool->slhLog);
337
338 return pPool;
339}
340
341VOID
342NTAPI
344{
345 PGDI_POOL_SECTION pSection;
347
348 /* Loop all empty sections, removing them */
349 while (!IsListEmpty(&pPool->leEmptyList))
350 {
351 /* Delete the section */
352 ple = RemoveHeadList(&pPool->leEmptyList);
353 pSection = CONTAINING_RECORD(ple, GDI_POOL_SECTION, leInUseLink);
354 GdiPoolDeleteSection(pPool, pSection);
355 }
356
357 /* Loop all ready sections, removing them */
358 while (!IsListEmpty(&pPool->leInUseList))
359 {
360 /* Delete the section */
361 ple = RemoveHeadList(&pPool->leInUseList);
362 pSection = CONTAINING_RECORD(ple, GDI_POOL_SECTION, leInUseLink);
363 GdiPoolDeleteSection(pPool, pSection);
364 }
365
366 DBG_CLEANUP_EVENT_LIST(&pPool->slhLog);
367
368 EngFreeMem(pPool);
369}
LONG NTSTATUS
Definition: precomp.h:26
#define DPRINT1
Definition: precomp.h:8
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:32
#define ULONG_PTR
Definition: config.h:101
#define RemoveEntryList(Entry)
Definition: env_spec_w32.h:986
#define InsertTailList(ListHead, Entry)
#define InsertHeadList(ListHead, Entry)
#define IsListEmpty(ListHead)
Definition: env_spec_w32.h:954
#define PAGE_SIZE
Definition: env_spec_w32.h:49
#define RemoveHeadList(ListHead)
Definition: env_spec_w32.h:964
#define InitializeListHead(ListHead)
Definition: env_spec_w32.h:944
#define ExInitializePushLock
Definition: ex.h:1013
FORCEINLINE VOID ExAcquirePushLockExclusive(PEX_PUSH_LOCK PushLock)
Definition: ex.h:1036
FORCEINLINE VOID ExReleasePushLockExclusive(PEX_PUSH_LOCK PushLock)
Definition: ex.h:1252
PSINGLE_LIST_ENTRY ple
#define DBG_LOGEVENT(pslh, type, val)
Definition: gdidebug.h:109
#define DBG_CLEANUP_EVENT_LIST(pslh)
Definition: gdidebug.h:112
#define DBG_DUMP_EVENT_LIST(pslh)
Definition: gdidebug.h:111
#define DBG_INITLOG(pslh)
Definition: gdidebug.h:110
struct _GDI_POOL GDI_POOL
PGDI_POOL NTAPI GdiPoolCreate(ULONG cjAllocSize, ULONG ulTag)
Definition: gdipool.c:316
VOID NTAPI GdiPoolFree(PGDI_POOL pPool, PVOID pvAlloc)
Definition: gdipool.c:233
static VOID GdiPoolDeleteSection(PGDI_POOL pPool, PGDI_POOL_SECTION pSection)
Definition: gdipool.c:95
struct _GDI_POOL_SECTION * PGDI_POOL_SECTION
struct _GDI_POOL_SECTION GDI_POOL_SECTION
static PGDI_POOL_SECTION GdiPoolAllocateSection(PGDI_POOL pPool)
Definition: gdipool.c:50
#define GDI_POOL_ALLOCATION_GRANULARITY
Definition: gdipool.c:46
VOID NTAPI GdiPoolDestroy(PGDI_POOL pPool)
Definition: gdipool.c:343
PVOID NTAPI GdiPoolAllocate(PGDI_POOL pPool)
Definition: gdipool.c:122
#define DbgPrint
Definition: hal.h:12
NTSYSAPI void WINAPI RtlInitializeBitMap(PRTL_BITMAP, PULONG, ULONG)
NTSYSAPI ULONG WINAPI RtlNumberOfSetBits(PCRTL_BITMAP)
NTSYSAPI void WINAPI RtlClearAllBits(PRTL_BITMAP)
NTSYSAPI ULONG WINAPI RtlFindClearBitsAndSet(PRTL_BITMAP, ULONG, ULONG)
#define KeLeaveCriticalRegion()
Definition: ke_x.h:119
#define KeEnterCriticalRegion()
Definition: ke_x.h:88
#define ASSERT(a)
Definition: mode.c:44
#define PAGE_READWRITE
Definition: nt_native.h:1304
#define NtCurrentProcess()
Definition: nt_native.h:1657
#define MEM_RESERVE
Definition: nt_native.h:1314
#define MEM_RELEASE
Definition: nt_native.h:1316
#define MEM_COMMIT
Definition: nt_native.h:1313
#define EngFreeMem
Definition: polytest.cpp:56
void * EngAllocMem(int zero, unsigned long size, int tag=0)
Definition: polytest.cpp:70
VOID NTAPI RtlClearBit(_In_ PRTL_BITMAP BitMapHeader, _In_ BITMAP_INDEX BitNumber)
Definition: bitmap.c:294
#define DPRINT
Definition: sndvol32.h:71
ULONG aulBits[1]
Definition: gdipool.c:26
ULONG cAllocCount
Definition: gdipool.c:23
LIST_ENTRY leReadyLink
Definition: gdipool.c:18
RTL_BITMAP bitmap
Definition: gdipool.c:25
ULONG ulCommitBitmap
Definition: gdipool.c:22
LIST_ENTRY leInUseLink
Definition: gdipool.c:17
PVOID pvBaseAddress
Definition: gdipool.c:20
ULONG ulTag
Definition: gdipool.c:31
LIST_ENTRY leInUseList
Definition: gdipool.c:41
EX_PUSH_LOCK pushlock
Definition: gdipool.c:36
ULONG cEmptySections
Definition: gdipool.c:35
ULONG cjSectionSize
Definition: gdipool.c:33
ULONG cSlotsPerSection
Definition: gdipool.c:34
LIST_ENTRY leEmptyList
Definition: gdipool.c:42
ULONG cjAllocSize
Definition: gdipool.c:32
LIST_ENTRY leReadyList
Definition: gdipool.c:43
Definition: typedefs.h:120
struct _LIST_ENTRY * Flink
Definition: typedefs.h:121
Definition: ps.c:97
#define MAXULONG
Definition: typedefs.h:251
#define NTAPI
Definition: typedefs.h:36
void * PVOID
Definition: typedefs.h:50
ULONG_PTR SIZE_T
Definition: typedefs.h:80
uint32_t ULONG_PTR
Definition: typedefs.h:65
#define CONTAINING_RECORD(address, type, field)
Definition: typedefs.h:260
uint32_t ULONG
Definition: typedefs.h:59
_In_ ULONG _In_ ULONG ulTag
Definition: winddi.h:3942
_In_ ULONG cjSize
Definition: winddi.h:3634
#define PAGE_ALIGN(Va)
#define ADDRESS_AND_SIZE_TO_SPAN_PAGES(_Va, _Size)
_Must_inspect_result_ NTSYSAPI BOOLEAN NTAPI RtlTestBit(_In_ PRTL_BITMAP BitMapHeader, _In_range_(<, BitMapHeader->SizeOfBitMap) ULONG BitNumber)
Definition: bitmap.c:434