📄 sbheap.c
字号:
// one more allocation in group - test if group was empty
if (pGroup->cntEntries++ == 0)
{
// if allocating into deferred group, cancel deferral
if (pHeader == __sbh_pHeaderDefer &&
indGroupUse == __sbh_indGroupDefer)
__sbh_pHeaderDefer = NULL;
}
pRegion->indGroupUse = indGroupUse;
return (void *)((char *)pEntry + sizeof(int));
}
/***
*PHEADER __sbh_alloc_new_region()
*
*Purpose:
* Add a new HEADER structure in the header list. Allocate a new
* REGION structure and initialize. Reserve memory for future
* group commitments.
*
*Entry:
* None.
*
*Exit:
* Returns a pointer to newly created HEADER entry, if successful.
* Returns NULL, if failure.
*
*Exceptions:
*
*******************************************************************************/
PHEADER __cdecl __sbh_alloc_new_region (void)
{
PHEADER pHeader;
// create a new entry in the header list
// if list if full, realloc to extend its size
if (__sbh_cntHeaderList == __sbh_sizeHeaderList)
{
if (!(pHeader = (PHEADER)HeapReAlloc(_crtheap, 0, __sbh_pHeaderList,
(__sbh_sizeHeaderList + 16) * sizeof(HEADER))))
return NULL;
// update pointer and counter values
__sbh_pHeaderList = pHeader;
__sbh_sizeHeaderList += 16;
}
// point to new header in list
pHeader = __sbh_pHeaderList + __sbh_cntHeaderList;
// allocate a new region associated with the new header
if (!(pHeader->pRegion = (PREGION)HeapAlloc(_crtheap, HEAP_ZERO_MEMORY,
sizeof(REGION))))
return NULL;
// reserve address space for heap data in the region
if ((pHeader->pHeapData = VirtualAlloc(0, BYTES_PER_REGION,
MEM_RESERVE, PAGE_READWRITE)) == NULL)
{
HeapFree(_crtheap, 0, pHeader->pRegion);
return NULL;
}
// initialize alloc and commit group vectors
pHeader->bitvEntryHi = 0;
pHeader->bitvEntryLo = 0;
pHeader->bitvCommit = BITV_COMMIT_INIT;
// complete entry by incrementing list count
__sbh_cntHeaderList++;
// initialize index of group to try first (none defined yet)
pHeader->pRegion->indGroupUse = -1;
return pHeader;
}
/***
*int __sbh_alloc_new_group(pHeader)
*
*Purpose:
* Initializes a GROUP structure within HEADER pointed by pHeader.
* Commits and initializes the memory in the memory reserved by the
* REGION.
*
*Entry:
* pHeader - pointer to HEADER from which the GROUP is defined.
*
*Exit:
* Returns an index to newly created GROUP, if successful.
* Returns -1, if failure.
*
*Exceptions:
*
*******************************************************************************/
int __cdecl __sbh_alloc_new_group (PHEADER pHeader)
{
PREGION pRegion = pHeader->pRegion;
PGROUP pGroup;
PENTRY pEntry;
PENTRY pHead;
PENTRYEND pEntryEnd;
BITVEC bitvCommit;
int indCommit;
int index;
void * pHeapPage;
void * pHeapStartPage;
void * pHeapEndPage;
// determine next group to use by first bit set in commit vector
bitvCommit = pHeader->bitvCommit;
indCommit = 0;
while ((int)bitvCommit >= 0)
{
bitvCommit <<= 1;
indCommit++;
}
// allocate and initialize a new group
pGroup = &pRegion->grpHeadList[indCommit];
for (index = 0; index < 63; index++)
{
pEntry = (PENTRY)((char *)&pGroup->listHead[index] - sizeof(int));
pEntry->pEntryNext = pEntry->pEntryPrev = pEntry;
}
// commit heap memory for new group
pHeapStartPage = (void *)((char *)pHeader->pHeapData +
indCommit * BYTES_PER_GROUP);
if ((VirtualAlloc(pHeapStartPage, BYTES_PER_GROUP, MEM_COMMIT,
PAGE_READWRITE)) == NULL)
return -1;
// initialize heap data with empty page entries
pHeapEndPage = (void *)((char *)pHeapStartPage +
(PAGES_PER_GROUP - 1) * BYTES_PER_PAGE);
for (pHeapPage = pHeapStartPage; pHeapPage <= pHeapEndPage;
pHeapPage = (void *)((char *)pHeapPage + BYTES_PER_PAGE))
{
// set sentinel values at start and end of the page
*(int *)((char *)pHeapPage + 8) = -1;
*(int *)((char *)pHeapPage + BYTES_PER_PAGE - 4) = -1;
// set size and pointer info for one empty entry
pEntry = (PENTRY)((char *)pHeapPage + ENTRY_OFFSET);
pEntry->sizeFront = MAX_FREE_ENTRY_SIZE;
pEntry->pEntryNext = (PENTRY)((char *)pEntry +
BYTES_PER_PAGE);
pEntry->pEntryPrev = (PENTRY)((char *)pEntry -
BYTES_PER_PAGE);
pEntryEnd = (PENTRYEND)((char *)pEntry + MAX_FREE_ENTRY_SIZE -
sizeof(ENTRYEND));
pEntryEnd->sizeBack = MAX_FREE_ENTRY_SIZE;
}
// initialize group entry pointer for maximum size
// and set terminate list entries
pHead = (PENTRY)((char *)&pGroup->listHead[63] - sizeof(int));
pEntry = pHead->pEntryNext =
(PENTRY)((char *)pHeapStartPage + ENTRY_OFFSET);
pEntry->pEntryPrev = pHead;
pEntry = pHead->pEntryPrev =
(PENTRY)((char *)pHeapEndPage + ENTRY_OFFSET);
pEntry->pEntryNext = pHead;
pRegion->bitvGroupHi[indCommit] = 0x00000000L;
pRegion->bitvGroupLo[indCommit] = 0x00000001L;
if (pRegion->cntRegionSize[63]++ == 0)
pHeader->bitvEntryLo |= 0x00000001L;
// clear bit in commit vector
pHeader->bitvCommit &= ~(0x80000000L >> indCommit);
return indCommit;
}
/***
*int __sbh_resize_block(pHeader, pvAlloc, intNew) - resize block
*
*Purpose:
* Resize the specified block from the small-block heap.
* The allocation block is not moved.
*
*Entry:
* pHeader - pointer to HEADER containing block
* pvAlloc - pointer to block to resize
* intNew - new size of block in bytes
*
*Exit:
* Returns 1, if successful. Otherwise, 0 is returned.
*
*Exceptions:
*
*******************************************************************************/
int __cdecl __sbh_resize_block (PHEADER pHeader, void * pvAlloc, int intNew)
{
PREGION pRegion;
PGROUP pGroup;
PENTRY pHead;
PENTRY pEntry;
PENTRY pNext;
int sizeEntry;
int sizeNext;
int sizeNew;
unsigned int indGroup;
unsigned int indEntry;
unsigned int indNext;
unsigned int offRegion;
// add 8 bytes entry overhead and round up to next para size
sizeNew = (intNew + 2 * sizeof(int) + (BYTES_PER_PARA - 1))
& ~(BYTES_PER_PARA - 1);
// region is determined by the header
pRegion = pHeader->pRegion;
// use the region offset to determine the group index
offRegion = (unsigned int)pvAlloc - (unsigned int)pHeader->pHeapData;
indGroup = offRegion / BYTES_PER_GROUP;
pGroup = &pRegion->grpHeadList[indGroup];
// get size of entry - decrement value since entry is allocated
pEntry = (PENTRY)((char *)pvAlloc - sizeof(int));
sizeEntry = pEntry->sizeFront - 1;
// point to next entry to get its size
pNext = (PENTRY)((char *)pEntry + sizeEntry);
sizeNext = pNext->sizeFront;
// test if new size is larger than the current one
if (sizeNew > sizeEntry)
{
// if next entry not free, or not large enough, fail
if ((sizeNext & 1) || (sizeNew > sizeEntry + sizeNext))
return FALSE;
// disconnect next entry
// determine index of next entry
indNext = (sizeNext >> 4) - 1;
if (indNext > 63)
indNext = 63;
// test entry is sole member of bucket (next == prev),
if (pNext->pEntryNext == pNext->pEntryPrev)
{
// clear bit in group vector, decrement region count
// if region count is now zero, clear bit in header
// entry vector
if (indNext < 32)
{
pRegion->bitvGroupHi[indGroup] &= ~(0x80000000L >> indNext);
if (--pRegion->cntRegionSize[indNext] == 0)
pHeader->bitvEntryHi &= ~(0x80000000L >> indNext);
}
else
{
pRegion->bitvGroupLo[indGroup] &=
~(0x80000000L >> (indNext - 32));
if (--pRegion->cntRegionSize[indNext] == 0)
pHeader->bitvEntryLo &= ~(0x80000000L >> (indNext - 32));
}
}
// unlink entry from list
pNext->pEntryPrev->pEntryNext = pNext->pEntryNext;
pNext->pEntryNext->pEntryPrev = pNext->pEntryPrev;
// compute new size of the next entry, test if nonzero
if ((sizeNext = sizeEntry + sizeNext - sizeNew) > 0)
{
// compute start of next entry and connect it
pNext = (PENTRY)((char *)pEntry + sizeNew);
// determine index of next entry
indNext = (sizeNext >> 4) - 1;
if (indNext > 63)
indNext = 63;
// add next entry to the start of the bucket list
pHead = (PENTRY)((char *)&pGroup->listHead[indNext] -
sizeof(int));
pNext->pEntryNext = pHead->pEntryNext;
pNext->pEntryPrev = pHead;
pHead->pEntryNext = pNext;
pNext->pEntryNext->pEntryPrev = pNext;
// test entry is sole member of bucket (next == prev),
if (pNext->pEntryNext == pNext->pEntryPrev)
{
// if region count was zero, set bit in region vector
// set bit in header entry vector, increment region count
if (indNext < 32)
{
if (pRegion->cntRegionSize[indNext]++ == 0)
pHeader->bitvEntryHi |= 0x80000000L >> indNext;
pRegion->bitvGroupHi[indGroup] |= 0x80000000L >> indNext;
}
else
{
if (pRegion->cntRegionSize[indNext]++ == 0)
pHeader->bitvEntryLo |= 0x80000000L >> (indNext - 32);
pRegion->bitvGroupLo[indGroup] |=
0x80000000L >> (indNext - 32);
}
}
// adjust size fields of next entry
pNext->sizeFront = sizeNext;
((PENTRYEND)((char *)pNext + sizeNext -
sizeof(ENTRYEND)))->sizeBack = sizeNext;
}
// adjust pEntry to its new size (plus one since allocated)
pEntry->sizeFront = sizeNew + 1;
((PENTRYEND)((char *)pEntry + sizeNew -
sizeof(ENTRYEND)))->sizeBack = sizeNew + 1;
}
// not larger, test if smaller
else if (sizeNew < sizeEntry)
{
// adjust pEntry to new smaller size
pEntry->sizeFront = sizeNew + 1;
((PENTRYEND)((char *)pEntry + sizeNew -
sizeof(ENTRYEND)))->sizeBack = sizeNew + 1;
// set pEntry and sizeEntry to leftover space
pEntry = (PENTRY)((char *)pEntry + sizeNew);
sizeEntry -= sizeNew;
// determine index of entry
indEntry = (sizeEntry >> 4) - 1;
if (indEntry > 63)
indEntry = 63;
// test if next entry is free
if ((sizeNext & 1) == 0)
{
// if so, disconnect it
// determine index of next entry
indNext = (sizeNext >> 4) - 1;
if (indNext > 63)
indNext = 63;
// test entry is sole member of bucket (next == prev),
if (pNext->pEntryNext == pNext->pEntryPrev)
{
// clear bit in group vector, decrement region count
// if region count is now zero, clear bit in header
// entry vector
if (indNext < 32)
{
pRegion->bitvGroupHi[indGroup] &=
~(0x80000000L >> indNext);
if (--pRegion->cntRegionSize[indNext] == 0)
pHeader->bitvEntryHi &= ~(0x80000000L >> indNext);
}
else
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -