VirtualBox

Ignore:
Timestamp:
Jun 20, 2009 6:25:43 PM (15 years ago)
Author:
vboxsync
Message:

VMM: Added TMTimerSetRelative and changed TMTimerSet(Millies|Micro|Nano) to use it. Intended to reduce races when starting timers running on the virtual sync clock.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/VMM/VMMAll/TMAll.cpp

    r20120 r20733  
    751751VMMDECL(int) TMTimerSet(PTMTIMER pTimer, uint64_t u64Expire)
    752752{
    753     STAM_PROFILE_START(&pTimer->CTX_SUFF(pVM)->tm.s.CTXALLSUFF(StatTimerSet), a);
     753    STAM_PROFILE_START(&pTimer->CTX_SUFF(pVM)->tm.s.CTX_SUFF_Z(StatTimerSet), a);
    754754    TMTIMER_ASSERT_CRITSECT(pTimer);
    755755
     
    852852
    853853/**
     854 * Return the current time for the specified clock, setting pu64Now if not NULL.
     855 *
     856 * @returns Current time.
     857 * @param   pVM             The VM handle.
     858 * @param   enmClock        The clock to query.
     859 * @param   pu64Now         Optional pointer where to store the return time
     860 */
     861DECL_FORCE_INLINE(uint64_t) tmTimerSetRelativeNowWorker(PVM pVM, TMCLOCK enmClock, uint64_t *pu64Now)
     862{
     863    uint64_t u64Now;
     864    switch (enmClock)
     865    {
     866        case TMCLOCK_VIRTUAL_SYNC:
     867            u64Now = TMVirtualSyncGet(pVM);
     868            break;
     869        case TMCLOCK_VIRTUAL:
     870            u64Now = TMVirtualGet(pVM);
     871            break;
     872        case TMCLOCK_REAL:
     873            u64Now = TMRealGet(pVM);
     874            break;
     875        default:
     876            AssertFatalMsgFailed(("%d\n", enmClock));
     877    }
     878
     879    if (pu64Now)
     880        *pu64Now = u64Now;
     881    return u64Now;
     882}
     883
     884
     885/**
     886 * Arm a timer with a expire time relative to the current time.
     887 *
     888 * @returns VBox status.
     889 * @param   pTimer          Timer handle as returned by one of the create functions.
     890 * @param   cTicksToNext    Clock ticks until the next time expiration.
     891 * @param   pu64Now         Where to return the current time stamp used.
     892 *                          Optional.
     893 */
     894VMMDECL(int) TMTimerSetRelative(PTMTIMER pTimer, uint64_t cTicksToNext, uint64_t *pu64Now)
     895{
     896    STAM_PROFILE_START(&pTimer->CTX_SUFF(pVM)->tm.s.CTX_SUFF_Z(StatTimerSetRelative), a);
     897    TMTIMER_ASSERT_CRITSECT(pTimer);
     898    PVM         pVM      = pTimer->CTX_SUFF(pVM);
     899    TMCLOCK     enmClock = pTimer->enmClock;
     900    bool        fOwnLock = false;
     901    int         rc;
     902
     903    /** @todo find the most frequently used paths and make them skip tmSchedule and tmTimerTryWithLink. */
     904    for (int cRetries = 1000; ; cRetries--)
     905    {
     906        /*
     907         * Try to take the appropriate lock to increase the likelyhood
     908         * that we don't race timer queue running and to some extend
     909         * clock queries.
     910         */
     911        if (!fOwnLock)
     912        {
     913            if (enmClock == TMCLOCK_VIRTUAL_SYNC)
     914                fOwnLock = RT_SUCCESS(tmVirtualSyncTryLock(pVM));
     915            else
     916                fOwnLock = RT_SUCCESS(tmTryLock(pVM));
     917        }
     918
     919        /*
     920         * Change to any of the SET_EXPIRE states if valid and then to SCHEDULE or RESCHEDULE.
     921         */
     922        TMTIMERSTATE    enmState = pTimer->enmState;
     923        switch (enmState)
     924        {
     925            case TMTIMERSTATE_EXPIRED_DELIVER:
     926            case TMTIMERSTATE_STOPPED:
     927                if (tmTimerTryWithLink(pTimer, TMTIMERSTATE_PENDING_SCHEDULE_SET_EXPIRE, enmState))
     928                {
     929                    Assert(!pTimer->offPrev);
     930                    Assert(!pTimer->offNext);
     931                    pTimer->u64Expire = cTicksToNext + tmTimerSetRelativeNowWorker(pVM, enmClock, pu64Now);
     932                    Log2(("TMTimerSetRelative: %p:{.enmState=%s, .pszDesc='%s', .u64Expire=%'RU64} cRetries=%d [EXP/STOP]\n",
     933                          pTimer, tmTimerState(enmState), R3STRING(pTimer->pszDesc), pTimer->u64Expire, cRetries));
     934                    TM_SET_STATE(pTimer, TMTIMERSTATE_PENDING_SCHEDULE);
     935                    tmSchedule(pTimer);
     936                    rc = VINF_SUCCESS;
     937                    break;
     938                }
     939                rc = VERR_TRY_AGAIN;
     940                break;
     941
     942            case TMTIMERSTATE_PENDING_SCHEDULE:
     943            case TMTIMERSTATE_PENDING_STOP_SCHEDULE:
     944                if (tmTimerTry(pTimer, TMTIMERSTATE_PENDING_SCHEDULE_SET_EXPIRE, enmState))
     945                {
     946                    pTimer->u64Expire = cTicksToNext + tmTimerSetRelativeNowWorker(pVM, enmClock, pu64Now);
     947                    Log2(("TMTimerSetRelative: %p:{.enmState=%s, .pszDesc='%s', .u64Expire=%'RU64} cRetries=%d [PEND_SCHED]\n",
     948                          pTimer, tmTimerState(enmState), R3STRING(pTimer->pszDesc), pTimer->u64Expire, cRetries));
     949                    TM_SET_STATE(pTimer, TMTIMERSTATE_PENDING_SCHEDULE);
     950                    tmSchedule(pTimer);
     951                    rc = VINF_SUCCESS;
     952                    break;
     953                }
     954                rc = VERR_TRY_AGAIN;
     955                break;
     956
     957
     958            case TMTIMERSTATE_ACTIVE:
     959                if (tmTimerTryWithLink(pTimer, TMTIMERSTATE_PENDING_RESCHEDULE_SET_EXPIRE, enmState))
     960                {
     961                    pTimer->u64Expire = cTicksToNext + tmTimerSetRelativeNowWorker(pVM, enmClock, pu64Now);
     962                    Log2(("TMTimerSetRelative: %p:{.enmState=%s, .pszDesc='%s', .u64Expire=%'RU64} cRetries=%d [ACTIVE]\n",
     963                          pTimer, tmTimerState(enmState), R3STRING(pTimer->pszDesc), pTimer->u64Expire, cRetries));
     964                    TM_SET_STATE(pTimer, TMTIMERSTATE_PENDING_RESCHEDULE);
     965                    tmSchedule(pTimer);
     966                    rc = VINF_SUCCESS;
     967                    break;
     968                }
     969                rc = VERR_TRY_AGAIN;
     970                break;
     971
     972            case TMTIMERSTATE_PENDING_RESCHEDULE:
     973            case TMTIMERSTATE_PENDING_STOP:
     974                if (tmTimerTry(pTimer, TMTIMERSTATE_PENDING_RESCHEDULE_SET_EXPIRE, enmState))
     975                {
     976                    pTimer->u64Expire = cTicksToNext + tmTimerSetRelativeNowWorker(pVM, enmClock, pu64Now);
     977                    Log2(("TMTimerSetRelative: %p:{.enmState=%s, .pszDesc='%s', .u64Expire=%'RU64} cRetries=%d [PEND_RESCH/STOP]\n",
     978                          pTimer, tmTimerState(enmState), R3STRING(pTimer->pszDesc), pTimer->u64Expire, cRetries));
     979                    TM_SET_STATE(pTimer, TMTIMERSTATE_PENDING_RESCHEDULE);
     980                    tmSchedule(pTimer);
     981                    rc = VINF_SUCCESS;
     982                    break;
     983                }
     984                rc = VERR_TRY_AGAIN;
     985                break;
     986
     987
     988            case TMTIMERSTATE_EXPIRED_GET_UNLINK:
     989            case TMTIMERSTATE_PENDING_SCHEDULE_SET_EXPIRE:
     990            case TMTIMERSTATE_PENDING_RESCHEDULE_SET_EXPIRE:
     991#ifdef IN_RING3
     992                if (!RTThreadYield())
     993                    RTThreadSleep(1);
     994#else
     995/** @todo call host context and yield after a couple of iterations */
     996#endif
     997                rc = VERR_TRY_AGAIN;
     998                break;
     999
     1000            /*
     1001             * Invalid states.
     1002             */
     1003            case TMTIMERSTATE_DESTROY:
     1004            case TMTIMERSTATE_FREE:
     1005                AssertMsgFailed(("Invalid timer state %d (%s)\n", enmState, R3STRING(pTimer->pszDesc)));
     1006                rc = VERR_TM_INVALID_STATE;
     1007                break;
     1008
     1009            default:
     1010                AssertMsgFailed(("Unknown timer state %d (%s)\n", enmState, R3STRING(pTimer->pszDesc)));
     1011                rc = VERR_TM_UNKNOWN_STATE;
     1012                break;
     1013        }
     1014
     1015        /* switch + loop is tedious to break out of. */
     1016        if (rc == VINF_SUCCESS)
     1017            break;
     1018
     1019        if (rc != VERR_TRY_AGAIN)
     1020        {
     1021            tmTimerSetRelativeNowWorker(pVM, enmClock, pu64Now);
     1022            break;
     1023        }
     1024        if (cRetries > 0)
     1025        {
     1026            AssertMsgFailed(("Failed waiting for stable state. state=%d (%s)\n", pTimer->enmState, R3STRING(pTimer->pszDesc)));
     1027            rc = VERR_INTERNAL_ERROR;
     1028            tmTimerSetRelativeNowWorker(pVM, enmClock, pu64Now);
     1029            break;
     1030        }
     1031    } /* for (;;) */
     1032
     1033    /*
     1034     * Clean up and return.
     1035     */
     1036    if (fOwnLock)
     1037    {
     1038        if (enmClock == TMCLOCK_VIRTUAL_SYNC)
     1039            tmVirtualSyncUnlock(pVM);
     1040        else
     1041            tmUnlock(pVM);
     1042    }
     1043
     1044    STAM_PROFILE_STOP(&pTimer->CTX_SUFF(pVM)->tm.s.CTX_SUFF_Z(StatTimerSetRelative), a);
     1045    return rc;
     1046}
     1047
     1048
     1049/**
    8541050 * Arm a timer with a (new) expire time relative to current time.
    8551051 *
     
    8661062    {
    8671063        case TMCLOCK_VIRTUAL:
    868             return TMTimerSet(pTimer, cMilliesToNext * (uint64_t)TMCLOCK_FREQ_VIRTUAL / 1000 + TMVirtualGet(pVM));
     1064            AssertCompile(TMCLOCK_FREQ_VIRTUAL == 1000000000);
     1065            return TMTimerSetRelative(pTimer, cMilliesToNext * UINT64_C(1000000), NULL);
     1066
    8691067        case TMCLOCK_VIRTUAL_SYNC:
    870             return TMTimerSet(pTimer, cMilliesToNext * (uint64_t)TMCLOCK_FREQ_VIRTUAL / 1000 + TMVirtualSyncGet(pVM));
     1068            AssertCompile(TMCLOCK_FREQ_VIRTUAL == 1000000000);
     1069            return TMTimerSetRelative(pTimer, cMilliesToNext * UINT64_C(1000000), NULL);
     1070
    8711071        case TMCLOCK_REAL:
    8721072            AssertCompile(TMCLOCK_FREQ_REAL == 1000);
    873             return TMTimerSet(pTimer, cMilliesToNext + TMRealGet(pVM));
    874         case TMCLOCK_TSC:
    875             return TMTimerSet(pTimer, cMilliesToNext * pVM->tm.s.cTSCTicksPerSecond / 1000 + TMCpuTickGet(pVCpu));
     1073            return TMTimerSetRelative(pTimer, cMilliesToNext, NULL);
    8761074
    8771075        default:
     
    8981096        case TMCLOCK_VIRTUAL:
    8991097            AssertCompile(TMCLOCK_FREQ_VIRTUAL == 1000000000);
    900             return TMTimerSet(pTimer, cMicrosToNext * 1000 + TMVirtualGet(pVM));
     1098            return TMTimerSetRelative(pTimer, cMicrosToNext * 1000, NULL);
    9011099
    9021100        case TMCLOCK_VIRTUAL_SYNC:
    9031101            AssertCompile(TMCLOCK_FREQ_VIRTUAL == 1000000000);
    904             return TMTimerSet(pTimer, cMicrosToNext * 1000 + TMVirtualSyncGet(pVM));
     1102            return TMTimerSetRelative(pTimer, cMicrosToNext * 1000, NULL);
    9051103
    9061104        case TMCLOCK_REAL:
    9071105            AssertCompile(TMCLOCK_FREQ_REAL == 1000);
    908             return TMTimerSet(pTimer, cMicrosToNext / 1000 + TMRealGet(pVM));
    909 
    910         case TMCLOCK_TSC:
    911             return TMTimerSet(pTimer, TMTimerFromMicro(pTimer, cMicrosToNext) + TMCpuTickGet(pVCpu));
     1106            return TMTimerSetRelative(pTimer, cMicrosToNext / 1000, NULL);
    9121107
    9131108        default:
     
    9341129        case TMCLOCK_VIRTUAL:
    9351130            AssertCompile(TMCLOCK_FREQ_VIRTUAL == 1000000000);
    936             return TMTimerSet(pTimer, cNanosToNext + TMVirtualGet(pVM));
     1131            return TMTimerSetRelative(pTimer, cNanosToNext, NULL);
    9371132
    9381133        case TMCLOCK_VIRTUAL_SYNC:
    9391134            AssertCompile(TMCLOCK_FREQ_VIRTUAL == 1000000000);
    940             return TMTimerSet(pTimer, cNanosToNext + TMVirtualSyncGet(pVM));
     1135            return TMTimerSetRelative(pTimer, cNanosToNext, NULL);
    9411136
    9421137        case TMCLOCK_REAL:
    9431138            AssertCompile(TMCLOCK_FREQ_REAL == 1000);
    944             return TMTimerSet(pTimer, cNanosToNext / 1000000 + TMRealGet(pVM));
    945 
    946         case TMCLOCK_TSC:
    947             return TMTimerSet(pTimer, TMTimerFromNano(pTimer, cNanosToNext) + TMCpuTickGet(pVCpu));
     1139            return TMTimerSetRelative(pTimer, cNanosToNext / 1000000, NULL);
    9481140
    9491141        default:
     
    9631155VMMDECL(int) TMTimerStop(PTMTIMER pTimer)
    9641156{
    965     STAM_PROFILE_START(&pTimer->CTX_SUFF(pVM)->tm.s.CTXALLSUFF(StatTimerStop), a);
     1157    STAM_PROFILE_START(&pTimer->CTX_SUFF(pVM)->tm.s.CTX_SUFF_Z(StatTimerStop), a);
    9661158    TMTIMER_ASSERT_CRITSECT(pTimer);
    9671159
     
    10671259            u64 = TMRealGet(pVM);
    10681260            break;
    1069         case TMCLOCK_TSC:
    1070         {
    1071             PVMCPU pVCpu = &pVM->aCpus[0];  /* just take the first VCPU */
    1072             u64 = TMCpuTickGet(pVCpu);
    1073             break;
    1074         }
    10751261        default:
    10761262            AssertMsgFailed(("Invalid enmClock=%d\n", pTimer->enmClock));
     
    10991285        case TMCLOCK_REAL:
    11001286            return TMCLOCK_FREQ_REAL;
    1101 
    1102         case TMCLOCK_TSC:
    1103             return TMCpuTicksPerSecond(pTimer->CTX_SUFF(pVM));
    11041287
    11051288        default:
     
    11681351            return u64Ticks * 1000000;
    11691352
    1170         case TMCLOCK_TSC:
    1171             AssertReleaseMsgFailed(("TMCLOCK_TSC conversions are not implemented\n"));
    1172             return 0;
    1173 
    11741353        default:
    11751354            AssertMsgFailed(("Invalid enmClock=%d\n", pTimer->enmClock));
     
    12011380            return u64Ticks * 1000;
    12021381
    1203         case TMCLOCK_TSC:
    1204             AssertReleaseMsgFailed(("TMCLOCK_TSC conversions are not implemented\n"));
    1205             return 0;
    1206 
    12071382        default:
    12081383            AssertMsgFailed(("Invalid enmClock=%d\n", pTimer->enmClock));
     
    12341409            return u64Ticks;
    12351410
    1236         case TMCLOCK_TSC:
    1237             AssertReleaseMsgFailed(("TMCLOCK_TSC conversions are not implemented\n"));
    1238             return 0;
    1239 
    12401411        default:
    12411412            AssertMsgFailed(("Invalid enmClock=%d\n", pTimer->enmClock));
     
    12661437            return u64NanoTS / 1000000;
    12671438
    1268         case TMCLOCK_TSC:
    1269             AssertReleaseMsgFailed(("TMCLOCK_TSC conversions are not implemented\n"));
    1270             return 0;
    1271 
    12721439        default:
    12731440            AssertMsgFailed(("Invalid enmClock=%d\n", pTimer->enmClock));
     
    12981465            return u64MicroTS / 1000;
    12991466
    1300         case TMCLOCK_TSC:
    1301             AssertReleaseMsgFailed(("TMCLOCK_TSC conversions are not implemented\n"));
    1302             return 0;
    1303 
    13041467        default:
    13051468            AssertMsgFailed(("Invalid enmClock=%d\n", pTimer->enmClock));
     
    13291492            AssertCompile(TMCLOCK_FREQ_REAL == 1000);
    13301493            return u64MilliTS;
    1331 
    1332         case TMCLOCK_TSC:
    1333             AssertReleaseMsgFailed(("TMCLOCK_TSC conversions are not implemented\n"));
    1334             return 0;
    13351494
    13361495        default:
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