⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 heap.c

📁 不错的东西 请查看 WINCE OS
💻 C
📖 第 1 页 / 共 5 页
字号:
        DEBUGMSG(DBGHEAP2, (L"CarveItem: Leftover %8.8lx(%lx)\r\n", pitNext, pitNext->size));
        pitNext->prgn = prgn;
#if HEAP_SENTINELS
        SetFreeSentinels(pitNext);
#endif
    }

    // update the size of the new item
    if (pitcombine) {
        DEBUGCHK ((pitcombine->size > 0) && ((DWORD) pitcombine + pitcombine->size == (DWORD) pit));
        (pit = pitcombine)->size += cbSeek;

    } else {
        pit->size = cbSeek;
    }

    // update the region's free pointer
    if (pitNext->size <= 0) {
        if (prgn->pitFree > pitNext)
            prgn->pitFree = pitNext;

        // update pitLast if we hit the end
        if (!((pitem) ((char *) pitNext - pitNext->size))->size) {
            prgn->pitLast = pitNext;
        }
    }

#if HEAP_SENTINELS
    SetSentinels(pit, dwBytes);
#else
    // zero the excess memory we allocated to it
    cbEx = pit->size - sizeof(item) - dwBytes;

    //
    // DEBUGCHK ((cbEx >= 0) && (cbEx < 16));
    if (cbEx > 0) {
        memset ((char *)(pit+1) + dwBytes, 0, cbEx);
    }
#endif
    DEBUGMSG(DBGHEAP2, (L"CarveItem returns: pit = %8.8lx pit->size = %8.8lx\r\n", pit, pit->size));
    return pit;
}


//
// Large allocation using VirtualAlloc
//
static pitem DoLargeHeapAlloc (LPVOID lpSlot, pheap php, DWORD dwBytes)
{
    pitem pitRet;
    pvaitem pva;
    DWORD dwReserve, cbSeek, dwData = 0;

    // Attempt to allocate the memory block before taking the heap critical section
    // to improve multi-threaded behavior.
    cbSeek = (dwBytes + ALIGNSIZE(sizeof(vaitem)) + PAGE_SIZE-1) & ~(PAGE_SIZE-1);
    dwReserve = (cbSeek + HEAP_SENTINELS + 0xFFFFL) & 0xFFFF0000L;
    if (!(pva = php->pfnAlloc (lpSlot, dwReserve, MEM_RESERVE, &dwData))
            || !php->pfnAlloc (pva, cbSeek, MEM_COMMIT, &dwData)) {
        if (pva)
            php->pfnFree (pva, 0, MEM_RELEASE, dwData);

        return NULL;
    }

    // New VA'ed item created.  Initialize the item structure within the vaitem.
    pva = (pvaitem)((char*)pva + (ALIGNSIZE(sizeof(vaitem)) - sizeof(vaitem)));
    pva->dwData = dwData;
    pitRet = &pva->it;
    pitRet->php = php;
    pitRet->size = (cbSeek - ALIGNSIZE(sizeof(vaitem)) + sizeof(item)) | 1;  // Tag item as VirtualAlloc'ed

#if HEAP_SENTINELS
    SetSentinels(pitRet, dwBytes);
#endif

    // Take the heap's CS and link it into the vaitem list.
    EnterCriticalSection(&php->cs);
    pva->pvaFwd = php->pvaList;
    if (php->pvaList)
        php->pvaList->pvaBak = pva;
    php->pvaList = pva;
    LeaveCriticalSection(&php->cs);

    return pitRet;
}

// find a free item of size >= cbSeek in a region (HOLDING HEAP CS).
static pitem FindFreeItemInRegion (LPVOID lpSlot, pregion prgn, int cbSeek)
{
    pitem pitStart = prgn->pitFree;
    pitem pit, pitRet, pitEnd;
    int   cbItem;
    int   nEndReached = 0;
    int   cbMax = 0;

    if (!pitStart->size)
        pitStart = FIRSTITEM (prgn);

    DEBUGMSG(DBGHEAP2, (L"1:FindFreeItemInRegion %8.8lx %8.8lx\r\n", prgn->pitFree, pitStart));
    pit = pitStart;
#ifndef FREE_POINTER_AT_LAST_FREE
    if (prgn->pitFree->size > 0)
        prgn->pitFree = prgn->pitLast;
#endif

    do {

        // find the next free item
        // NOTE: MUST SAVE THE SIZE IN LOCAL OR THERE'LL BE RACE CONDITION BECAUSE
        //       HeapReAlloc DOES NOT ACQUIRE CS while shrinking.
        while ((cbItem = pit->size) > 0) {
            pit = (pitem)((char*)pit + cbItem);
        }

        pit = MergeFreeItems (prgn, pitRet = pit);
        cbItem = -pitRet->size;

        // Is the block big enough?
        if (cbItem >= cbSeek) {

            DEBUGMSG(DBGHEAP2, (L"FindFreeItemInRegion returns pitRet = %8.8lx\r\n", pitRet));
            if (cbItem - cbSeek > cbMax)
                cbMax = cbItem - cbSeek;

            break;
        }

        if (cbMax < cbItem)
            cbMax = cbItem;

        if (nEndReached && (pit >= pitStart))
            break;

        // if we've reached the last block and the size is big enough, mark the end
        // but don't use it yet -- since it requires committing more memory
        if (!pit->size) {

            if (nEndReached ++) {
                // heap is corrupted -- faked end marker being inserted
                DEBUGMSG(DBGHEAP2, (L"!FindFreeItemInRegion: Heap is corrupted\r\n"));
                DEBUGCHK (0);
                return NULL;
            }
            pitEnd = pitRet;

            // continue search from the 1st item if not done the full pass
            pit = FIRSTITEM (prgn);
        }

    }while (!nEndReached || (pit < pitStart));

    if (cbItem < cbSeek) {

        // if we reach here, either we need to commit more memory or don't have enough room

        // if the last item examined is not the end, update it to the recorded end
        if (pit->size)
            pitRet = pitEnd;

        pitEnd = (pitem) ((char *)pitRet - pitRet->size);

        DEBUGCHK ((pitRet->size <= 0) && !pitEnd->size);

        // need an extra room for tail item. thus the check
        if (pitEnd->cbTail - pitRet->size < (int) (cbSeek + sizeof(item)))
            pitRet = NULL;

        prgn->cbMaxFree = 0;    // the number is no longer an estimate, wil be updated next
    }

    if (cbMax > prgn->cbMaxFree) {
        prgn->cbMaxFree = cbMax | (prgn->cbMaxFree & REGION_MAX_IS_ESTIMATE);
    }

    DEBUGMSG(DBGHEAP2, (L"FindFreeItemInRegion returns pitRet = %8.8lx\r\n", pitRet));
    return pitRet;
}


// find a free item of size >= cbSeek in a heap (HOLDING HEAP CS).
static pitem FindFreeItem (LPVOID lpSlot, pheap php, DWORD cbSeek, pregion *pprgn)
{
    pregion prgn = &php->rgn;
    pitem   pitRet = NULL;

    DEBUGMSG(DBGHEAP2, (L"FindFreeItem %8.8lx %8.8lx %8.8lx\r\n", lpSlot, php, cbSeek));

    // pass 1: look for regions with items large enough for us
    do {
        if (prgn->cbMaxFree >= (int) cbSeek) {
            if (pitRet = FindFreeItemInRegion (lpSlot, prgn, cbSeek)) {
                DEBUGCHK (pitRet->size <= 0);
                break;
            }
        }
    } while (prgn = prgn->prgnNext);

    // pass 2: look for all region that are estimates or need to commit memory
    if (!pitRet) {
        prgn = &php->rgn;
        do {
            // if the region has an exact upper bound, return the pitLast if there are
            // enough room at the end after committing pages
            if (!(prgn->cbMaxFree & REGION_MAX_IS_ESTIMATE)) {
                pitem pitLast = prgn->pitLast;
                pitem pitTail = (pitem) ((char *) pitLast - pitLast->size);
                if (pitTail->cbTail - pitLast->size > (int) cbSeek) {
                    pitRet = pitLast;
                    break;
                }
            } else if (pitRet = FindFreeItemInRegion (lpSlot, prgn, cbSeek)) {
                DEBUGCHK (pitRet->size <= 0);
                break;
            }
        } while (prgn = prgn->prgnNext);
    }
    *pprgn = prgn;
    DEBUGMSG(DBGHEAP2, (L"FindFreeItem returns %8.8lx, prgn = %8.8lx\r\n", pitRet, prgn));
    return pitRet;
}


/*
    @doc BOTH EXTERNAL

    @func LPVOID | HeapReAlloc | Realloc's a HeapAlloc'ed block of memory
    @parm HANDLE | hHeap     | Handle returned from CreateHeap()
    @parm DWORD  | dwFlags   | HEAP_NO_SERIALIZE, HEAP_REALLOC_IN_PLACE_ONLY and HEAP_ZERO_MEM supported
    @parm LPVOID | lpMem     | pointer to memory to realloc
    @parm DWORD  | dwBytes   | Desired size of block
*/
LPVOID WINAPI HeapReAlloc(HANDLE hHeap, DWORD dwFlags, LPVOID lpMem, DWORD dwBytes)
{
    return ptrHeapReAlloc (hHeap, dwFlags, lpMem, dwBytes);
}
LPVOID WINAPI Int_HeapReAlloc(HANDLE hHeap, DWORD dwFlags, LPVOID lpMem, DWORD dwBytes)
{
    LPVOID pRet = NULL;
    int cbItem;
    int cbOrigSize;
    int cbSeek;
    pitem pit;
    pheap php = (pheap)hHeap;
    pregion prgn;
    BOOL bZeroPtr = FALSE;      // set to TRUE if caller is using "zero based pointers"
#if HEAP_SENTINELS
    DWORD dwSize;
#endif

    if (((DWORD)hHeap>>SECTION_SHIFT) != ((DWORD)lpMem>>SECTION_SHIFT)) {
        // The ptr has been unmapped by someone or it doesn't belong to this heap.
        if ((DWORD)lpMem>>SECTION_SHIFT) {
            DEBUGMSG(DBGFIXHP, (L"   1:HeapReAlloc %8.8lx %8.8lx %8.8lx %8.8lx ==> %8.8lx (invalid parameter)\r\n", hHeap,dwFlags,lpMem,dwBytes,0));
            SetLastError(ERROR_INVALID_PARAMETER);
            return NULL;
        }
        // Restore the "slot mapping" bits to the pointer.
        lpMem = (LPVOID)((DWORD)lpMem | ((DWORD)hHeap & -(1<<SECTION_SHIFT)));
        bZeroPtr = TRUE;
    }
    pit = (pitem)((char*)lpMem - sizeof(item));
    if (dwFlags & ~(HEAP_GENERATE_EXCEPTIONS | HEAP_NO_SERIALIZE | HEAP_REALLOC_IN_PLACE_ONLY | HEAP_ZERO_MEMORY)) {
        DEBUGMSG(DBGFIXHP, (L"   2:HeapReAlloc %8.8lx %8.8lx %8.8lx %8.8lx ==> %8.8lx (invalid parameter)\r\n", hHeap,dwFlags,lpMem,dwBytes,0));
        SetLastError(ERROR_INVALID_PARAMETER);
        return NULL;
    }
    if (dwFlags & HEAP_GENERATE_EXCEPTIONS) {
        DEBUGMSG(DBGFIXHP, (L"   3:HeapReAlloc %8.8lx %8.8lx %8.8lx %8.8lx ==> %8.8lx (not supported)\r\n", hHeap,dwFlags,lpMem,dwBytes,0));
        SetLastError(ERROR_NOT_SUPPORTED);
        return NULL;
    }
    if (!hHeap || php->dwSig != HEAPSIG || (DWORD)ZeroPtr(lpMem) < 0x10000 || pit->size <= 0) {
        DEBUGMSG(DBGFIXHP, (L"   4:HeapReAlloc %8.8lx %8.8lx %8.8lx %8.8lx %8.8lx (invalid parameter)\r\n", hHeap,dwFlags,lpMem,dwBytes,pit->size));
        SetLastError(ERROR_INVALID_PARAMETER);
        return NULL;
    }
    if (dwBytes > HEAP_MAX_ALLOC) {
        DEBUGMSG(DBGFIXHP, (L"   5:HeapReAlloc %8.8lx %8.8lx %8.8lx %8.8lx ==> %8.8lx\r\n", hHeap,dwFlags,lpMem,dwBytes,0));
        SetLastError(ERROR_NOT_ENOUGH_MEMORY);
        return NULL;
    }

    cbItem = pit->size;
#if HEAP_SENTINELS
    cbOrigSize = pit->cbTrueSize;
#else
    cbOrigSize = cbItem & ~1;
#endif

    if (cbItem & 1) {
        // VirtualAlloc'ed item.  Validate that the item pointer falls correctly within a
        // 64K aligned virtual memory block and that the heap owner information in the
        // item is correct.
        pvaitem pva;
        int cbAllocated;

        --cbItem;       // Fix the item size
        pva = (pvaitem)(((DWORD)lpMem&0xFFFF0000) + (ALIGNSIZE(sizeof(vaitem)) - sizeof(vaitem)));
        cbAllocated = cbItem + (ALIGNSIZE(sizeof(vaitem)) - sizeof(item));
        if (pit != &pva->it || pit->php != php || (cbAllocated & PageMask) != 0) {
            DEBUGMSG(DBGFIXHP, (L"   6:HeapReAlloc %8.8lx %8.8lx %8.8lx %8.8lx ==> %8.8lx (invalid parameter)\r\n", hHeap,dwFlags,lpMem,dwBytes,0));
            SetLastError(ERROR_INVALID_PARAMETER);
            return NULL;
        }
#if HEAP_SENTINELS
        CheckSentinels(pit, TRUE);
#endif
        cbSeek = (dwBytes + ALIGNSIZE(sizeof(vaitem)) + PAGE_SIZE-1) & ~(PAGE_SIZE-1);
        if (cbSeek <= cbAllocated) {
            // Just use the existing block and treat this as a NOP.
#if HEAP_SENTINELS
            // If the size is changing, we must update the sentinels and
            // possibly zero out a few bytes.
            if ((dwSize = pit->cbTrueSize) != dwBytes) {
                SetSentinels(pit, dwBytes);
                if (dwSize < dwBytes && (dwFlags & HEAP_ZERO_MEMORY))
                    memset((char*)(pit+1)+dwSize, 0, dwBytes-dwSize);
            }
#endif
            pRet = pit+1;
        }
        
    } else {
        // Normal heap allocation.  Verify the region parameters.
        prgn = pit->prgn;
        if (prgn == NULL || php != prgn->phpOwner || (cbItem & (ALIGNBYTES-1)) != 0) {
            DEBUGMSG(DBGFIXHP, (L"   7:HeapReAlloc %8.8lx %8.8lx %8.8lx %8.8lx ==> %8.8lx (invalid parameter)\r\n", hHeap,dwFlags,lpMem,dwBytes,0));
            SetLastError(ERROR_INVALID_PARAMETER);
            return NULL;
        }
#if HEAP_SENTINELS
        CheckSentinels(pit, TRUE);
#endif
        cbSeek = ALIGNSIZE(dwBytes + sizeof(item) + HEAP_SENTINELS);

        if (cbSeek > cbItem) {
            // Need to grow the block. Check to see if there is a free block following
            // this one that is large enough to satisfy the request.
            pitem pitTrav, pitNext = (pitem)((char*)pit + cbItem);
            int   cbNext;

            // grab the CS
            EnterCriticalSection(&php->cs);

            if (pitNext->size > 0) {
                // release CS
                LeaveCriticalSection(&php->cs);

            } else {

                pitTrav = MergeFreeItems (prgn, pitNext);
                cbNext = -pitNext->size;

                DEBUGMSG(DBGFIXHP, (L"   8:HeapReAlloc %8.8lx %8.8lx %8.8lx %8.8lx\n", cbSeek, cbItem, cbNext, pitTrav->size));
                // do we have room to do in-place realloc?
                if ((cbItem + cbNext >= cbSeek)                 // have room by merging with free blocks?
                    || (!pitTrav->size                          // reach the end marker and have enough room?
                        && (cbItem + cbNext + pitTrav->cbTail > cbSeek))) {
                    if (pit = CarveItem (prgn, pitNext, cbSeek - cbItem, dwBytes, pit)) {
                        pRet = pit + 1;   // return value is right after the item

                        if (prgn->pitFree > pit) {
                            prgn->pitFree = (pitem) ((char *)pit + pit->size);
                        }
                    }

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -