ReactOS  0.4.13-dev-101-g0ca4b50
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 
15 typedef struct _GDI_POOL_SECTION
16 {
19 
21 
24 
28 
29 typedef 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 
44 } GDI_POOL;
45 
46 #define GDI_POOL_ALLOCATION_GRANULARITY 64 * 1024
47 
48 static
51 {
52  PGDI_POOL_SECTION pSection;
53  PVOID pvBaseAddress;
54  SIZE_T cjSize;
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 
93 static
94 VOID
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,
113  MEM_RELEASE);
115 
116  /* Free the section object */
117  EngFreeMem(pSection);
118 }
119 
120 PVOID
121 NTAPI
123  PGDI_POOL pPool)
124 {
125  PGDI_POOL_SECTION pSection;
126  ULONG ulIndex, cjOffset, ulPageBit;
127  PLIST_ENTRY ple;
128  PVOID pvAlloc, pvBaseAddress;
129  SIZE_T cjSize;
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 comitted */
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,
199  MEM_COMMIT,
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 
222 done:
223  /* Release the pool lock and enable APCs */
226 
227  DPRINT("GdiPoolallocate: %p\n", pvAlloc);
228  return pvAlloc;
229 }
230 
231 VOID
232 NTAPI
234  PGDI_POOL pPool,
235  PVOID pvAlloc)
236 {
237  PLIST_ENTRY ple;
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 
308 done:
309  /* Release the pool lock and enable APCs */
312 }
313 
314 PGDI_POOL
315 NTAPI
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 
341 VOID
342 NTAPI
344 {
345  PGDI_POOL_SECTION pSection;
346  PLIST_ENTRY ple;
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 }
FORCEINLINE VOID ExAcquirePushLockExclusive(PEX_PUSH_LOCK PushLock)
Definition: ex.h:1022
#define TRUE
Definition: types.h:120
NTSYSAPI void WINAPI RtlInitializeBitMap(PRTL_BITMAP, PULONG, ULONG)
#define DbgPrint
Definition: loader.c:25
VOID NTAPI GdiPoolFree(PGDI_POOL pPool, PVOID pvAlloc)
Definition: gdipool.c:233
RTL_BITMAP bitmap
Definition: gdipool.c:25
#define DBG_INITLOG(pslh)
Definition: gdidebug.h:110
#define EngFreeMem
Definition: polytest.cpp:56
FORCEINLINE VOID InsertHeadList(_Inout_ PLIST_ENTRY ListHead, _Inout_ __drv_aliasesMem PLIST_ENTRY Entry)
Definition: rtlfuncs.h:201
#define GDI_POOL_ALLOCATION_GRANULARITY
Definition: gdipool.c:46
LONG NTSTATUS
Definition: precomp.h:26
ULONG cSlotsPerSection
Definition: gdipool.c:34
ULONG cjAllocSize
Definition: gdipool.c:32
ULONG cAllocCount
Definition: gdipool.c:23
struct _GDI_POOL_SECTION * PGDI_POOL_SECTION
#define InsertTailList(ListHead, Entry)
#define MEM_COMMIT
Definition: nt_native.h:1313
_Must_inspect_result_ FORCEINLINE BOOLEAN IsListEmpty(_In_ const LIST_ENTRY *ListHead)
Definition: rtlfuncs.h:57
NTSYSAPI ULONG WINAPI RtlNumberOfSetBits(PCRTL_BITMAP)
uint32_t ULONG_PTR
Definition: typedefs.h:63
FORCEINLINE BOOLEAN RemoveEntryList(_In_ PLIST_ENTRY Entry)
Definition: rtlfuncs.h:105
PGDI_POOL NTAPI GdiPoolCreate(ULONG cjAllocSize, ULONG ulTag)
Definition: gdipool.c:316
NTSTATUS(* NTAPI)(IN PFILE_FULL_EA_INFORMATION EaBuffer, IN ULONG EaLength, OUT PULONG ErrorOffset)
Definition: IoEaTest.cpp:117
EX_PUSH_LOCK pushlock
Definition: gdipool.c:36
#define DBG_LOGEVENT(pslh, type, val)
Definition: gdidebug.h:109
LIST_ENTRY leEmptyList
Definition: gdipool.c:42
#define MEM_RESERVE
Definition: nt_native.h:1314
FORCEINLINE VOID ExReleasePushLockExclusive(PEX_PUSH_LOCK PushLock)
Definition: ex.h:1238
LIST_ENTRY leReadyLink
Definition: gdipool.c:18
struct _GDI_POOL_SECTION GDI_POOL_SECTION
smooth NULL
Definition: ftsmooth.c:416
FORCEINLINE PLIST_ENTRY RemoveHeadList(_Inout_ PLIST_ENTRY ListHead)
Definition: rtlfuncs.h:128
void DPRINT(...)
Definition: polytest.cpp:61
#define ExInitializePushLock
Definition: ex.h:999
LIST_ENTRY leInUseLink
Definition: gdipool.c:17
void * PVOID
Definition: retypes.h:9
PVOID NTAPI GdiPoolAllocate(PGDI_POOL pPool)
Definition: gdipool.c:122
PFLT_MESSAGE_WAITER_QUEUE CONTAINING_RECORD(Csq, DEVICE_EXTENSION, IrpQueue)) -> WaiterQ.mLock) _IRQL_raises_(DISPATCH_LEVEL) VOID NTAPI FltpAcquireMessageWaiterLock(_In_ PIO_CSQ Csq, _Out_ PKIRQL Irql)
Definition: Messaging.c:560
#define ADDRESS_AND_SIZE_TO_SPAN_PAGES(_Va, _Size)
#define NtCurrentProcess()
Definition: nt_native.h:1657
NTSYSAPI void WINAPI RtlClearAllBits(PRTL_BITMAP)
struct _LIST_ENTRY * Flink
Definition: typedefs.h:119
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:32
PVOID pvBaseAddress
Definition: gdipool.c:20
VOID NTAPI RtlClearBit(_In_ PRTL_BITMAP BitMapHeader, _In_ BITMAP_INDEX BitNumber)
Definition: bitmap.c:294
#define PAGE_ALIGN(Va)
ULONG ulTag
Definition: gdipool.c:31
_Must_inspect_result_ NTSYSAPI BOOLEAN NTAPI RtlTestBit(_In_ PRTL_BITMAP BitMapHeader, _In_range_(<, BitMapHeader->SizeOfBitMap) ULONG BitNumber)
Definition: bitmap.c:434
LIST_ENTRY leInUseList
Definition: gdipool.c:41
ASSERT((InvokeOnSuccess||InvokeOnError||InvokeOnCancel) ?(CompletionRoutine !=NULL) :TRUE)
void * EngAllocMem(int zero, unsigned long size, int tag=0)
Definition: polytest.cpp:70
#define DBG_DUMP_EVENT_LIST(pslh)
Definition: gdidebug.h:111
#define KeEnterCriticalRegion()
Definition: ke_x.h:83
ULONG cjSectionSize
Definition: gdipool.c:33
#define PAGE_SIZE
Definition: env_spec_w32.h:49
Definition: typedefs.h:117
NTSYSAPI ULONG WINAPI RtlFindClearBitsAndSet(PRTL_BITMAP, ULONG, ULONG)
ULONG aulBits[1]
Definition: gdipool.c:26
#define MAXULONG
Definition: typedefs.h:250
struct _GDI_POOL GDI_POOL
_In_ ULONG _In_ ULONG ulTag
Definition: winddi.h:3941
ULONG_PTR SIZE_T
Definition: typedefs.h:78
ULONG ulIndex
Definition: symbols.c:92
ULONG ulCommitBitmap
Definition: gdipool.c:22
#define KeLeaveCriticalRegion()
Definition: ke_x.h:114
LIST_ENTRY leReadyList
Definition: gdipool.c:43
#define InitializeListHead(ListHead)
Definition: env_spec_w32.h:944
#define DPRINT1
Definition: precomp.h:8
ULONG cEmptySections
Definition: gdipool.c:35
#define DBG_CLEANUP_EVENT_LIST(pslh)
Definition: gdidebug.h:112
#define MEM_RELEASE
Definition: nt_native.h:1316
static PGDI_POOL_SECTION GdiPoolAllocateSection(PGDI_POOL pPool)
Definition: gdipool.c:50
unsigned int ULONG
Definition: retypes.h:1
static VOID GdiPoolDeleteSection(PGDI_POOL pPool, PGDI_POOL_SECTION pSection)
Definition: gdipool.c:95
_In_ ULONG cjSize
Definition: winddi.h:3634
#define ULONG_PTR
Definition: config.h:101
static SERVICE_STATUS status
Definition: service.c:31
VOID NTAPI GdiPoolDestroy(PGDI_POOL pPool)
Definition: gdipool.c:343
#define PAGE_READWRITE
Definition: nt_native.h:1304
Definition: ps.c:97