VirtualBox

Changeset 59754 in vbox


Ignore:
Timestamp:
Feb 20, 2016 2:41:57 AM (9 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
105624
Message:

vfsreadahead.cpp: Completed and debugged.

Location:
trunk
Files:
5 edited

Legend:

Unmodified
Added
Removed
  • trunk/include/iprt/list.h

    r59184 r59754  
    161161}
    162162
     163
     164/**
     165 * Remove a node from a list, returns value.
     166 *
     167 * @returns pNode
     168 * @param   pNode               The node to remove.
     169 */
     170DECLINLINE(PRTLISTNODE) RTListNodeRemoveRet(PRTLISTNODE pNode)
     171{
     172    PRTLISTNODE pPrev = pNode->pPrev;
     173    PRTLISTNODE pNext = pNode->pNext;
     174
     175    pPrev->pNext = pNext;
     176    pNext->pPrev = pPrev;
     177
     178    /* poison */
     179    pNode->pNext = NULL;
     180    pNode->pPrev = NULL;
     181
     182    return pNode;
     183}
     184
    163185/**
    164186 * Checks if a node is the last element in the list.
     
    246268 * Returns the first element in the list (checks for empty list).
    247269 *
    248  * @retval  Pointer to the first list element.
    249  * @retval  NULL if the list is empty.
     270 * @returns Pointer to the first list element, or NULL if empty list.
    250271 *
    251272 * @param   pList               List to get the first element from.
     
    262283 * Returns the last element in the list (checks for empty list).
    263284 *
    264  * @retval  Pointer to the last list element.
    265  * @retval  NULL if the list is empty.
     285 * @returns Pointer to the last list element, or NULL if empty list.
    266286 *
    267287 * @param   pList               List to get the last element from.
     
    278298 * Returns the next node in the list or NULL if the end has been reached.
    279299 *
    280  * @returns The next node or NULL.
     300 * @returns The next node, or NULL if end of list.
    281301 *
    282302 * @param   pList               The list @a pCurNode is linked on.
     
    294314 * Returns the previous node in the list or NULL if the start has been reached.
    295315 *
    296  * @returns The previous node or NULL.
     316 * @returns The previous node, or NULL if end of list.
    297317 *
    298318 * @param   pList               The list @a pCurNode is linked on.
     
    306326#define RTListGetPrevCpp(pList, pCurNode, Type, Member) \
    307327    ( (pCurNode)->Member.pPrev != (pList) ? RT_FROM_CPP_MEMBER((pCurNode)->Member.pPrev, Type, Member) : NULL )
     328
     329
     330/**
     331 * Removes and returns the first element in the list (checks for empty list).
     332 *
     333 * @returns Pointer to the first list element, or NULL if empty list.
     334 *
     335 * @param   pList               List to get the first element from.
     336 * @param   Type                Structure the list node is a member of.
     337 * @param   Member              The list node member.
     338 */
     339#define RTListRemoveFirst(pList, Type, Member) \
     340    (!RTListIsEmpty(pList) ? RT_FROM_MEMBER(RTListNodeRemoveRet((pList)->pNext), Type, Member) : NULL)
     341/** @copydoc RTListRemoveFirst */
     342#define RTListRemoveFirstCpp(pList, Type, Member) \
     343    (!RTListIsEmpty(pList) ? RT_FROM_CPP_MEMBER(RTListNodeRemoveRet((pList)->pNext), Type, Member) : NULL)
     344
     345/**
     346 * Removes and returns the last element in the list (checks for empty list).
     347 *
     348 * @returns Pointer to the last list element, or NULL if empty list.
     349 *
     350 * @param   pList               List to get the last element from.
     351 * @param   Type                Structure the list node is a member of.
     352 * @param   Member              The list node member.
     353 */
     354#define RTListRemoveLast(pList, Type, Member) \
     355    (!RTListIsEmpty(pList) ? RT_FROM_MEMBER(RTListNodeRemoveRet((pList)->pPrev), Type, Member) : NULL)
     356/** @copydoc RTListRemoveLast */
     357#define RTListRemoveLastCpp(pList, Type, Member) \
     358    (!RTListIsEmpty(pList) ? RT_FROM_CPP_MEMBER(RTListNodeRemoveRet((pList)->pPrev), Type, Member) : NULL)
     359
     360/**
     361 * Removes and returns the next node in the list or NULL if the end has been
     362 * reached.
     363 *
     364 * @returns The next node, or NULL if end of list.
     365 *
     366 * @param   pList               The list @a pCurNode is linked on.
     367 * @param   pCurNode            The current node, of type @a Type.
     368 * @param   Type                Structure the list node is a member of.
     369 * @param   Member              The list node member.
     370 */
     371#define RTListRemoveNext(pList, pCurNode, Type, Member) \
     372    ( (pCurNode)->Member.pNext != (pList) ? RT_FROM_MEMBER(RTListNodeRemoveRet((pCurNode)->Member.pNext), Type, Member) : NULL )
     373/** @copydoc RTListRemoveNext */
     374#define RTListRemoveNextCpp(pList, pCurNode, Type, Member) \
     375    ( (pCurNode)->Member.pNext != (pList) ? RT_FROM_CPP_MEMBER(RTListNodeRemoveRet((pCurNode)->Member.pNext), Type, Member) : NULL )
     376
     377/**
     378 * Removes and returns the previous node in the list or NULL if the start has
     379 * been reached.
     380 *
     381 * @returns The previous node, or NULL if end of list.
     382 *
     383 * @param   pList               The list @a pCurNode is linked on.
     384 * @param   pCurNode            The current node, of type @a Type.
     385 * @param   Type                Structure the list node is a member of.
     386 * @param   Member              The list node member.
     387 */
     388#define RTListRemovePrev(pList, pCurNode, Type, Member) \
     389    ( (pCurNode)->Member.pNext != (pList) ? RT_FROM_MEMBER(RTListNodeRemoveRet((pCurNode)->Member.pPrev), Type, Member) : NULL )
     390/** @copydoc RTListRemovePrev */
     391#define RTListRemovePrevCpp(pList, pCurNode, Type, Member) \
     392    ( (pCurNode)->Member.pNext != (pList) ? RT_FROM_CPP_MEMBER(RTListNodeRemoveRet((pCurNode)->Member.pPrev), Type, Member) : NULL )
     393
    308394
    309395/**
  • trunk/include/iprt/mangling.h

    r59747 r59754  
    23122312# define RTVfsUtilDummyPollOne                          RT_MANGLER(RTVfsUtilDummyPollOne)
    23132313# define RTVfsUtilPumpIoStreams                         RT_MANGLER(RTVfsUtilPumpIoStreams)
     2314# define RTVfsCreateReadAheadForFile                    RT_MANGLER(RTVfsCreateReadAheadForFile)
     2315# define RTVfsCreateReadAheadForIoStream                RT_MANGLER(RTVfsCreateReadAheadForIoStream)
    23142316# define RTZipBlockCompress                             RT_MANGLER(RTZipBlockCompress)
    23152317# define RTZipBlockDecompress                           RT_MANGLER(RTZipBlockDecompress)
  • trunk/include/iprt/vfs.h

    r59620 r59754  
    10101010RTDECL(int) RTVfsUtilPumpIoStreams(RTVFSIOSTREAM hVfsIosSrc, RTVFSIOSTREAM hVfsIosDst, size_t cbBufHint);
    10111011
     1012/**
     1013 * Create an I/O stream instance performing simple sequential read-ahead.
     1014 *
     1015 * @returns IPRT status code.
     1016 * @param   hVfsIos     The input stream to perform read ahead on.  If this is
     1017 *                      actually for a file object, the returned I/O stream
     1018 *                      handle can also be cast to a file handle.
     1019 * @param   fFlags      Flags reserved for future use, MBZ.
     1020 * @param   cBuffers    How many read ahead buffers to use. Specify 0 for
     1021 *                      default value.
     1022 * @param   cbBuffers   The size of each read ahead buffer. Specify 0 for
     1023 *                      default value.
     1024 * @param   phVfsIos    Where to return the read ahead I/O stream handle.
     1025 *
     1026 * @remarks Careful using this on a message pipe or socket.  The reads are
     1027 *          performed in blocked mode and it may be host and/or implementation
     1028 *          dependent whether they will return ready data immediate or wait
     1029 *          until there's a whole @a cbBuffer (or default) worth ready.
     1030 *
     1031 * @sa      RTVfsCreateReadAheadForFile
     1032 */
     1033RTDECL(int) RTVfsCreateReadAheadForIoStream(RTVFSIOSTREAM hVfsIos, uint32_t fFlags, uint32_t cBuffers, uint32_t cbBuffer,
     1034                                            PRTVFSIOSTREAM phVfsIos);
     1035
     1036/**
     1037 * Create an I/O stream instance performing simple sequential read-ahead.
     1038 *
     1039 * @returns IPRT status code.
     1040 * @param   hVfsFile    The input file to perform read ahead on.
     1041 * @param   fFlags      Flags reserved for future use, MBZ.
     1042 * @param   cBuffers    How many read ahead buffers to use. Specify 0 for
     1043 *                      default value.
     1044 * @param   cbBuffers   The size of each read ahead buffer. Specify 0 for
     1045 *                      default value.
     1046 * @param   phVfsIos    Where to return the read ahead I/O stream handle.
     1047 * @sa      RTVfsCreateReadAheadForIoStream
     1048 */
     1049RTDECL(int) RTVfsCreateReadAheadForFile(RTVFSFILE hVfsFile, uint32_t fFlags, uint32_t cBuffers, uint32_t cbBuffer,
     1050                                        PRTVFSFILE phVfsFile);
     1051
    10121052/** @}  */
    10131053
  • trunk/src/VBox/Runtime/Makefile.kmk

    r59751 r59754  
    599599        common/vfs/vfsmemory.cpp \
    600600        common/vfs/vfsmisc.cpp \
     601        common/vfs/vfsreadahead.cpp \
    601602        common/vfs/vfsstdfile.cpp \
    602603        common/vfs/vfsstdpipe.cpp \
  • trunk/src/VBox/Runtime/common/vfs/vfsreadahead.cpp

    r59729 r59754  
    104104    uint64_t                offConsumer;
    105105
     106    /** The end-of-file(/stream) offset.  This is initially UINT64_MAX and later
     107     *  set when reading past EOF.  */
     108    uint64_t                offEof;
     109
    106110    /** The read ahead thread. */
    107111    RTTHREAD                hThread;
     
    200204    PRTVFSREADAHEAD pThis = (PRTVFSREADAHEAD)pvThis;
    201205
    202     Assert(pSgBuf->cSegs == 1);
     206    Assert(pSgBuf->cSegs == 1); /* Caller deals with multiple SGs. */
    203207    Assert(off < 0);
    204208    NOREF(fBlocking);
     
    209213     * section, just in case a buffer got inserted while we were waiting for it.
    210214     */
    211     int    rc = VINF_SUCCESS;
    212     size_t cbTotalRead     = 0;
    213     bool   fPokeReader     = false;
    214     bool   fOwnsIoCritSect = false;
     215    int      rc = VINF_SUCCESS;
     216    uint8_t *pbDst           = (uint8_t *)pSgBuf->paSegs[0].pvSeg;
     217    size_t   cbDst           =            pSgBuf->paSegs[0].cbSeg;
     218    size_t   cbTotalRead     = 0;
     219    bool     fPokeReader     = false;
     220    bool     fOwnsIoCritSect = false;
    215221    RTCritSectEnter(&pThis->BufferCritSect);
    216222    for (;;)
    217223    {
    218224        /*
    219          * Try satisfy the read from the buffer.
     225         * Try satisfy the read from the buffers.
    220226         */
    221227        uint64_t offCur = pThis->offConsumer;
     
    223229        {
    224230            offCur = (uint64_t)off;
     231            if (pThis->offConsumer != offCur)
     232                fPokeReader = true; /* If the current position changed, poke it in case it stopped at EOF. */
    225233            pThis->offConsumer = offCur;
    226234        }
    227235
    228         PRTVFSREADAHEADBUFDESC pCurBufDesc;
    229         RTListForEach(&pThis->ConsumerList, pCurBufDesc, RTVFSREADAHEADBUFDESC, ListEntry)
     236        PRTVFSREADAHEADBUFDESC pBufDesc, pNextBufDesc;
     237        RTListForEachSafe(&pThis->ConsumerList, pBufDesc, pNextBufDesc, RTVFSREADAHEADBUFDESC, ListEntry)
    230238        {
    231             if (pThis->offConsumer)
     239            /* The buffers are sorted and reads must start in a buffer if
     240               anything should be taken from the buffer (at least for now). */
     241            if (offCur < pBufDesc->off)
     242                break;
     243
     244            /* Anything we can read from this buffer? */
     245            uint64_t offCurBuf = offCur - pBufDesc->off;
     246            if (offCurBuf < pBufDesc->cbFilled)
    232247            {
     248                size_t const cbFromCurBuf = RT_MIN(pBufDesc->cbFilled - offCurBuf, cbDst);
     249                memcpy(pbDst, pBufDesc->pbBuffer + offCurBuf, cbFromCurBuf);
     250                pbDst              += cbFromCurBuf;
     251                cbDst              -= cbFromCurBuf;
     252                cbTotalRead        += cbFromCurBuf;
     253                offCur             += cbFromCurBuf;
    233254            }
     255
     256            /* Discard buffers we've read past. */
     257            if (pBufDesc->off + pBufDesc->cbFilled <= offCur)
     258            {
     259                RTListNodeRemove(&pBufDesc->ListEntry);
     260                RTListAppend(&pThis->FreeList, &pBufDesc->ListEntry);
     261                fPokeReader = true; /* Poke it as there are now more buffers available. */
     262            }
     263
     264            /* Stop if we're done. */
     265            if (!cbDst)
     266                break;
    234267        }
    235 /** @todo EOF handling! */
    236         if (pSgBuf->cbSegLeft == 0)
     268
     269        pThis->offConsumer = offCur;
     270        if (off != -1)
     271            off = offCur;
     272
     273        if (!cbDst)
    237274            break;
     275
     276        /*
     277         * Check if we've reached the end of the file/stream.
     278         */
     279        if (offCur >= pThis->offEof)
     280        {
     281            rc = pcbRead ? VINF_EOF : VERR_EOF;
     282            break;
     283        }
     284
    238285
    239286        /*
     
    250297        }
    251298
     299
    252300        /*
    253301         * Do a direct read of the remaining data.
    254302         */
    255         //size_t cbDirectRead;
    256 
    257 
     303        if (off == -1)
     304        {
     305            RTFOFF offActual = RTVfsIoStrmTell(pThis->hIos);
     306            if (offActual >= 0 && (uint64_t)offActual != offCur)
     307                off = offCur;
     308        }
     309        RTSGSEG TmpSeg = { pbDst, cbDst };
     310        RTSGBUF TmpSgBuf;
     311        RTSgBufInit(&TmpSgBuf, &TmpSeg, 1);
     312        size_t cbThisRead = cbDst;
     313        rc = RTVfsIoStrmSgRead(pThis->hIos, off, pSgBuf, fBlocking, pcbRead ? &cbThisRead : NULL);
     314        if (RT_SUCCESS(rc))
     315        {
     316            cbTotalRead = cbThisRead;
     317            offCur     += cbThisRead;
     318            pThis->offConsumer = offCur;
     319            if (rc != VINF_EOF)
     320                fPokeReader = true;
     321            else
     322                pThis->offEof = offCur;
     323        }
     324        /* else if (rc == VERR_EOF): hard to say where exactly the current position
     325           is here as cannot have had a non-NULL pcbRead.  Set offEof later. */
     326        break;
    258327    }
    259328    RTCritSectLeave(&pThis->BufferCritSect);
    260329    if (fOwnsIoCritSect)
    261330        RTCritSectLeave(&pThis->IoCritSect);
    262     if (fPokeReader)
     331    if (fPokeReader && rc != VINF_EOF && rc != VERR_EOF)
    263332        RTThreadUserSignal(pThis->hThread);
    264333
     
    487556    Assert(pThis);
    488557
    489     while (pThis->fTerminateThread)
     558    while (!pThis->fTerminateThread)
    490559    {
    491560        int rc;
    492561
    493 /** @todo EOF handling.   */
    494562        /*
    495563         * Is there a buffer handy for reading ahead.
     
    498566        RTCritSectEnter(&pThis->BufferCritSect);
    499567        if (!pThis->fTerminateThread)
    500             pBufDesc = RTListGetFirst(&pThis->FreeList, RTVFSREADAHEADBUFDESC, ListEntry);
     568            pBufDesc = RTListRemoveFirst(&pThis->FreeList, RTVFSREADAHEADBUFDESC, ListEntry);
    501569        RTCritSectLeave(&pThis->BufferCritSect);
    502570
     
    516584                if (RT_SUCCESS(rc))
    517585                {
     586                    if (rc == VINF_EOF)
     587                        pThis->offEof = pBufDesc->off + cbRead;
    518588                    pBufDesc->cbFilled = (uint32_t)cbRead;
    519589
     
    534604                            RTListPrepend(&pThis->ConsumerList, &pBufDesc->ListEntry);
    535605                        else
     606                        {
     607                            Assert(pAfter->off <= pBufDesc->off);
    536608                            RTListNodeInsertAfter(&pAfter->ListEntry, &pBufDesc->ListEntry);
     609                        }
    537610                    }
    538611                    RTCritSectLeave(&pThis->BufferCritSect);
    539612                    pBufDesc = NULL;
     613
     614#ifdef RT_STRICT
     615                    /* Verify the list ordering.  */
     616                    unsigned                cAsserted = 0;
     617                    uint64_t                offAssert = 0;
     618                    PRTVFSREADAHEADBUFDESC  pAssertCur;
     619                    RTListForEach(&pThis->ConsumerList, pAssertCur, RTVFSREADAHEADBUFDESC, ListEntry)
     620                    {
     621                        Assert(offAssert <= pAssertCur->off);
     622                        offAssert = pAssertCur->off;
     623                        Assert(cAsserted < pThis->cBuffers);
     624                        cAsserted++;
     625                    }
     626#endif
    540627                }
     628                else
     629                    Assert(rc != VERR_EOF);
    541630            }
    542631            RTCritSectLeave(&pThis->IoCritSect);
    543632
    544633            /*
    545              * If we succeeded, loop without delay to start processing the next buffer.
     634             * If we succeeded and we didn't yet reach the end of the stream,
     635             * loop without delay to start processing the next buffer.
    546636             */
    547             if (RT_LIKELY(!pBufDesc))
     637            if (RT_LIKELY(!pBufDesc && rc != VINF_EOF))
    548638                continue;
    549639
    550             /* On failure or termination, put the buffer back in the free list and wait. */
    551             RTCritSectEnter(&pThis->BufferCritSect);
    552             RTListPrepend(&pThis->FreeList, &pBufDesc->ListEntry);
    553             RTCritSectLeave(&pThis->BufferCritSect);
     640            /* Put any unused buffer back in the free list (termination/failure, not EOF). */
     641            if (pBufDesc)
     642            {
     643                RTCritSectEnter(&pThis->BufferCritSect);
     644                RTListPrepend(&pThis->FreeList, &pBufDesc->ListEntry);
     645                RTCritSectLeave(&pThis->BufferCritSect);
     646            }
    554647            if (pThis->fTerminateThread)
    555648                break;
     
    609702            pThis->cBuffers         = cBuffers;
    610703            pThis->cbBuffer         = cbBuffer;
     704            pThis->offEof           = UINT64_MAX;
    611705            pThis->offConsumer      = RTVfsIoStrmTell(hVfsIosSrc);
    612706            if ((RTFOFF)pThis->offConsumer >= 0)
Note: See TracChangeset for help on using the changeset viewer.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette