VirtualBox

Changeset 24738 in vbox for trunk


Ignore:
Timestamp:
Nov 17, 2009 9:33:54 PM (15 years ago)
Author:
vboxsync
Message:

VMReq.cpp: Made VMR3ReqProcessU re-entrant.

Location:
trunk/src/VBox/VMM
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/VMM/VM.cpp

    r24730 r24738  
    811811        STAM_REG(pVM, &pUVM->vm.s.StatReqFree,       STAMTYPE_COUNTER,     "/VM/Req/Free",           STAMUNIT_OCCURENCES,        "Number of VMR3ReqFree calls.");
    812812        STAM_REG(pVM, &pUVM->vm.s.StatReqFreeOverflow, STAMTYPE_COUNTER,   "/VM/Req/FreeOverflow",   STAMUNIT_OCCURENCES,        "Number of times the request was actually freed.");
     813        STAM_REG(pVM, &pUVM->vm.s.StatReqProcessed,  STAMTYPE_COUNTER,     "/VM/Req/Processed",      STAMUNIT_OCCURENCES,        "Number of processed requests (any queue).");
     814        STAM_REG(pVM, &pUVM->vm.s.StatReqMoreThan1,  STAMTYPE_COUNTER,     "/VM/Req/MoreThan1",      STAMUNIT_OCCURENCES,        "Number of times there are more than one request on the queue when processing it.");
     815        STAM_REG(pVM, &pUVM->vm.s.StatReqPushBackRaces, STAMTYPE_COUNTER,  "/VM/Req/PushBackRaces",  STAMUNIT_OCCURENCES,        "Number of push back races.");
    813816
    814817        rc = CPUMR3Init(pVM);
  • trunk/src/VBox/VMM/VMInternal.h

    r24508 r24738  
    198198    /** Number of times the request was actually freed. */
    199199    STAMCOUNTER                     StatReqFreeOverflow;
     200    /** Number of requests served. */
     201    STAMCOUNTER                     StatReqProcessed;
     202    /** Number of times there are more than one request and the others needed to be
     203     * pushed back onto the list. */
     204    STAMCOUNTER                     StatReqMoreThan1;
     205    /** Number of times we've raced someone when pushing the other requests back
     206     * onto the list. */
     207    STAMCOUNTER                     StatReqPushBackRaces;
    200208#endif
    201209
  • trunk/src/VBox/VMM/VMReq.cpp

    r24467 r24738  
    983983
    984984/**
     985 * VMR3ReqProcessU helper that handles cases where there are more than one
     986 * pending request.
     987 *
     988 * @returns The oldest request.
     989 * @param   pUVM                Pointer to the user mode VM structure
     990 * @param   idDstCpu            VMCPUID_ANY or virtual CPU ID.
     991 * @param   pReqList            The list of requests.
     992 * @param   ppvReqs             Pointer to the list head.
     993 */
     994static PVMREQ vmR3ReqProcessUTooManyHelper(PUVM pUVM, VMCPUID idDstCpu, PVMREQ pReqList, void * volatile *ppvReqs)
     995{
     996    STAM_COUNTER_INC(&pUVM->vm.s.StatReqMoreThan1);
     997    /* Chop off the last one (pReq). */
     998    PVMREQ pPrev;
     999    PVMREQ pReqRet = pReqList;
     1000    do
     1001    {
     1002        pPrev = pReqRet;
     1003        pReqRet = pReqRet->pNext;
     1004    } while (pReqRet->pNext);
     1005    ASMAtomicWritePtr((void * volatile *)&pPrev->pNext, NULL);
     1006
     1007    /* Push the others back onto the list (end of it). */
     1008    Log2(("VMR3ReqProcess: Pushing back %p %p...\n", pReqList, pReqList->pNext));
     1009    if (RT_UNLIKELY(!ASMAtomicCmpXchgPtr(ppvReqs, pReqList, NULL)))
     1010    {
     1011        STAM_COUNTER_INC(&pUVM->vm.s.StatReqPushBackRaces);
     1012        do
     1013        {
     1014            ASMNopPause();
     1015            PVMREQ pReqList2 = (PVMREQ)ASMAtomicXchgPtr(ppvReqs, NULL);
     1016            if (pReqList2)
     1017            {
     1018                PVMREQ pLast = pReqList2;
     1019                while (pLast->pNext)
     1020                    pLast = pLast->pNext;
     1021                ASMAtomicWritePtr((void * volatile *)&pLast->pNext, pReqList);
     1022                pReqList = pReqList2;
     1023            }
     1024        } while (!ASMAtomicCmpXchgPtr(ppvReqs, pReqList, NULL));
     1025    }
     1026
     1027    if (RT_LIKELY(pUVM->pVM))
     1028    {
     1029        if (idDstCpu == VMCPUID_ANY)
     1030            VM_FF_SET(pUVM->pVM, VM_FF_REQUEST);
     1031        else
     1032            VMCPU_FF_SET(&pUVM->pVM->aCpus[idDstCpu], VMCPU_FF_REQUEST);
     1033    }
     1034
     1035    return pReqRet;
     1036}
     1037
     1038
     1039/**
    9851040 * Process pending request(s).
    9861041 *
     
    9961051 *
    9971052 * @note    SMP safe (multiple EMTs trying to satisfy VM_FF_REQUESTs).
     1053 *
     1054 * @remarks This was made reentrant for
    9981055 */
    9991056VMMR3DECL(int) VMR3ReqProcessU(PUVM pUVM, VMCPUID idDstCpu)
     
    10111068    {
    10121069        /*
    1013          * Get pending requests.
     1070         * Get the pending requests.
     1071         * If there are more than one request, unlink the oldest and put the
     1072         * rest back so that we're reentrant.
    10141073         */
    1015         void * volatile *ppReqs;
     1074        void * volatile *ppvReqs;
    10161075        if (idDstCpu == VMCPUID_ANY)
    10171076        {
    1018             ppReqs = (void * volatile *)&pUVM->vm.s.pReqs;
     1077            ppvReqs = (void * volatile *)&pUVM->vm.s.pReqs;
    10191078            if (RT_LIKELY(pUVM->pVM))
    10201079                VM_FF_CLEAR(pUVM->pVM, VM_FF_REQUEST);
     
    10241083            Assert(idDstCpu < pUVM->cCpus);
    10251084            Assert(pUVM->aCpus[idDstCpu].vm.s.NativeThreadEMT == RTThreadNativeSelf());
    1026             ppReqs = (void * volatile *)&pUVM->aCpus[idDstCpu].vm.s.pReqs;
     1085            ppvReqs = (void * volatile *)&pUVM->aCpus[idDstCpu].vm.s.pReqs;
    10271086            if (RT_LIKELY(pUVM->pVM))
    10281087                VMCPU_FF_CLEAR(&pUVM->pVM->aCpus[idDstCpu], VMCPU_FF_REQUEST);
    10291088        }
    1030         PVMREQ pReqs = (PVMREQ)ASMAtomicXchgPtr(ppReqs, NULL);
    1031         if (!pReqs)
     1089
     1090        PVMREQ pReq = (PVMREQ)ASMAtomicXchgPtr(ppvReqs, NULL);
     1091        if (!pReq)
    10321092            break;
     1093        if (RT_UNLIKELY(pReq->pNext))
     1094            pReq = vmR3ReqProcessUTooManyHelper(pUVM, idDstCpu, pReq, ppvReqs);
    10331095
    10341096        /*
    1035          * Reverse the list to process it in FIFO order.
     1097         * Process the request.
     1098         * Note! The status code handling here extremely important and yet very
     1099         *       fragile.
    10361100         */
    1037         PVMREQ pReq = pReqs;
    1038         if (pReq->pNext)
    1039             Log2(("VMR3ReqProcess: 2+ requests: %p %p %p\n", pReq, pReq->pNext, pReq->pNext->pNext));
    1040         pReqs = NULL;
    1041         while (pReq)
    1042         {
    1043             Assert(pReq->enmState == VMREQSTATE_QUEUED);
    1044             Assert(pReq->pUVM == pUVM);
    1045             PVMREQ pCur = pReq;
    1046             pReq = pReq->pNext;
    1047             pCur->pNext = pReqs;
    1048             pReqs = pCur;
    1049         }
    1050 
    1051 
    1052         /*
    1053          * Process the requests.
    1054          *
    1055          * Since this is a FF worker certain rules applies to the
    1056          * status codes. See the EM section in VBox/err.h and EM.cpp for details.
    1057          */
    1058         while (pReqs)
    1059         {
    1060             /* Unchain the first request and advance the list. */
    1061             pReq = pReqs;
    1062             pReqs = pReqs->pNext;
    1063             pReq->pNext = NULL;
    1064 
    1065             /* Process the request */
    1066             int rc2 = vmR3ReqProcessOneU(pUVM, pReq);
    1067 
    1068             /*
    1069              * The status code handling extremely important yet very fragile. Should probably
    1070              * look for a better way of communicating status changes to EM...
    1071              */
    1072             if (    rc2 >= VINF_EM_FIRST
    1073                 &&  rc2 <= VINF_EM_LAST
    1074                 &&  (   rc == VINF_SUCCESS
    1075                      || rc2 < rc) )
    1076                 rc = rc2;
    1077             /** @todo may have to abort processing to propagate EM scheduling status codes
    1078              *        up to the caller... See the ugly hacks after VMMR3EmtRendezvousFF
    1079              *        and VMR3ReqProcessU in EM.cpp. */
    1080         }
     1101        STAM_COUNTER_INC(&pUVM->vm.s.StatReqProcessed);
     1102        int rc2 = vmR3ReqProcessOneU(pUVM, pReq);
     1103        if (    rc2 >= VINF_EM_FIRST
     1104            &&  rc2 <= VINF_EM_LAST
     1105            &&  (   rc == VINF_SUCCESS
     1106                 || rc2 < rc) )
     1107            rc = rc2;
     1108        /** @todo may have to abort processing to propagate EM scheduling status codes
     1109         *        up to the caller... See the ugly hacks after VMMR3EmtRendezvousFF
     1110         *        and VMR3ReqProcessU in EM.cpp. */
    10811111    }
    10821112
     
    10961126static int  vmR3ReqProcessOneU(PUVM pUVM, PVMREQ pReq)
    10971127{
    1098     LogFlow(("vmR3ReqProcessOne: pReq=%p type=%d fFlags=%#x\n", pReq, pReq->enmType, pReq->fFlags));
     1128    LogFlow(("vmR3ReqProcessOneU: pReq=%p type=%d fFlags=%#x\n", pReq, pReq->enmType, pReq->fFlags));
    10991129
    11001130    /*
     
    12101240    {
    12111241        /* Free the packet, nobody is waiting. */
    1212         LogFlow(("vmR3ReqProcessOne: Completed request %p: rcReq=%Rrc rcRet=%Rrc - freeing it\n",
     1242        LogFlow(("vmR3ReqProcessOneU: Completed request %p: rcReq=%Rrc rcRet=%Rrc - freeing it\n",
    12131243                 pReq, rcReq, rcRet));
    12141244        VMR3ReqFree(pReq);
     
    12171247    {
    12181248        /* Notify the waiter and him free up the packet. */
    1219         LogFlow(("vmR3ReqProcessOne: Completed request %p: rcReq=%Rrc rcRet=%Rrc - notifying waiting thread\n",
     1249        LogFlow(("vmR3ReqProcessOneU: Completed request %p: rcReq=%Rrc rcRet=%Rrc - notifying waiting thread\n",
    12201250                 pReq, rcReq, rcRet));
    12211251        ASMAtomicXchgSize(&pReq->fEventSemClear, false);
Note: See TracChangeset for help on using the changeset viewer.

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