Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygengdipool.c
Go to the documentation of this file.
00001 /* 00002 * PROJECT: ReactOS win32 kernel mode subsystem 00003 * LICENSE: GPL - See COPYING in the top level directory 00004 * FILE: subsystems/win32/win32k/objects/gdipool.c 00005 * PURPOSE: Static size allocator for user mode object attributes 00006 * PROGRAMMERS: Timo Kreuzer 00007 */ 00008 00009 /* INCLUDES ******************************************************************/ 00010 00011 #include <win32k.h> 00012 #define NDEBUG 00013 #include <debug.h> 00014 00015 typedef struct _GDI_POOL_SECTION 00016 { 00017 LIST_ENTRY leInUseLink; 00018 LIST_ENTRY leReadyLink; 00019 00020 PVOID pvBaseAddress; 00021 00022 ULONG ulCommitBitmap; 00023 ULONG cAllocCount; 00024 00025 RTL_BITMAP bitmap; 00026 ULONG aulBits[1]; 00027 } GDI_POOL_SECTION, *PGDI_POOL_SECTION; 00028 00029 typedef struct _GDI_POOL 00030 { 00031 ULONG ulTag; 00032 ULONG cjAllocSize; 00033 ULONG cjSectionSize; // 32 * cjAllocSize, rounded up to pages 00034 ULONG cSlotsPerSection; 00035 ULONG cEmptySections; 00036 EX_PUSH_LOCK pushlock; // For pool growth 00037 #if DBG_ENABLE_EVENT_LOGGING 00038 SLIST_HEADER slhLog; 00039 #endif 00040 00041 LIST_ENTRY leInUseList; 00042 LIST_ENTRY leEmptyList; 00043 LIST_ENTRY leReadyList; 00044 } GDI_POOL; 00045 00046 #define GDI_POOL_ALLOCATION_GRANULARITY 64 * 1024 00047 00048 static 00049 PGDI_POOL_SECTION 00050 GdiPoolAllocateSection(PGDI_POOL pPool) 00051 { 00052 PGDI_POOL_SECTION pSection; 00053 PVOID pvBaseAddress; 00054 SIZE_T cjSize; 00055 NTSTATUS status; 00056 00057 /* Allocate a section object */ 00058 cjSize = sizeof(GDI_POOL_SECTION) + pPool->cSlotsPerSection / sizeof(ULONG); 00059 pSection = EngAllocMem(0, cjSize, pPool->ulTag); 00060 if (!pSection) 00061 { 00062 return NULL; 00063 } 00064 00065 /* Reserve user mode memory */ 00066 cjSize = GDI_POOL_ALLOCATION_GRANULARITY; 00067 pvBaseAddress = NULL; 00068 status = ZwAllocateVirtualMemory(NtCurrentProcess(), 00069 &pvBaseAddress, 00070 0, 00071 &cjSize, 00072 MEM_RESERVE, 00073 PAGE_READWRITE); 00074 if (!NT_SUCCESS(status)) 00075 { 00076 EngFreeMem(pSection); 00077 return NULL; 00078 } 00079 00080 /* Initialize the section */ 00081 pSection->pvBaseAddress = pvBaseAddress; 00082 pSection->ulCommitBitmap = 0; 00083 pSection->cAllocCount = 0; 00084 RtlInitializeBitMap(&pSection->bitmap, 00085 pSection->aulBits, 00086 pPool->cSlotsPerSection); 00087 RtlClearAllBits(&pSection->bitmap); 00088 00089 /* Return the section */ 00090 return pSection; 00091 } 00092 00093 static 00094 VOID 00095 GdiPoolDeleteSection(PGDI_POOL pPool, PGDI_POOL_SECTION pSection) 00096 { 00097 NTSTATUS status; 00098 SIZE_T cjSize = 0; 00099 00100 /* Should not have any allocations */ 00101 if (pSection->cAllocCount != 0) 00102 { 00103 DPRINT1("There are %ld allocations left, section=%p, pool=%p\n", 00104 pSection->cAllocCount, pSection, pPool); 00105 DBG_DUMP_EVENT_LIST(&pPool->slhLog); 00106 ASSERT(FALSE); 00107 } 00108 00109 /* Release the virtual memory */ 00110 status = ZwFreeVirtualMemory(NtCurrentProcess(), 00111 &pSection->pvBaseAddress, 00112 &cjSize, 00113 MEM_RELEASE); 00114 ASSERT(NT_SUCCESS(status)); 00115 00116 /* Free the section object */ 00117 EngFreeMem(pSection); 00118 } 00119 00120 PVOID 00121 NTAPI 00122 GdiPoolAllocate( 00123 PGDI_POOL pPool) 00124 { 00125 PGDI_POOL_SECTION pSection; 00126 ULONG ulIndex, cjOffset, ulPageBit; 00127 PLIST_ENTRY ple; 00128 PVOID pvAlloc, pvBaseAddress; 00129 SIZE_T cjSize; 00130 00131 /* Disable APCs and acquire the pool lock */ 00132 KeEnterCriticalRegion(); 00133 ExAcquirePushLockExclusive(&pPool->pushlock); 00134 00135 /* Check if we have a ready section */ 00136 if (!IsListEmpty(&pPool->leReadyList)) 00137 { 00138 /* Get a free section */ 00139 ple = pPool->leReadyList.Flink; 00140 pSection = CONTAINING_RECORD(ple, GDI_POOL_SECTION, leReadyLink); 00141 if (pSection->cAllocCount >= pPool->cSlotsPerSection) 00142 { 00143 DPRINT1("pSection->cAllocCount=%ld, pPool->cSlotsPerSection=%ld\n", 00144 pSection->cAllocCount, pPool->cSlotsPerSection); 00145 DBG_DUMP_EVENT_LIST(&pPool->slhLog); 00146 ASSERT(FALSE); 00147 } 00148 ASSERT(pSection->cAllocCount < pPool->cSlotsPerSection); 00149 } 00150 else 00151 { 00152 /* No, check if we have something on the empty list */ 00153 if (!IsListEmpty(&pPool->leEmptyList)) 00154 { 00155 /* Yes, remove it from the empty list */ 00156 ple = RemoveHeadList(&pPool->leEmptyList); 00157 pSection = CONTAINING_RECORD(ple, GDI_POOL_SECTION, leInUseLink); 00158 } 00159 else 00160 { 00161 /* No, allocate a new section */ 00162 pSection = GdiPoolAllocateSection(pPool); 00163 if (!pSection) 00164 { 00165 DPRINT1("Couldn't allocate a section\n"); 00166 pvAlloc = NULL; 00167 goto done; 00168 } 00169 00170 /* Insert it into the ready list */ 00171 InsertHeadList(&pPool->leReadyList, &pSection->leReadyLink); 00172 } 00173 00174 /* Insert it into the in-use list */ 00175 InsertHeadList(&pPool->leInUseList, &pSection->leInUseLink); 00176 } 00177 00178 /* Find and set a single bit */ 00179 ulIndex = RtlFindClearBitsAndSet(&pSection->bitmap, 1, 0); 00180 ASSERT(ulIndex != MAXULONG); 00181 00182 /* Calculate the allocation address */ 00183 cjOffset = ulIndex * pPool->cjAllocSize; 00184 pvAlloc = (PVOID)((ULONG_PTR)pSection->pvBaseAddress + cjOffset); 00185 00186 /* Check if memory is comitted */ 00187 ulPageBit = 1 << (cjOffset / PAGE_SIZE); 00188 ulPageBit |= 1 << ((cjOffset + pPool->cjAllocSize - 1) / PAGE_SIZE); 00189 if ((pSection->ulCommitBitmap & ulPageBit) != ulPageBit) 00190 { 00191 /* Commit the pages */ 00192 pvBaseAddress = PAGE_ALIGN(pvAlloc); 00193 cjSize = ADDRESS_AND_SIZE_TO_SPAN_PAGES(pvAlloc, pPool->cjAllocSize) * PAGE_SIZE; 00194 ZwAllocateVirtualMemory(NtCurrentProcess(), 00195 &pvBaseAddress, 00196 0, 00197 &cjSize, 00198 MEM_COMMIT, 00199 PAGE_READWRITE); 00200 00201 pSection->ulCommitBitmap |= ulPageBit; 00202 } 00203 00204 /* Increase alloc count */ 00205 pSection->cAllocCount++; 00206 DBG_LOGEVENT(&pPool->slhLog, EVENT_ALLOCATE, pvAlloc); 00207 00208 /* Check if section is now busy */ 00209 if (pSection->cAllocCount == pPool->cSlotsPerSection) 00210 { 00211 /* Remove the section from the ready list */ 00212 RemoveEntryList(&pSection->leReadyLink); 00213 } 00214 00215 done: 00216 /* Release the pool lock and enable APCs */ 00217 ExReleasePushLockExclusive(&pPool->pushlock); 00218 KeLeaveCriticalRegion(); 00219 00220 DPRINT("GdiPoolallocate: %p\n", pvAlloc); 00221 return pvAlloc; 00222 } 00223 00224 VOID 00225 NTAPI 00226 GdiPoolFree( 00227 PGDI_POOL pPool, 00228 PVOID pvAlloc) 00229 { 00230 PLIST_ENTRY ple; 00231 PGDI_POOL_SECTION pSection = NULL; 00232 ULONG_PTR cjOffset; 00233 ULONG ulIndex; 00234 DPRINT("GdiPoolFree: %p\n", pvAlloc); 00235 00236 /* Disable APCs and acquire the pool lock */ 00237 KeEnterCriticalRegion(); 00238 ExAcquirePushLockExclusive(&pPool->pushlock); 00239 00240 /* Loop all used sections */ 00241 for (ple = pPool->leInUseList.Flink; 00242 ple != &pPool->leInUseList; 00243 ple = ple->Flink) 00244 { 00245 /* Get the pointer to the section */ 00246 pSection = CONTAINING_RECORD(ple, GDI_POOL_SECTION, leInUseLink); 00247 00248 /* Calculate offset */ 00249 cjOffset = (ULONG_PTR)pvAlloc - (ULONG_PTR)pSection->pvBaseAddress; 00250 00251 /* Check if the allocation is from this section */ 00252 if (cjOffset < pPool->cjSectionSize) 00253 { 00254 /* Calculate the index of the allocation */ 00255 ulIndex = cjOffset / pPool->cjAllocSize; 00256 00257 /* Mark it as free */ 00258 ASSERT(RtlTestBit(&pSection->bitmap, ulIndex) == TRUE); 00259 RtlClearBit(&pSection->bitmap, ulIndex); 00260 00261 /* Decrease allocation count */ 00262 pSection->cAllocCount--; 00263 DBG_LOGEVENT(&pPool->slhLog, EVENT_FREE, pvAlloc); 00264 00265 /* Check if the section got valid now */ 00266 if (pSection->cAllocCount == pPool->cSlotsPerSection - 1) 00267 { 00268 /* Insert it into the ready list */ 00269 InsertTailList(&pPool->leReadyList, &pSection->leReadyLink); 00270 } 00271 /* Check if it got empty now */ 00272 else if (pSection->cAllocCount == 0) 00273 { 00274 /* Remove the section from the lists */ 00275 RemoveEntryList(&pSection->leInUseLink); 00276 RemoveEntryList(&pSection->leReadyLink); 00277 00278 if (pPool->cEmptySections > 1) 00279 { 00280 /* Delete the section */ 00281 GdiPoolDeleteSection(pPool, pSection); 00282 } 00283 else 00284 { 00285 /* Insert it into the empty list */ 00286 InsertHeadList(&pPool->leEmptyList, &pSection->leInUseLink); 00287 pPool->cEmptySections++; 00288 } 00289 } 00290 00291 goto done; 00292 } 00293 } 00294 00295 DbgPrint("failed to free. pvAlloc=%p, base=%p, size=%lx\n", 00296 pvAlloc, pSection->pvBaseAddress, pPool->cjSectionSize); 00297 ASSERT(FALSE); 00298 // KeBugCheck() 00299 00300 done: 00301 /* Release the pool lock and enable APCs */ 00302 ExReleasePushLockExclusive(&pPool->pushlock); 00303 KeLeaveCriticalRegion(); 00304 } 00305 00306 PGDI_POOL 00307 NTAPI 00308 GdiPoolCreate( 00309 ULONG cjAllocSize, 00310 ULONG ulTag) 00311 { 00312 PGDI_POOL pPool; 00313 00314 /* Allocate a pool object */ 00315 pPool = EngAllocMem(0, sizeof(GDI_POOL), 'lopG'); 00316 if (!pPool) return NULL; 00317 00318 /* Initialize the object */ 00319 ExInitializePushLock(&pPool->pushlock); 00320 InitializeListHead(&pPool->leInUseList); 00321 InitializeListHead(&pPool->leReadyList); 00322 InitializeListHead(&pPool->leEmptyList); 00323 pPool->cEmptySections = 0; 00324 pPool->cjAllocSize = cjAllocSize; 00325 pPool->ulTag = ulTag; 00326 pPool->cjSectionSize = GDI_POOL_ALLOCATION_GRANULARITY; 00327 pPool->cSlotsPerSection = pPool->cjSectionSize / cjAllocSize; 00328 DBG_INITLOG(&pPool->slhLog); 00329 00330 return pPool; 00331 } 00332 00333 VOID 00334 NTAPI 00335 GdiPoolDestroy(PGDI_POOL pPool) 00336 { 00337 PGDI_POOL_SECTION pSection; 00338 PLIST_ENTRY ple; 00339 00340 /* Loop all empty sections, removing them */ 00341 while (!IsListEmpty(&pPool->leEmptyList)) 00342 { 00343 /* Delete the section */ 00344 ple = RemoveHeadList(&pPool->leEmptyList); 00345 pSection = CONTAINING_RECORD(ple, GDI_POOL_SECTION, leInUseLink); 00346 GdiPoolDeleteSection(pPool, pSection); 00347 } 00348 00349 /* Loop all ready sections, removing them */ 00350 while (!IsListEmpty(&pPool->leInUseList)) 00351 { 00352 /* Delete the section */ 00353 ple = RemoveHeadList(&pPool->leInUseList); 00354 pSection = CONTAINING_RECORD(ple, GDI_POOL_SECTION, leInUseLink); 00355 GdiPoolDeleteSection(pPool, pSection); 00356 } 00357 00358 DBG_CLEANUP_EVENT_LIST(&pPool->slhLog); 00359 00360 EngFreeMem(pPool); 00361 } Generated on Sun May 27 2012 04:38:26 for ReactOS by
1.7.6.1
|