Beispiel #1
0
static void test2(RTTEST hTest)
{
    struct TestMap2 *p2 = (struct TestMap2 *)RTTestGuardedAllocTail(hTest, sizeof(TestMap2));
    p2->idNil  = NIL_TEST2_ID;
    p2->idLast = TEST2_ID_LAST;

    /* Some simple tests first. */
    RT_ZERO(p2->bmChunkId);
    RTTEST_CHECK(hTest, ASMBitFirstSet(&p2->bmChunkId[0], TEST2_ID_LAST + 1) == -1);
    for (uint32_t iBit = 0; iBit <= TEST2_ID_LAST; iBit++)
        RTTEST_CHECK(hTest, !ASMBitTest(&p2->bmChunkId[0], iBit));

    memset(&p2->bmChunkId[0], 0xff, sizeof(p2->bmChunkId));
    RTTEST_CHECK(hTest, ASMBitFirstClear(&p2->bmChunkId[0], TEST2_ID_LAST + 1) == -1);
    for (uint32_t iBit = 0; iBit <= TEST2_ID_LAST; iBit++)
        RTTEST_CHECK(hTest, ASMBitTest(&p2->bmChunkId[0], iBit));

    /* The real test. */
    p2->idChunkPrev = 0;
    RT_ZERO(p2->bmChunkId);
    ASMBitSet(p2->bmChunkId, NIL_TEST2_ID);
    uint32_t cLeft = TEST2_ID_LAST;
    while (cLeft-- > 0)
        test2AllocId(p2);

    RTTEST_CHECK(hTest, ASMBitFirstClear(&p2->bmChunkId[0], TEST2_ID_LAST + 1) == -1);
}
Beispiel #2
0
static PCR_DISPLAY crServerDisplayGet(uint32_t idScreen)
{
    if (idScreen >= CR_MAX_GUEST_MONITORS)
    {
        crWarning("invalid idScreen %d", idScreen);
        return NULL;
    }

    if (ASMBitTest(cr_server.DisplaysInitMap, idScreen))
        return &cr_server.aDispplays[idScreen];

    /* the display (screen id == 0) can be initialized while doing crServerCheckInitDisplayBlitter,
     * so re-check the bit map */
     if (ASMBitTest(cr_server.DisplaysInitMap, idScreen))
         return &cr_server.aDispplays[idScreen];

     int rc = CrDpInit(&cr_server.aDispplays[idScreen]);
     if (RT_SUCCESS(rc))
     {
         CrDpResize(&cr_server.aDispplays[idScreen],
                 cr_server.screen[idScreen].w, cr_server.screen[idScreen].h,
                 cr_server.screen[idScreen].w, cr_server.screen[idScreen].h);
         ASMBitSet(cr_server.DisplaysInitMap, idScreen);
         return &cr_server.aDispplays[idScreen];
     }
     else
     {
         crWarning("CrDpInit failed for screen %d", idScreen);
     }

    return NULL;
}
Beispiel #3
0
/**
 * Checks if a page range is free in the specified block.
 *
 * @returns @c true if the range is free, @c false if not.
 * @param   pBlock          The block.
 * @param   iFirst          The first page to check.
 * @param   cPages          The number of pages to check.
 */
DECLINLINE(bool) rtHeapPageIsPageRangeFree(PRTHEAPPAGEBLOCK pBlock, uint32_t iFirst, uint32_t cPages)
{
    uint32_t i = iFirst + cPages;
    while (i-- > iFirst)
    {
        if (ASMBitTest(&pBlock->bmAlloc[0], i))
            return false;
        Assert(!ASMBitTest(&pBlock->bmFirst[0], i));
    }
    return true;
}
Beispiel #4
0
/**
 * Flush pending queues.
 * This is a forced action callback.
 *
 * @param   pVM     Pointer to the VM.
 * @thread  Emulation thread only.
 */
VMMR3_INT_DECL(void) PDMR3QueueFlushAll(PVM pVM)
{
    VM_ASSERT_EMT(pVM);
    LogFlow(("PDMR3QueuesFlush:\n"));

    /*
     * Only let one EMT flushing queues at any one time to preserve the order
     * and to avoid wasting time. The FF is always cleared here, because it's
     * only used to get someones attention. Queue inserts occurring during the
     * flush are caught using the pending bit.
     *
     * Note! We must check the force action and pending flags after clearing
     *       the active bit!
     */
    VM_FF_CLEAR(pVM, VM_FF_PDM_QUEUES);
    while (!ASMAtomicBitTestAndSet(&pVM->pdm.s.fQueueFlushing, PDM_QUEUE_FLUSH_FLAG_ACTIVE_BIT))
    {
        ASMAtomicBitClear(&pVM->pdm.s.fQueueFlushing, PDM_QUEUE_FLUSH_FLAG_PENDING_BIT);

        for (PPDMQUEUE pCur = pVM->pUVM->pdm.s.pQueuesForced; pCur; pCur = pCur->pNext)
            if (    pCur->pPendingR3
                    ||  pCur->pPendingR0
                    ||  pCur->pPendingRC)
                pdmR3QueueFlush(pCur);

        ASMAtomicBitClear(&pVM->pdm.s.fQueueFlushing, PDM_QUEUE_FLUSH_FLAG_ACTIVE_BIT);

        /* We're done if there were no inserts while we were busy. */
        if (   !ASMBitTest(&pVM->pdm.s.fQueueFlushing, PDM_QUEUE_FLUSH_FLAG_PENDING_BIT)
                && !VM_FF_ISPENDING(pVM, VM_FF_PDM_QUEUES))
            break;
        VM_FF_CLEAR(pVM, VM_FF_PDM_QUEUES);
    }
}
Beispiel #5
0
RTDECL(bool) ASMBitTestAndClear(volatile void *pvBitmap, int32_t iBit)
{
    if (!ASMBitTest(pvBitmap, iBit))
        return false;
    ASMBitClear(pvBitmap, iBit);
    return true;
}
Beispiel #6
0
RTDECL(bool) ASMBitTestAndSet(volatile void *pvBitmap, int32_t iBit)
{
    if (ASMBitTest(pvBitmap, iBit))
        return true;
    ASMBitSet(pvBitmap, iBit);
    return false;
}
Beispiel #7
0
/**
 * Checks if the specified generic event is enabled or not.
 *
 * @returns true / false.
 * @param   pVM                 The cross context VM structure.
 * @param   enmEvent            The generic event being raised.
 * @param   uEventArg           The argument of that event.
 */
DECLINLINE(bool) dbgfEventIsGenericWithArgEnabled(PVM pVM, DBGFEVENTTYPE enmEvent, uint64_t uEventArg)
{
    if (DBGF_IS_EVENT_ENABLED(pVM, enmEvent))
    {
        switch (enmEvent)
        {
            case DBGFEVENT_INTERRUPT_HARDWARE:
                AssertReturn(uEventArg < 256, false);
                return ASMBitTest(pVM->dbgf.s.bmHardIntBreakpoints, (uint32_t)uEventArg);

            case DBGFEVENT_INTERRUPT_SOFTWARE:
                AssertReturn(uEventArg < 256, false);
                return ASMBitTest(pVM->dbgf.s.bmSoftIntBreakpoints, (uint32_t)uEventArg);

            default:
                return true;

        }
    }
    return false;
}
Beispiel #8
0
PVBOXWDDM_VIDEOMODES_INFO VBoxWddmUpdateVideoModesInfoByMask(PVBOXMP_DEVEXT pExt, uint8_t *pScreenIdMask)
{
    for (int i = 0; i < VBoxCommonFromDeviceExt(pExt)->cDisplays; ++i)
    {
        if (ASMBitTest(pScreenIdMask, i))
            VBoxWddmInvalidateVideoModesInfo(pExt, i);
    }

    /* ensure we have all the rest populated */
    VBoxWddmGetAllVideoModesInfos(pExt);
    return g_aVBoxVideoModeInfos;
}
Beispiel #9
0
/**
 * Destroys the per thread data.
 *
 * @param   pThread     The thread to destroy.
 */
static void rtThreadDestroy(PRTTHREADINT pThread)
{
    RTSEMEVENTMULTI hEvt1, hEvt2;
    /*
     * Remove it from the tree and mark it as dead.
     *
     * Threads that has seen rtThreadTerminate and should already have been
     * removed from the tree. There is probably no thread that  should
     * require removing here. However, be careful making sure that cRefs
     * isn't 0 if we do or we'll blow up because the strict locking code
     * will be calling us back.
     */
    if (ASMBitTest(&pThread->fIntFlags, RTTHREADINT_FLAG_IN_TREE_BIT))
    {
        ASMAtomicIncU32(&pThread->cRefs);
        rtThreadRemove(pThread);
        ASMAtomicDecU32(&pThread->cRefs);
    }

    /*
     * Invalidate the thread structure.
     */
#ifdef IN_RING3
    rtLockValidatorSerializeDestructEnter();

    rtLockValidatorDeletePerThread(&pThread->LockValidator);
#endif
#ifdef RT_WITH_ICONV_CACHE
    rtStrIconvCacheDestroy(pThread);
#endif
    ASMAtomicXchgU32(&pThread->u32Magic, RTTHREADINT_MAGIC_DEAD);
    ASMAtomicWritePtr(&pThread->Core.Key, (void *)NIL_RTTHREAD);
    pThread->enmType         = RTTHREADTYPE_INVALID;
    hEvt1    = pThread->EventUser;
    pThread->EventUser       = NIL_RTSEMEVENTMULTI;
    hEvt2    = pThread->EventTerminated;
    pThread->EventTerminated = NIL_RTSEMEVENTMULTI;

#ifdef IN_RING3
    rtLockValidatorSerializeDestructLeave();
#endif

    /*
     * Destroy semaphore resources and free the bugger.
     */
    RTSemEventMultiDestroy(hEvt1);
    if (hEvt2 != NIL_RTSEMEVENTMULTI)
        RTSemEventMultiDestroy(hEvt2);

    rtThreadNativeDestroy(pThread);
    RTMemFree(pThread);
}
Beispiel #10
0
RTR3DECL(int) RTTlsSet(RTTLS iTls, void *pvValue)
{
    if (RT_UNLIKELY(    iTls < 0
                    ||  iTls >= RTTHREAD_TLS_ENTRIES
                    ||  !ASMBitTest(&g_au32AllocatedBitmap[0], iTls)))
        return VERR_INVALID_PARAMETER;

    PRTTHREADINT pThread = rtThreadGet(RTThreadSelf());
    AssertReturn(pThread, VERR_NOT_SUPPORTED);
    pThread->apvTlsEntries[iTls] = pvValue;
    rtThreadRelease(pThread);
    return VINF_SUCCESS;
}
Beispiel #11
0
RTR3DECL(int) RTTlsFree(RTTLS iTls)
{
    if (iTls == NIL_RTTLS)
        return VINF_SUCCESS;
    if (    iTls < 0
        ||  iTls >= RTTHREAD_TLS_ENTRIES
        ||  !ASMBitTest(&g_au32AllocatedBitmap[0], iTls))
        return VERR_INVALID_PARAMETER;

    ASMAtomicWriteNullPtr(&g_apfnDestructors[iTls]);
    rtThreadClearTlsEntry(iTls);
    ASMAtomicBitClear(&g_au32AllocatedBitmap[0], iTls);
    return VINF_SUCCESS;
}
Beispiel #12
0
/**
 * Check if this page was previously scanned by CSAM
 *
 * @returns true -> scanned, false -> not scanned
 * @param   pVM         Pointer to the VM.
 * @param   pPage       GC page address
 */
VMM_INT_DECL(bool) CSAMIsPageScanned(PVM pVM, RTRCPTR pPage)
{
    int pgdir, bit;
    uintptr_t page;

    page  = (uintptr_t)pPage;
    pgdir = page >> X86_PAGE_4M_SHIFT;
    bit   = (page & X86_PAGE_4M_OFFSET_MASK) >> X86_PAGE_4K_SHIFT;

    Assert(pgdir < CSAM_PGDIRBMP_CHUNKS);
    Assert(bit < PAGE_SIZE);

    return pVM->csam.s.CTXSUFF(pPDBitmap)[pgdir] && ASMBitTest((void *)pVM->csam.s.CTXSUFF(pPDBitmap)[pgdir], bit);
}
/**
 * \#PF Virtual Handler callback for Guest write access to the Guest's own current IDT.
 *
 * @returns VBox status code (appropriate for trap handling and GC return).
 * @param   pVM         Pointer to the VM.
 * @param   uErrorCode   CPU Error code.
 * @param   pRegFrame   Trap register frame.
 * @param   pvFault     The fault address (cr2).
 * @param   pvRange     The base address of the handled virtual range.
 * @param   offRange    The offset of the access into this range.
 *                      (If it's a EIP range this is the EIP, if not it's pvFault.)
 */
VMMRCDECL(int) trpmRCGuestIDTWriteHandler(PVM pVM, RTGCUINT uErrorCode, PCPUMCTXCORE pRegFrame, RTGCPTR pvFault, RTGCPTR pvRange, uintptr_t offRange)
{
    PVMCPU      pVCpu = VMMGetCpu0(pVM);
    uint16_t    cbIDT;
    RTGCPTR     GCPtrIDT    = (RTGCPTR)CPUMGetGuestIDTR(pVCpu, &cbIDT);
#ifdef VBOX_STRICT
    RTGCPTR     GCPtrIDTEnd = (RTGCPTR)((RTGCUINTPTR)GCPtrIDT + cbIDT + 1);
#endif
    uint32_t    iGate       = ((RTGCUINTPTR)pvFault - (RTGCUINTPTR)GCPtrIDT)/sizeof(VBOXIDTE);

    AssertMsg(offRange < (uint32_t)cbIDT+1, ("pvFault=%RGv GCPtrIDT=%RGv-%RGv pvRange=%RGv\n", pvFault, GCPtrIDT, GCPtrIDTEnd, pvRange));
    Assert((RTGCPTR)(RTRCUINTPTR)pvRange == GCPtrIDT);
    NOREF(uErrorCode);

#if 0
    /* Note! this causes problems in Windows XP as instructions following the update can be dangerous (str eax has been seen) */
    /* Note! not going back to ring 3 could make the code scanner miss them. */
    /* Check if we can handle the write here. */
    if (     iGate != 3                                         /* Gate 3 is handled differently; could do it here as well, but let ring 3 handle this case for now. */
        &&  !ASMBitTest(&pVM->trpm.s.au32IdtPatched[0], iGate)) /* Passthru gates need special attention too. */
    {
        uint32_t cb;
        int rc = EMInterpretInstructionEx(pVM, pVCpu, pRegFrame, pvFault, &cb);
        if (RT_SUCCESS(rc) && cb)
        {
            uint32_t iGate1 = (offRange + cb - 1)/sizeof(VBOXIDTE);

            Log(("trpmRCGuestIDTWriteHandler: write to gate %x (%x) offset %x cb=%d\n", iGate, iGate1, offRange, cb));

            trpmClearGuestTrapHandler(pVM, iGate);
            if (iGate != iGate1)
                trpmClearGuestTrapHandler(pVM, iGate1);

            STAM_COUNTER_INC(&pVM->trpm.s.StatRCWriteGuestIDTHandled);
            return VINF_SUCCESS;
        }
    }
#else
    NOREF(iGate);
#endif

    Log(("trpmRCGuestIDTWriteHandler: eip=%RGv write to gate %x offset %x\n", pRegFrame->eip, iGate, offRange));

    /** @todo Check which IDT entry and keep the update cost low in TRPMR3SyncIDT() and CSAMCheckGates(). */
    VMCPU_FF_SET(pVCpu, VMCPU_FF_TRPM_SYNC_IDT);

    STAM_COUNTER_INC(&pVM->trpm.s.StatRCWriteGuestIDTFault);
    return VINF_EM_RAW_EMULATE_INSTR_IDT_FAULT;
}
/**
 * Checks if the argument needs quoting or not.
 *
 * @returns true if it needs, false if it don't.
 * @param   pszArg              The argument.
 * @param   fFlags              Quoting style.
 * @param   pcch                Where to store the argument length when quoting
 *                              is not required.  (optimization)
 */
DECLINLINE(bool) rtGetOpArgvRequiresQuoting(const char *pszArg, uint32_t fFlags, size_t *pcch)
{
    char const *psz = pszArg;
    unsigned char ch;
    while ((ch = (unsigned char)*psz))
    {
        if (   ch < 128
                && ASMBitTest(&g_abmQuoteChars[fFlags & RTGETOPTARGV_CNV_QUOTE_MASK], ch))
            return true;
        psz++;
    }

    *pcch = psz - pszArg;
    return false;
}
Beispiel #15
0
/**
 * Frees a page from the page pool.
 *
 * @param   pPool   Pointer to the page pool.
 * @param   pv      Pointer to the page to free.
 *                  I.e. pointer returned by mmR3PagePoolAlloc().
 * @thread  The Emulation Thread.
 */
DECLINLINE(void) mmR3PagePoolFree(PMMPAGEPOOL pPool, void *pv)
{
    VM_ASSERT_EMT(pPool->pVM);
    STAM_COUNTER_INC(&pPool->cFreeCalls);

    /*
     * Lookup the virtual address.
     */
    PMMPPLOOKUPHCPTR pLookup = (PMMPPLOOKUPHCPTR)RTAvlPVGetBestFit(&pPool->pLookupVirt, pv, false);
    if (    !pLookup
        ||  (uint8_t *)pv >= (uint8_t *)pLookup->pSubPool->pvPages + (pLookup->pSubPool->cPages << PAGE_SHIFT)
        )
    {
        STAM_COUNTER_INC(&pPool->cErrors);
        AssertMsgFailed(("invalid pointer %p\n", pv));
        return;
    }

    /*
     * Free the page.
     */
    PMMPAGESUBPOOL  pSubPool = pLookup->pSubPool;
    /* clear bitmap bit */
    const unsigned  iPage = ((uint8_t *)pv - (uint8_t *)pSubPool->pvPages) >> PAGE_SHIFT;
#ifdef USE_INLINE_ASM_BIT_OPS
    Assert(ASMBitTest(pSubPool->auBitmap, iPage));
    ASMBitClear(pSubPool->auBitmap, iPage);
#else
    unsigned    iBit   = iPage % (sizeof(pSubPool->auBitmap[0]) * 8);
    unsigned    iIndex = iPage / (sizeof(pSubPool->auBitmap[0]) * 8);
    pSubPool->auBitmap[iIndex] &= ~(1 << iBit);
#endif
    /* update stats. */
    pSubPool->cPagesFree++;
#ifdef VBOX_WITH_STATISTICS
    pPool->cFreePages++;
#endif
    if (pSubPool->cPagesFree == 1)
    {
        pSubPool->pNextFree = pPool->pHeadFree;
        pPool->pHeadFree = pSubPool;
    }
}
Beispiel #16
0
int main()
{
    /*
     * Init the runtime and stuff.
     */
    RTTEST hTest;
    int rc = RTTestInitAndCreate("tstRTBitOperations", &hTest);
    if (rc)
        return rc;
    RTTestBanner(hTest);

    int i;
    int j;
    int k;

    /*
     * Tests
     */
    struct TestMap
    {
        uint32_t au32[4];
    };
#if 0
    struct TestMap sTest;
    struct TestMap *p = &sTest;
#else
    struct TestMap *p = (struct TestMap *)RTTestGuardedAllocTail(hTest, sizeof(*p));
#endif
#define DUMP()          RTTestPrintf(hTest, RTTESTLVL_INFO, "au32={%08x,%08x,%08x,%08x}", p->au32[0], p->au32[1], p->au32[2], p->au32[3])
#define CHECK(expr)     do { if (!(expr)) { RTTestFailed(hTest, "line %d: %s", __LINE__, #expr); DUMP(); } CHECK_GUARD(s); } while (0)
#define CHECK_BIT(expr,  b1)            do { if (!(expr)) { RTTestFailed(hTest, "line %d, b1=%d: %s", __LINE__, b1, #expr); } CHECK_GUARD(s); } while (0)
#define CHECK_BIT2(expr, b1, b2)        do { if (!(expr)) { RTTestFailed(hTest, "line %d, b1=%d b2=%d: %s", __LINE__, b1, b2, #expr); } CHECK_GUARD(s); } while (0)
#define CHECK_BIT3(expr, b1, b2, b3)    do { if (!(expr)) { RTTestFailed(hTest, "line %d, b1=%d b2=%d b3=%d: %s", __LINE__, b1, b2, b3, #expr); } CHECK_GUARD(s); } while (0)

#define GUARD_MAP(p)    do {  } while (0)
#define CHECK_GUARD(p)  do {  } while (0)
#define MAP_CLEAR(p)    do { RT_ZERO(*(p)); GUARD_MAP(p); } while (0)
#define MAP_SET(p)      do { memset(p, 0xff, sizeof(*(p))); GUARD_MAP(p); } while (0)

    /* self check. */
    MAP_CLEAR(p);
    CHECK_GUARD(p);

    /* bit set */
    MAP_CLEAR(p);
    ASMBitSet(&p->au32[0], 0);
    ASMBitSet(&p->au32[0], 31);
    ASMBitSet(&p->au32[0], 65);
    CHECK(p->au32[0] == 0x80000001U);
    CHECK(p->au32[2] == 0x00000002U);
    CHECK(ASMBitTestAndSet(&p->au32[0], 0)   && p->au32[0] == 0x80000001U);
    CHECK(!ASMBitTestAndSet(&p->au32[0], 16) && p->au32[0] == 0x80010001U);
    CHECK(ASMBitTestAndSet(&p->au32[0], 16)  && p->au32[0] == 0x80010001U);
    CHECK(!ASMBitTestAndSet(&p->au32[0], 80) && p->au32[2] == 0x00010002U);

    MAP_CLEAR(p);
    ASMAtomicBitSet(&p->au32[0], 0);
    ASMAtomicBitSet(&p->au32[0], 30);
    ASMAtomicBitSet(&p->au32[0], 64);
    CHECK(p->au32[0] == 0x40000001U);
    CHECK(p->au32[2] == 0x00000001U);
    CHECK(ASMAtomicBitTestAndSet(&p->au32[0], 0)   && p->au32[0] == 0x40000001U);
    CHECK(!ASMAtomicBitTestAndSet(&p->au32[0], 16) && p->au32[0] == 0x40010001U);
    CHECK(ASMAtomicBitTestAndSet(&p->au32[0], 16)  && p->au32[0] == 0x40010001U);
    CHECK(!ASMAtomicBitTestAndSet(&p->au32[0], 80) && p->au32[2] == 0x00010001U);

    /* bit clear */
    MAP_SET(p);
    ASMBitClear(&p->au32[0], 0);
    ASMBitClear(&p->au32[0], 31);
    ASMBitClear(&p->au32[0], 65);
    CHECK(p->au32[0] == ~0x80000001U);
    CHECK(p->au32[2] == ~0x00000002U);
    CHECK(!ASMBitTestAndClear(&p->au32[0], 0)   && p->au32[0] == ~0x80000001U);
    CHECK(ASMBitTestAndClear(&p->au32[0], 16)   && p->au32[0] == ~0x80010001U);
    CHECK(!ASMBitTestAndClear(&p->au32[0], 16)  && p->au32[0] == ~0x80010001U);
    CHECK(ASMBitTestAndClear(&p->au32[0], 80)   && p->au32[2] == ~0x00010002U);

    MAP_SET(p);
    ASMAtomicBitClear(&p->au32[0], 0);
    ASMAtomicBitClear(&p->au32[0], 30);
    ASMAtomicBitClear(&p->au32[0], 64);
    CHECK(p->au32[0] == ~0x40000001U);
    CHECK(p->au32[2] == ~0x00000001U);
    CHECK(!ASMAtomicBitTestAndClear(&p->au32[0], 0)   && p->au32[0] == ~0x40000001U);
    CHECK(ASMAtomicBitTestAndClear(&p->au32[0], 16)   && p->au32[0] == ~0x40010001U);
    CHECK(!ASMAtomicBitTestAndClear(&p->au32[0], 16)  && p->au32[0] == ~0x40010001U);
    CHECK(ASMAtomicBitTestAndClear(&p->au32[0], 80)   && p->au32[2] == ~0x00010001U);

    /* toggle */
    MAP_SET(p);
    ASMBitToggle(&p->au32[0], 0);
    ASMBitToggle(&p->au32[0], 31);
    ASMBitToggle(&p->au32[0], 65);
    ASMBitToggle(&p->au32[0], 47);
    ASMBitToggle(&p->au32[0], 47);
    CHECK(p->au32[0] == ~0x80000001U);
    CHECK(p->au32[2] == ~0x00000002U);
    CHECK(!ASMBitTestAndToggle(&p->au32[0], 0)   && p->au32[0] == ~0x80000000U);
    CHECK(ASMBitTestAndToggle(&p->au32[0], 0)    && p->au32[0] == ~0x80000001U);
    CHECK(ASMBitTestAndToggle(&p->au32[0], 16)   && p->au32[0] == ~0x80010001U);
    CHECK(!ASMBitTestAndToggle(&p->au32[0], 16)  && p->au32[0] == ~0x80000001U);
    CHECK(ASMBitTestAndToggle(&p->au32[0], 80)   && p->au32[2] == ~0x00010002U);

    MAP_SET(p);
    ASMAtomicBitToggle(&p->au32[0], 0);
    ASMAtomicBitToggle(&p->au32[0], 30);
    ASMAtomicBitToggle(&p->au32[0], 64);
    ASMAtomicBitToggle(&p->au32[0], 47);
    ASMAtomicBitToggle(&p->au32[0], 47);
    CHECK(p->au32[0] == ~0x40000001U);
    CHECK(p->au32[2] == ~0x00000001U);
    CHECK(!ASMAtomicBitTestAndToggle(&p->au32[0], 0)   && p->au32[0] == ~0x40000000U);
    CHECK(ASMAtomicBitTestAndToggle(&p->au32[0], 0)    && p->au32[0] == ~0x40000001U);
    CHECK(ASMAtomicBitTestAndToggle(&p->au32[0], 16)   && p->au32[0] == ~0x40010001U);
    CHECK(!ASMAtomicBitTestAndToggle(&p->au32[0], 16)  && p->au32[0] == ~0x40000001U);
    CHECK(ASMAtomicBitTestAndToggle(&p->au32[0], 80)   && p->au32[2] == ~0x00010001U);

    /* test bit. */
    for (i = 0; i < 128; i++)
    {
        MAP_SET(p);
        CHECK_BIT(ASMBitTest(&p->au32[0], i), i);
        ASMBitToggle(&p->au32[0], i);
        CHECK_BIT(!ASMBitTest(&p->au32[0], i), i);
        CHECK_BIT(!ASMBitTestAndToggle(&p->au32[0], i), i);
        CHECK_BIT(ASMBitTest(&p->au32[0], i), i);
        CHECK_BIT(ASMBitTestAndToggle(&p->au32[0], i), i);
        CHECK_BIT(!ASMBitTest(&p->au32[0], i), i);

        MAP_SET(p);
        CHECK_BIT(ASMBitTest(&p->au32[0], i), i);
        ASMAtomicBitToggle(&p->au32[0], i);
        CHECK_BIT(!ASMBitTest(&p->au32[0], i), i);
        CHECK_BIT(!ASMAtomicBitTestAndToggle(&p->au32[0], i), i);
        CHECK_BIT(ASMBitTest(&p->au32[0], i), i);
        CHECK_BIT(ASMAtomicBitTestAndToggle(&p->au32[0], i), i);
        CHECK_BIT(!ASMBitTest(&p->au32[0], i), i);
    }

    /* bit searching */
    MAP_SET(p);
    CHECK(ASMBitFirstClear(&p->au32[0], sizeof(p->au32) * 8) == -1);
    CHECK(ASMBitFirstSet(&p->au32[0], sizeof(p->au32) * 8) == 0);

    ASMBitClear(&p->au32[0], 1);
    CHECK(ASMBitFirstClear(&p->au32[0], sizeof(p->au32) * 8) == 1);
    CHECK(ASMBitFirstSet(&p->au32[0], sizeof(p->au32) * 8) == 0);

    MAP_SET(p);
    ASMBitClear(&p->au32[0], 95);
    CHECK(ASMBitFirstClear(&p->au32[0], sizeof(p->au32) * 8) == 95);
    CHECK(ASMBitFirstSet(&p->au32[0], sizeof(p->au32) * 8) == 0);

    MAP_SET(p);
    ASMBitClear(&p->au32[0], 127);
    CHECK(ASMBitFirstClear(&p->au32[0], sizeof(p->au32) * 8) == 127);
    CHECK(ASMBitFirstSet(&p->au32[0], sizeof(p->au32) * 8) == 0);
    CHECK(ASMBitNextSet(&p->au32[0], sizeof(p->au32) * 8, 0) == 1);
    CHECK(ASMBitNextSet(&p->au32[0], sizeof(p->au32) * 8, 1) == 2);
    CHECK(ASMBitNextSet(&p->au32[0], sizeof(p->au32) * 8, 2) == 3);


    MAP_SET(p);
    CHECK(ASMBitNextClear(&p->au32[0], sizeof(p->au32) * 8, 0) == -1);
    ASMBitClear(&p->au32[0], 32);
    CHECK(ASMBitNextClear(&p->au32[0], sizeof(p->au32) * 8, 32) == -1);
    ASMBitClear(&p->au32[0], 88);
    CHECK(ASMBitNextClear(&p->au32[0], sizeof(p->au32) * 8,  57) ==  88);

    MAP_SET(p);
    ASMBitClear(&p->au32[0], 31);
    ASMBitClear(&p->au32[0], 57);
    ASMBitClear(&p->au32[0], 88);
    ASMBitClear(&p->au32[0], 101);
    ASMBitClear(&p->au32[0], 126);
    ASMBitClear(&p->au32[0], 127);
    CHECK(ASMBitFirstClear(&p->au32[0], sizeof(p->au32) * 8) == 31);
    CHECK(ASMBitNextClear(&p->au32[0], sizeof(p->au32) * 8,  31) ==  57);
    CHECK(ASMBitNextClear(&p->au32[0], sizeof(p->au32) * 8,  57) ==  88);
    CHECK(ASMBitNextClear(&p->au32[0], sizeof(p->au32) * 8,  88) == 101);
    CHECK(ASMBitNextClear(&p->au32[0], sizeof(p->au32) * 8, 101) == 126);
    CHECK(ASMBitNextClear(&p->au32[0], sizeof(p->au32) * 8, 126) == 127);
    CHECK(ASMBitNextClear(&p->au32[0], sizeof(p->au32) * 8, 127) == -1);

    CHECK(ASMBitNextSet(&p->au32[0], sizeof(p->au32) * 8, 29) == 30);
    CHECK(ASMBitNextSet(&p->au32[0], sizeof(p->au32) * 8, 30) == 32);

    MAP_CLEAR(p);
    for (i = 1; i < 128; i++)
        CHECK_BIT(ASMBitNextClear(&p->au32[0], sizeof(p->au32) * 8, i - 1) == i, i);
    for (i = 0; i < 128; i++)
    {
        MAP_SET(p);
        ASMBitClear(&p->au32[0], i);
        CHECK_BIT(ASMBitFirstClear(&p->au32[0], sizeof(p->au32) * 8) == i, i);
        for (j = 0; j < i; j++)
            CHECK_BIT(ASMBitNextClear(&p->au32[0], sizeof(p->au32) * 8, j) == i, i);
        for (j = i; j < 128; j++)
            CHECK_BIT(ASMBitNextClear(&p->au32[0], sizeof(p->au32) * 8, j) == -1, i);
    }

    /* clear range. */
    MAP_SET(p);
    ASMBitClearRange(&p->au32, 0, 128);
    CHECK(!p->au32[0] && !p->au32[1] && !p->au32[2] && !p->au32[3]);
    for (i = 0; i < 128; i++)
    {
        for (j = i + 1; j <= 128; j++)
        {
            MAP_SET(p);
            ASMBitClearRange(&p->au32, i, j);
            for (k = 0; k < i; k++)
                CHECK_BIT3(ASMBitTest(&p->au32[0], k), i, j, k);
            for (k = i; k < j; k++)
                CHECK_BIT3(!ASMBitTest(&p->au32[0], k), i, j, k);
            for (k = j; k < 128; k++)
                CHECK_BIT3(ASMBitTest(&p->au32[0], k), i, j, k);
        }
    }

    /* set range. */
    MAP_CLEAR(p);
    ASMBitSetRange(&p->au32[0], 0, 5);
    ASMBitSetRange(&p->au32[0], 6, 44);
    ASMBitSetRange(&p->au32[0], 64, 65);
    CHECK(p->au32[0] == UINT32_C(0xFFFFFFDF));
    CHECK(p->au32[1] == UINT32_C(0x00000FFF));
    CHECK(p->au32[2] == UINT32_C(0x00000001));

    MAP_CLEAR(p);
    ASMBitSetRange(&p->au32[0], 0, 1);
    ASMBitSetRange(&p->au32[0], 62, 63);
    ASMBitSetRange(&p->au32[0], 63, 64);
    ASMBitSetRange(&p->au32[0], 127, 128);
    CHECK(p->au32[0] == UINT32_C(0x00000001) && p->au32[1] == UINT32_C(0xC0000000));
    CHECK(p->au32[2] == UINT32_C(0x00000000) && p->au32[3] == UINT32_C(0x80000000));

    MAP_CLEAR(p);
    ASMBitSetRange(&p->au32, 0, 128);
    CHECK(!~p->au32[0] && !~p->au32[1] && !~p->au32[2] && !~p->au32[3]);
    for (i = 0; i < 128; i++)
    {
        for (j = i + 1; j <= 128; j++)
        {
            MAP_CLEAR(p);
            ASMBitSetRange(&p->au32, i, j);
            for (k = 0; k < i; k++)
                CHECK_BIT3(!ASMBitTest(&p->au32[0], k), i, j, k);
            for (k = i; k < j; k++)
                CHECK_BIT3(ASMBitTest(&p->au32[0], k), i, j, k);
            for (k = j; k < 128; k++)
                CHECK_BIT3(!ASMBitTest(&p->au32[0], k), i, j, k);
        }
    }

    /* searching for set bits. */
    MAP_CLEAR(p);
    CHECK(ASMBitFirstSet(&p->au32[0], sizeof(p->au32) * 8) == -1);

    ASMBitSet(&p->au32[0], 65);
    CHECK(ASMBitFirstSet(&p->au32[0], sizeof(p->au32) * 8) == 65);
    CHECK(ASMBitNextSet(&p->au32[0], sizeof(p->au32) * 8, 65) == -1);
    for (i = 0; i < 65; i++)
        CHECK(ASMBitNextSet(&p->au32[0], sizeof(p->au32) * 8, i) == 65);
    for (i = 65; i < 128; i++)
        CHECK(ASMBitNextSet(&p->au32[0], sizeof(p->au32) * 8, i) == -1);

    ASMBitSet(&p->au32[0], 17);
    CHECK(ASMBitFirstSet(&p->au32[0], sizeof(p->au32) * 8) == 17);
    CHECK(ASMBitNextSet(&p->au32[0], sizeof(p->au32) * 8, 17) == 65);
    for (i = 0; i < 16; i++)
        CHECK(ASMBitNextSet(&p->au32[0], sizeof(p->au32) * 8, i) == 17);
    for (i = 17; i < 65; i++)
        CHECK(ASMBitNextSet(&p->au32[0], sizeof(p->au32) * 8, i) == 65);

    MAP_SET(p);
    for (i = 1; i < 128; i++)
        CHECK_BIT(ASMBitNextSet(&p->au32[0], sizeof(p->au32) * 8, i - 1) == i, i);
    for (i = 0; i < 128; i++)
    {
        MAP_CLEAR(p);
        ASMBitSet(&p->au32[0], i);
        CHECK_BIT(ASMBitFirstSet(&p->au32[0], sizeof(p->au32) * 8) == i, i);
        for (j = 0; j < i; j++)
            CHECK_BIT(ASMBitNextSet(&p->au32[0], sizeof(p->au32) * 8, j) == i, i);
        for (j = i; j < 128; j++)
            CHECK_BIT(ASMBitNextSet(&p->au32[0], sizeof(p->au32) * 8, j) == -1, i);
    }


    CHECK(ASMBitLastSetU32(0) == 0);
    CHECK(ASMBitLastSetU32(1) == 1);
    CHECK(ASMBitLastSetU32(0x80000000) == 32);
    CHECK(ASMBitLastSetU32(0xffffffff) == 32);
    CHECK(ASMBitLastSetU32(RT_BIT(23) | RT_BIT(11)) == 24);
    for (i = 0; i < 32; i++)
        CHECK(ASMBitLastSetU32(1 << i) == (unsigned)i + 1);

    CHECK(ASMBitFirstSetU32(0) == 0);
    CHECK(ASMBitFirstSetU32(1) == 1);
    CHECK(ASMBitFirstSetU32(0x80000000) == 32);
    CHECK(ASMBitFirstSetU32(0xffffffff) == 1);
    CHECK(ASMBitFirstSetU32(RT_BIT(23) | RT_BIT(11)) == 12);
    for (i = 0; i < 32; i++)
        CHECK(ASMBitFirstSetU32(1 << i) == (unsigned)i + 1);

    /*
     * Special tests.
     */
    test2(hTest);

    /*
     * Summary
     */
    return RTTestSummaryAndDestroy(hTest);
}
Beispiel #17
0
/**
 * Allocates a page from the page pool.
 *
 * @returns Pointer to allocated page(s).
 * @returns NULL on failure.
 * @param   pPool   Pointer to the page pool.
 * @thread  The Emulation Thread.
 */
DECLINLINE(void *) mmR3PagePoolAlloc(PMMPAGEPOOL pPool)
{
    VM_ASSERT_EMT(pPool->pVM);
    STAM_COUNTER_INC(&pPool->cAllocCalls);

    /*
     * Walk free list.
     */
    if (pPool->pHeadFree)
    {
        PMMPAGESUBPOOL  pSub = pPool->pHeadFree;
        /* decrement free count and unlink if no more free entries. */
        if (!--pSub->cPagesFree)
            pPool->pHeadFree = pSub->pNextFree;
#ifdef VBOX_WITH_STATISTICS
        pPool->cFreePages--;
#endif

        /* find free spot in bitmap. */
#ifdef USE_INLINE_ASM_BIT_OPS
        const int iPage = ASMBitFirstClear(pSub->auBitmap, pSub->cPages);
        if (iPage >= 0)
        {
            Assert(!ASMBitTest(pSub->auBitmap, iPage));
            ASMBitSet(pSub->auBitmap, iPage);
            return (uint8_t *)pSub->pvPages + PAGE_SIZE * iPage;
        }
#else
        unsigned   *pu = &pSub->auBitmap[0];
        unsigned   *puEnd = &pSub->auBitmap[pSub->cPages / (sizeof(pSub->auBitmap) * 8)];
        while (pu < puEnd)
        {
            unsigned u;
            if ((u = *pu) != ~0U)
            {
                unsigned iBit = 0;
                unsigned uMask = 1;
                while (iBit < sizeof(pSub->auBitmap[0]) * 8)
                {
                    if (!(u & uMask))
                    {
                        *pu |= uMask;
                        return (uint8_t *)pSub->pvPages
                            + PAGE_SIZE * (iBit + ((uint8_t *)pu - (uint8_t *)&pSub->auBitmap[0]) * 8);
                    }
                    iBit++;
                    uMask <<= 1;
                }
                STAM_COUNTER_INC(&pPool->cErrors);
                AssertMsgFailed(("how odd, expected to find a free bit in %#x, but didn't\n", u));
            }
            /* next */
            pu++;
        }
#endif
        STAM_COUNTER_INC(&pPool->cErrors);
#ifdef VBOX_WITH_STATISTICS
        pPool->cFreePages++;
#endif
        AssertMsgFailed(("how strange, expected to find a free bit in %p, but didn't (%d pages supposed to be free!)\n", pSub, pSub->cPagesFree + 1));
    }

    /*
     * Allocate new subpool.
     */
    unsigned        cPages = !pPool->fLow ? 128 : 32;
    PMMPAGESUBPOOL  pSub;
    int rc = MMHyperAlloc(pPool->pVM,
                          RT_OFFSETOF(MMPAGESUBPOOL, auBitmap[cPages / (sizeof(pSub->auBitmap[0]) * 8)])
                          + (sizeof(SUPPAGE) + sizeof(MMPPLOOKUPHCPHYS)) * cPages
                          + sizeof(MMPPLOOKUPHCPTR),
                          0,
                          MM_TAG_MM_PAGE,
                          (void **)&pSub);
    if (RT_FAILURE(rc))
        return NULL;

    PSUPPAGE paPhysPages = (PSUPPAGE)&pSub->auBitmap[cPages / (sizeof(pSub->auBitmap[0]) * 8)];
    Assert((uintptr_t)paPhysPages >= (uintptr_t)&pSub->auBitmap[1]);
    if (!pPool->fLow)
    {
        rc = SUPR3PageAllocEx(cPages,
                              0 /* fFlags */,
                              &pSub->pvPages,
                              NULL,
                              paPhysPages);
        if (RT_FAILURE(rc))
            rc = VMSetError(pPool->pVM, rc, RT_SRC_POS,
                            N_("Failed to lock host %zd bytes of memory (out of memory)"), (size_t)cPages << PAGE_SHIFT);
    }
    else
        rc = SUPR3LowAlloc(cPages, &pSub->pvPages, NULL, paPhysPages);
    if (RT_SUCCESS(rc))
    {
        /*
         * Setup the sub structure and allocate the requested page.
         */
        pSub->cPages    = cPages;
        pSub->cPagesFree= cPages - 1;
        pSub->paPhysPages = paPhysPages;
        memset(pSub->auBitmap, 0, cPages / 8);
        /* allocate first page. */
        pSub->auBitmap[0] |= 1;
        /* link into free chain. */
        pSub->pNextFree = pPool->pHeadFree;
        pPool->pHeadFree= pSub;
        /* link into main chain. */
        pSub->pNext     = pPool->pHead;
        pPool->pHead    = pSub;
        /* update pool statistics. */
        pPool->cSubPools++;
        pPool->cPages  += cPages;
#ifdef VBOX_WITH_STATISTICS
        pPool->cFreePages += cPages - 1;
#endif

        /*
         * Initialize the physical pages with backpointer to subpool.
         */
        unsigned i = cPages;
        while (i-- > 0)
        {
            AssertMsg(paPhysPages[i].Phys && !(paPhysPages[i].Phys & PAGE_OFFSET_MASK),
                      ("i=%d Phys=%d\n", i, paPhysPages[i].Phys));
            paPhysPages[i].uReserved = (RTHCUINTPTR)pSub;
        }

        /*
         * Initialize the physical lookup record with backpointers to the physical pages.
         */
        PMMPPLOOKUPHCPHYS paLookupPhys = (PMMPPLOOKUPHCPHYS)&paPhysPages[cPages];
        i = cPages;
        while (i-- > 0)
        {
            paLookupPhys[i].pPhysPage = &paPhysPages[i];
            paLookupPhys[i].Core.Key = paPhysPages[i].Phys;
            RTAvlHCPhysInsert(&pPool->pLookupPhys, &paLookupPhys[i].Core);
        }

        /*
         * And the one record for virtual memory lookup.
         */
        PMMPPLOOKUPHCPTR   pLookupVirt = (PMMPPLOOKUPHCPTR)&paLookupPhys[cPages];
        pLookupVirt->pSubPool = pSub;
        pLookupVirt->Core.Key = pSub->pvPages;
        RTAvlPVInsert(&pPool->pLookupVirt, &pLookupVirt->Core);

        /* return allocated page (first). */
        return pSub->pvPages;
    }

    MMHyperFree(pPool->pVM, pSub);
    STAM_COUNTER_INC(&pPool->cErrors);
    if (pPool->fLow)
        VMSetError(pPool->pVM, rc, RT_SRC_POS,
                   N_("Failed to expand page pool for memory below 4GB. Current size: %d pages"),
                   pPool->cPages);
    AssertMsgFailed(("Failed to expand pool%s. rc=%Rrc poolsize=%d\n",
                     pPool->fLow ? " (<4GB)" : "", rc, pPool->cPages));
    return NULL;
}
/**
 * Worker for the --list and --extract commands.
 *
 * @returns The appropriate exit code.
 * @param   pOpts               The Unzip options.
 * @param   pfnCallback         The command specific callback.
 */
static RTEXITCODE rtZipUnzipDoWithMembers(PRTZIPUNZIPCMDOPS pOpts, PFNDOWITHMEMBER pfnCallback,
                                          uint32_t *pcFiles, PRTFOFF pcBytes)
{
    /*
     * Allocate a bitmap to go with the file list.  This will be used to
     * indicate which files we've processed and which not.
     */
    uint32_t *pbmFound = NULL;
    if (pOpts->cFiles)
    {
        pbmFound = (uint32_t *)RTMemAllocZ(((pOpts->cFiles + 31) / 32) * sizeof(uint32_t));
        if (!pbmFound)
            return RTMsgErrorExit(RTEXITCODE_FAILURE, "Failed to allocate the found-file-bitmap");
    }

    uint32_t cFiles = 0;
    RTFOFF cBytesSum = 0;

    /*
     * Open the input archive.
     */
    RTVFSFSSTREAM hVfsFssIn;
    RTEXITCODE rcExit = rtZipUnzipCmdOpenInputArchive(pOpts, &hVfsFssIn);
    if (rcExit == RTEXITCODE_SUCCESS)
    {
        /*
         * Process the stream.
         */
        for (;;)
        {
            /*
             * Retrieve the next object.
             */
            char       *pszName;
            RTVFSOBJ    hVfsObj;
            int rc = RTVfsFsStrmNext(hVfsFssIn, &pszName, NULL, &hVfsObj);
            if (RT_FAILURE(rc))
            {
                if (rc != VERR_EOF)
                    rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "RTVfsFsStrmNext returned %Rrc", rc);
                break;
            }

            /*
             * Should we process this object?
             */
            uint32_t iFile = UINT32_MAX;
            if (   !pOpts->cFiles
                || rtZipUnzipCmdIsNameInArray(pszName, pOpts->papszFiles, &iFile))
            {
                if (pbmFound)
                    ASMBitSet(pbmFound, iFile);

                RTFOFF cBytes = 0;
                rcExit = pfnCallback(pOpts, hVfsObj, pszName, rcExit, &cBytes);

                cBytesSum += cBytes;
                cFiles++;
            }

            /*
             * Release the current object and string.
             */
            RTVfsObjRelease(hVfsObj);
            RTStrFree(pszName);
        }

        /*
         * Complain about any files we didn't find.
         */
        for (uint32_t iFile = 0; iFile <pOpts->cFiles; iFile++)
            if (!ASMBitTest(pbmFound, iFile))
            {
                RTMsgError("%s: Was not found in the archive", pOpts->papszFiles[iFile]);
                rcExit = RTEXITCODE_FAILURE;
            }

        RTVfsFsStrmRelease(hVfsFssIn);
    }

    RTMemFree(pbmFound);

    *pcFiles = cFiles;
    *pcBytes = cBytesSum;

    return RTEXITCODE_SUCCESS;
}
Beispiel #19
0
RTDECL(bool) ASMBitTestAndToggle(volatile void *pvBitmap, int32_t iBit)
{
    bool fRet = ASMBitTest(pvBitmap, iBit);
    ASMBitToggle(pvBitmap, iBit);
    return fRet;
}
Beispiel #20
0
PCR_DISPLAY crServerDisplayGetInitialized(uint32_t idScreen)
{
    if (ASMBitTest(cr_server.DisplaysInitMap, idScreen))
        return &cr_server.aDispplays[idScreen];
    return NULL;
}
Beispiel #21
0
/**
 * Allocates one or more pages off the heap.
 *
 * @returns IPRT status code.
 * @param   pHeap           The page heap.
 * @param   pv              Pointer to what RTHeapPageAlloc returned.
 * @param   cPages          The number of pages that was allocated.
 */
int RTHeapPageFree(PRTHEAPPAGE pHeap, void *pv, size_t cPages)
{
    /*
     * Validate input.
     */
    if (!pv)
        return VINF_SUCCESS;
    AssertPtrReturn(pHeap, VERR_INVALID_HANDLE);
    AssertReturn(pHeap->u32Magic == RTHEAPPAGE_MAGIC, VERR_INVALID_HANDLE);

    /*
     * Grab the lock and look up the page.
     */
    int rc = RTCritSectEnter(&pHeap->CritSect);
    if (RT_SUCCESS(rc))
    {
        PRTHEAPPAGEBLOCK pBlock = (PRTHEAPPAGEBLOCK)RTAvlrPVRangeGet(&pHeap->BlockTree, pv);
        if (pBlock)
        {
            /*
             * Validate the specified address range.
             */
            uint32_t const iPage = (uint32_t)(((uintptr_t)pv - (uintptr_t)pBlock->Core.Key) >> PAGE_SHIFT);
            /* Check the range is within the block. */
            bool fOk = iPage + cPages <= RTMEMPAGEPOSIX_BLOCK_PAGE_COUNT;
            /* Check that it's the start of an allocation. */
            fOk = fOk && ASMBitTest(&pBlock->bmFirst[0], iPage);
            /* Check that the range ends at an allocation boundrary. */
            fOk = fOk && (   iPage + cPages == RTMEMPAGEPOSIX_BLOCK_PAGE_COUNT
                             || ASMBitTest(&pBlock->bmFirst[0], iPage + cPages)
                             || !ASMBitTest(&pBlock->bmAlloc[0], iPage + cPages));
            /* Check the other pages. */
            uint32_t const iLastPage = iPage + cPages - 1;
            for (uint32_t i = iPage + 1; i < iLastPage && fOk; i++)
                fOk = ASMBitTest(&pBlock->bmAlloc[0], i)
                      && !ASMBitTest(&pBlock->bmFirst[0], i);
            if (fOk)
            {
                /*
                 * Free the memory.
                 */
                ASMBitClearRange(&pBlock->bmAlloc[0], iPage, iPage + cPages);
                ASMBitClear(&pBlock->bmFirst[0], iPage);
                pBlock->cFreePages += cPages;
                pHeap->cFreePages  += cPages;
                pHeap->cFreeCalls++;
                if (!pHeap->pHint1 || pHeap->pHint1->cFreePages < pBlock->cFreePages)
                    pHeap->pHint1 = pBlock;

                /*
                 * Shrink the heap. Not very efficient because of the AVL tree.
                 */
                if (   pHeap->cFreePages >= RTMEMPAGEPOSIX_BLOCK_PAGE_COUNT * 3
                        && pHeap->cFreePages >= pHeap->cHeapPages / 2 /* 50% free */
                        && pHeap->cFreeCalls - pHeap->uLastMinimizeCall > RTMEMPAGEPOSIX_BLOCK_PAGE_COUNT
                   )
                {
                    uint32_t cFreePageTarget = pHeap->cHeapPages / 4; /* 25% free */
                    while (pHeap->cFreePages > cFreePageTarget)
                    {
                        pHeap->uLastMinimizeCall = pHeap->cFreeCalls;

                        pBlock = NULL;
                        RTAvlrPVDoWithAll(&pHeap->BlockTree, false /*fFromLeft*/,
                                          rtHeapPageFindUnusedBlockCallback, &pBlock);
                        if (!pBlock)
                            break;

                        void *pv2 = RTAvlrPVRemove(&pHeap->BlockTree, pBlock->Core.Key);
                        Assert(pv2);
                        NOREF(pv2);
                        pHeap->cHeapPages -= RTMEMPAGEPOSIX_BLOCK_PAGE_COUNT;
                        pHeap->cFreePages -= RTMEMPAGEPOSIX_BLOCK_PAGE_COUNT;
                        pHeap->pHint1      = NULL;
                        pHeap->pHint2      = NULL;
                        RTCritSectLeave(&pHeap->CritSect);

                        munmap(pBlock->Core.Key, RTMEMPAGEPOSIX_BLOCK_SIZE);
                        pBlock->Core.Key = pBlock->Core.KeyLast = NULL;
                        pBlock->cFreePages = 0;
                        rtMemBaseFree(pBlock);

                        RTCritSectEnter(&pHeap->CritSect);
                    }
                }
            }
            else
                rc = VERR_INVALID_POINTER;
        }
        else
            rc = VERR_INVALID_POINTER;

        RTCritSectLeave(&pHeap->CritSect);
    }