ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

gdipool.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 doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.