VirtualBox

儲存庫 vbox 的更動 89762


忽略:
時間撮記:
2021-6-17 上午09:39:11 (4 年 以前)
作者:
vboxsync
svn:sync-xref-src-repo-rev:
145213
訊息:

Runtime/r3/win/timer-win.cpp: Implement RTTimerCreateEx, RTTimerStart and RTTimerStop as well as removing code paths unused for a very long time

位置:
trunk/src/VBox/Runtime
檔案:
修改 3 筆資料

圖例:

未更動
新增
刪除
  • trunk/src/VBox/Runtime/Makefile.kmk

    r88215 r89762  
    934934        generic/RTSemMutexRequest-generic.cpp \
    935935        generic/RTSemMutexRequestDebug-generic.cpp \
     936        generic/RTTimerCreate-generic.cpp \
    936937        generic/RTThreadSetAffinityToCpu-generic.cpp \
    937938        generic/mppresent-generic-online.cpp \
  • trunk/src/VBox/Runtime/r3/win/timer-win.cpp

    r83739 r89762  
    55
    66/*
    7  * Copyright (C) 2006-2020 Oracle Corporation
     7 * Copyright (C) 2006-2021 Oracle Corporation
    88 *
    99 * This file is part of VirtualBox Open Source Edition (OSE), as
     
    2626
    2727
    28 /* Which code to use is determined here...
    29  *
    30  * The default is to use wait on NT timers directly with no APC since this
    31  * is supposed to give the shortest kernel code paths.
    32  *
    33  * The USE_APC variation will do as above except that an APC routine is
    34  * handling the callback action.
    35  *
    36  * The USE_WINMM version will use the NT timer wrappers in WinMM which may
    37  * result in some 0.1% better correctness in number of delivered ticks. However,
    38  * this codepath have more overhead (it uses APC among other things), and I'm not
    39  * quite sure if it's actually any more correct.
    40  *
    41  * The USE_CATCH_UP will play catch up when the timer lags behind. However this
    42  * requires a monotonous time source.
    43  *
    44  * The default mode which we are using is using relative periods of time and thus
    45  * will never suffer from errors in the time source. Neither will it try catch up
    46  * missed ticks. This suits our current purposes best I'd say.
    47  */
    48 #undef USE_APC
    49 #undef USE_WINMM
    50 #undef USE_CATCH_UP
    51 
    52 
    5328/*********************************************************************************************************************************
    5429*   Header Files                                                                                                                 *
     
    8964     * This is RTTIMER_MAGIC, but changes to something else before the timer
    9065     * is destroyed to indicate clearly that thread should exit. */
    91     volatile uint32_t       u32Magic;
     66    uint32_t volatile       u32Magic;
     67    /** Flag indicating the timer is suspended. */
     68    bool    volatile        fSuspended;
     69    /** Flag indicating that the timer has been destroyed. */
     70    bool    volatile        fDestroyed;
    9271    /** User argument. */
    9372    void                   *pvUser;
     
    9675    /** The current tick. */
    9776    uint64_t                iTick;
    98     /** The interval. */
    99     unsigned                uMilliesInterval;
    100 #ifdef USE_WINMM
    101     /** Win32 timer id. */
    102     UINT                    TimerId;
    103 #else
     77    /** The timer interval. 0 if one-shot. */
     78    uint64_t                u64NanoInterval;
     79    /** The first shot interval. 0 if ASAP. */
     80    uint64_t volatile       u64NanoFirst;
    10481    /** Time handle. */
    10582    HANDLE                  hTimer;
    106 # ifdef USE_APC
    107     /** Handle to wait on. */
    108     HANDLE                  hevWait;
    109 # endif
    11083    /** USE_CATCH_UP: ns time of the next tick.
    11184     * !USE_CATCH_UP: -uMilliesInterval * 10000 */
     
    11386    /** The thread handle of the timer thread. */
    11487    RTTHREAD                Thread;
     88    /** Event semaphore on which the thread is blocked. */
     89    RTSEMEVENT              Event;
    11590    /** The error/status of the timer.
    11691     * Initially -1, set to 0 when the timer have been successfully started, and
    11792     * to errno on failure in starting the timer. */
    11893    volatile int            iError;
    119 #endif
    12094} RTTIMER;
    12195
    12296
    123 
    124 #ifdef USE_WINMM
    125 /**
    126  * Win32 callback wrapper.
    127  */
    128 static void CALLBACK rttimerCallback(UINT uTimerID, UINT uMsg, DWORD_PTR dwUser, DWORD_PTR dw1, DWORD_PTR dw2)
    129 {
    130     PRTTIMER pTimer = (PRTTIMER)(void *)dwUser;
    131     Assert(pTimer->TimerId == uTimerID);
    132     pTimer->pfnTimer(pTimer, pTimer->pvUser, ++pTimer->iTick);
    133     NOREF(uMsg); NOREF(dw1); NOREF(dw2); NOREF(uTimerID);
    134 }
    135 #else /* !USE_WINMM */
    136 
    137 #ifdef USE_APC
    138 /**
    139  * Async callback.
    140  *
    141  * @param   lpArgToCompletionRoutine    Pointer to our timer structure.
    142  */
    143 VOID CALLBACK rttimerAPCProc(LPVOID lpArgToCompletionRoutine, DWORD dwTimerLowValue, DWORD dwTimerHighValue)
    144 {
    145     PRTTIMER pTimer = (PRTTIMER)lpArgToCompletionRoutine;
    146 
    147     /*
    148      * Check if we're begin destroyed.
    149      */
    150     if (pTimer->u32Magic != RTTIMER_MAGIC)
    151         return;
    152 
    153     /*
    154      * Callback the handler.
    155      */
    156     pTimer->pfnTimer(pTimer, pTimer->pvUser, ++pTimer->iTick);
    157 
    158     /*
    159      * Rearm the timer handler.
    160      */
    161 #ifdef USE_CATCH_UP
    162     pTimer->llNext.QuadPart += (int64_t)pTimer->uMilliesInterval * 10000;
    163     LARGE_INTEGER ll;
    164     ll.QuadPart = RTTimeNanoTS() - pTimer->llNext.QuadPart;
    165     if (ll.QuadPart < -500000)
    166         ll.QuadPart = ll.QuadPart / 100;
    167     else
    168         ll.QuadPart = -500000 / 100; /* need to catch up, do a minimum wait of 0.5ms. */
    169 #else
    170     LARGE_INTEGER ll = pTimer->llNext;
    171 #endif
    172     BOOL frc = SetWaitableTimer(pTimer->hTimer, &ll, 0, rttimerAPCProc, pTimer, FALSE);
    173     AssertMsg(frc || pTimer->u32Magic != RTTIMER_MAGIC, ("last error %d\n", GetLastError()));
    174 }
    175 #endif /* USE_APC */
    17697
    17798/**
    17899 * Timer thread.
    179100 */
    180 static DECLCALLBACK(int) rttimerCallback(RTTHREAD Thread, void *pvArg)
     101static DECLCALLBACK(int) rttimerCallback(RTTHREAD hThreadSelf, void *pvArg)
    181102{
    182103    PRTTIMER pTimer = (PRTTIMER)(void *)pvArg;
     
    186107     * Bounce our priority up quite a bit.
    187108     */
    188     if (    !SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL)
    189         /*&&  !SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_HIGHEST)*/)
     109    if (!SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL))
    190110    {
    191111        int rc = GetLastError();
    192112        AssertMsgFailed(("Failed to set priority class lasterror %d.\n", rc));
    193113        pTimer->iError = RTErrConvertFromWin32(rc);
     114        RTThreadUserSignal(hThreadSelf);
    194115        return rc;
    195116    }
    196117
    197118    /*
    198      * Start the waitable timer.
    199      */
    200 
    201 #ifdef USE_CATCH_UP
    202     const int64_t NSInterval = (int64_t)pTimer->uMilliesInterval * 1000000;
    203     pTimer->llNext.QuadPart = RTTimeNanoTS() + NSInterval;
    204 #else
    205     pTimer->llNext.QuadPart = -(int64_t)pTimer->uMilliesInterval * 10000;
    206 #endif
    207     LARGE_INTEGER ll;
    208     ll.QuadPart = -(int64_t)pTimer->uMilliesInterval * 10000;
    209 #ifdef USE_APC
    210     if (!SetWaitableTimer(pTimer->hTimer, &ll, 0, rttimerAPCProc, pTimer, FALSE))
    211 #else
    212     if (!SetWaitableTimer(pTimer->hTimer, &ll, 0, NULL, NULL, FALSE))
    213 #endif
    214     {
    215         int rc = GetLastError();
    216         AssertMsgFailed(("Failed to set timer, lasterr %d.\n", rc));
    217         pTimer->iError = RTErrConvertFromWin32(rc);
    218         RTThreadUserSignal(Thread);
    219         return rc;
    220     }
    221 
    222     /*
    223      * Wait for the semaphore to be posted.
    224      */
    225     RTThreadUserSignal(Thread);
    226     for (;pTimer->u32Magic == RTTIMER_MAGIC;)
    227     {
    228 #ifdef USE_APC
    229         int rc = WaitForSingleObjectEx(pTimer->hevWait, INFINITE, TRUE);
    230         if (rc != WAIT_OBJECT_0 && rc != WAIT_IO_COMPLETION)
    231 #else
    232         int rc = WaitForSingleObjectEx(pTimer->hTimer, INFINITE, FALSE);
    233         if (pTimer->u32Magic != RTTIMER_MAGIC)
    234             break;
    235         if (rc == WAIT_OBJECT_0)
    236         {
    237             /*
    238              * Callback the handler.
    239              */
    240             pTimer->pfnTimer(pTimer, pTimer->pvUser, ++pTimer->iTick);
    241 
    242             /*
    243              * Rearm the timer handler.
    244              */
    245 # ifdef USE_CATCH_UP
    246             pTimer->llNext.QuadPart += NSInterval;
    247             ll.QuadPart = RTTimeNanoTS() - pTimer->llNext.QuadPart;
    248             if (ll.QuadPart < -500000)
    249                 ll.QuadPart = ll.QuadPart / 100;
     119     * The work loop.
     120     */
     121    RTThreadUserSignal(hThreadSelf);
     122
     123    while (     !pTimer->fDestroyed
     124           &&   pTimer->u32Magic == RTTIMER_MAGIC)
     125    {
     126        /*
     127         * Wait for a start or destroy event.
     128         */
     129        if (pTimer->fSuspended)
     130        {
     131            int rc = RTSemEventWait(pTimer->Event, RT_INDEFINITE_WAIT);
     132            if (RT_FAILURE(rc) && rc != VERR_INTERRUPTED)
     133            {
     134                AssertRC(rc);
     135                if (pTimer->fDestroyed)
     136                    continue;
     137                RTThreadSleep(1000); /* Don't cause trouble! */
     138            }
     139            if (    pTimer->fSuspended
     140                ||  pTimer->fDestroyed)
     141                continue;
     142        }
     143
     144        /*
     145         * Start the waitable timer.
     146         */
     147        pTimer->llNext.QuadPart = -(int64_t)pTimer->u64NanoInterval / 100;
     148        LARGE_INTEGER ll;
     149        if (pTimer->u64NanoFirst)
     150        {
     151            GetSystemTimeAsFileTime((LPFILETIME)&ll);
     152            ll.QuadPart += pTimer->u64NanoFirst / 100;
     153            pTimer->u64NanoFirst = 0;
     154        }
     155        else
     156            ll.QuadPart = -(int64_t)pTimer->u64NanoInterval / 100;
     157        if (!SetWaitableTimer(pTimer->hTimer, &ll, 0, NULL, NULL, FALSE))
     158        {
     159            ASMAtomicXchgBool(&pTimer->fSuspended, true);
     160            int rc = GetLastError();
     161            AssertMsgFailed(("Failed to set timer, lasterr %d.\n", rc));
     162            pTimer->iError = RTErrConvertFromWin32(rc);
     163            RTThreadUserSignal(hThreadSelf);
     164            continue; /* back to suspended mode. */
     165        }
     166        pTimer->iError = 0;
     167        RTThreadUserSignal(hThreadSelf);
     168
     169        /*
     170         * Timer Service Loop.
     171         */
     172        do
     173        {
     174            int rc = WaitForSingleObjectEx(pTimer->hTimer, INFINITE, FALSE);
     175            if (pTimer->u32Magic != RTTIMER_MAGIC)
     176                break;
     177            if (rc == WAIT_OBJECT_0)
     178            {
     179                /*
     180                 * Callback the handler.
     181                 */
     182                pTimer->pfnTimer(pTimer, pTimer->pvUser, ++pTimer->iTick);
     183
     184                /*
     185                 * Rearm the timer handler.
     186                 */
     187                ll = pTimer->llNext;
     188                BOOL fRc = SetWaitableTimer(pTimer->hTimer, &ll, 0, NULL, NULL, FALSE);
     189                AssertMsg(fRc || pTimer->u32Magic != RTTIMER_MAGIC, ("last error %d\n", GetLastError())); NOREF(fRc);
     190            }
    250191            else
    251                 ll.QuadPart = -500000 / 100; /* need to catch up, do a minimum wait of 0.5ms. */
    252 # else
    253             ll = pTimer->llNext;
    254 # endif
    255             BOOL fRc = SetWaitableTimer(pTimer->hTimer, &ll, 0, NULL, NULL, FALSE);
    256             AssertMsg(fRc || pTimer->u32Magic != RTTIMER_MAGIC, ("last error %d\n", GetLastError())); NOREF(fRc);
    257         }
    258         else
    259 #endif
    260         {
    261             /*
    262              * We failed during wait, so just signal the destructor and exit.
    263              */
    264             int rc2 = GetLastError();
    265             RTThreadUserSignal(Thread);
    266             AssertMsgFailed(("Wait on hTimer failed, rc=%d lasterr=%d\n", rc, rc2)); NOREF(rc2);
    267             return -1;
     192            {
     193                /*
     194                 * We failed during wait, so just signal the destructor and exit.
     195                 */
     196                int rc2 = GetLastError();
     197                RTThreadUserSignal(hThreadSelf);
     198                AssertMsgFailed(("Wait on hTimer failed, rc=%d lasterr=%d\n", rc, rc2)); NOREF(rc2);
     199                return -1;
     200            }
     201        } while (RT_LIKELY(   !pTimer->fSuspended
     202                           && !pTimer->fDestroyed
     203                           &&  pTimer->u32Magic == RTTIMER_MAGIC));
     204
     205        /*
     206         * Disable the timer.
     207         */
     208        int rc = CancelWaitableTimer (pTimer->hTimer);
     209        AssertMsg(rc, ("CancelWaitableTimer lasterr=%d\n", GetLastError()));
     210
     211        /*
     212         * ACK any pending suspend request.
     213         */
     214        if (!pTimer->fDestroyed)
     215        {
     216            pTimer->iError = 0;
     217            RTThreadUserSignal(hThreadSelf);
    268218        }
    269219    }
     
    272222     * Exit.
    273223     */
    274     RTThreadUserSignal(Thread);
    275     return 0;
    276 }
    277 #endif /* !USE_WINMM */
    278 
    279 
    280 RTDECL(int) RTTimerCreate(PRTTIMER *ppTimer, unsigned uMilliesInterval, PFNRTTIMER pfnTimer, void *pvUser)
    281 {
    282 #ifndef USE_WINMM
     224    pTimer->iError = 0;
     225    RTThreadUserSignal(hThreadSelf);
     226    return VINF_SUCCESS;
     227}
     228
     229
     230RTDECL(int) RTTimerCreateEx(PRTTIMER *ppTimer, uint64_t u64NanoInterval, uint32_t fFlags, PFNRTTIMER pfnTimer, void *pvUser)
     231{
     232    /*
     233     * We don't support the fancy MP features.
     234     */
     235    if (fFlags & RTTIMER_FLAGS_CPU_SPECIFIC)
     236        return VERR_NOT_SUPPORTED;
     237
    283238    /*
    284239     * On windows we'll have to set the timer resolution before
     
    288243    ULONG ulMin = UINT32_MAX;
    289244    ULONG ulCur = UINT32_MAX;
     245    ULONG ulReq = (ULONG)(u64NanoInterval / 100);
    290246    NtQueryTimerResolution(&ulMax, &ulMin, &ulCur);
    291247    Log(("NtQueryTimerResolution -> ulMax=%lu00ns ulMin=%lu00ns ulCur=%lu00ns\n", ulMax, ulMin, ulCur));
    292     if (ulCur > ulMin && ulCur > 10000 /* = 1ms */)
    293     {
    294         if (NtSetTimerResolution(10000, TRUE, &ulCur) >= 0)
     248    if (ulCur > ulMin && ulCur > ulReq)
     249    {
     250        ulReq = RT_MIN(ulMin, ulReq);
     251        if (NtSetTimerResolution(ulReq, TRUE, &ulCur) >= 0)
     252            Log(("Changed timer resolution to %lu*100ns.\n", ulReq));
     253        else if (NtSetTimerResolution(10000, TRUE, &ulCur) >= 0)
    295254            Log(("Changed timer resolution to 1ms.\n"));
    296255        else if (NtSetTimerResolution(20000, TRUE, &ulCur) >= 0)
     
    306265        }
    307266    }
    308 #endif /* !USE_WINN */
    309267
    310268    /*
     
    315273    if (pTimer)
    316274    {
    317         pTimer->u32Magic    = RTTIMER_MAGIC;
    318         pTimer->pvUser      = pvUser;
    319         pTimer->pfnTimer    = pfnTimer;
    320         pTimer->iTick       = 0;
    321         pTimer->uMilliesInterval = uMilliesInterval;
    322 #ifdef USE_WINMM
    323         /* sync kill doesn't work. */
    324         pTimer->TimerId     = timeSetEvent(uMilliesInterval, 0, rttimerCallback, (DWORD_PTR)pTimer, TIME_PERIODIC | TIME_CALLBACK_FUNCTION);
    325         if (pTimer->TimerId)
    326         {
    327             ULONG ulMax = UINT32_MAX;
    328             ULONG ulMin = UINT32_MAX;
    329             ULONG ulCur = UINT32_MAX;
    330             NtQueryTimerResolution(&ulMax, &ulMin, &ulCur);
    331             Log(("NtQueryTimerResolution -> ulMax=%lu00ns ulMin=%lu00ns ulCur=%lu00ns\n", ulMax, ulMin, ulCur));
    332 
    333             *ppTimer = pTimer;
    334             return VINF_SUCCESS;
    335         }
    336         rc = VERR_INVALID_PARAMETER;
    337 
    338 #else /* !USE_WINMM */
    339 
    340         /*
    341          * Create Win32 event semaphore.
    342          */
    343         pTimer->iError = 0;
    344         pTimer->hTimer = CreateWaitableTimer(NULL, TRUE, NULL);
    345         if (pTimer->hTimer)
    346         {
    347 #ifdef USE_APC
     275        pTimer->u32Magic        = RTTIMER_MAGIC;
     276        pTimer->fSuspended      = true;
     277        pTimer->fDestroyed      = false;
     278        pTimer->Thread          = NIL_RTTHREAD;
     279        pTimer->pfnTimer        = pfnTimer;
     280        pTimer->pvUser          = pvUser;
     281        pTimer->u64NanoInterval = u64NanoInterval;
     282
     283        rc = RTSemEventCreate(&pTimer->Event);
     284        AssertRC(rc);
     285        if (RT_SUCCESS(rc))
     286        {
    348287            /*
    349              * Create wait semaphore.
     288             * Create Win32 event semaphore.
    350289             */
    351             pTimer->hevWait = CreateEvent(NULL, FALSE, FALSE, NULL);
    352             if (pTimer->hevWait)
    353 #endif
     290            pTimer->iError = 0;
     291            pTimer->hTimer = CreateWaitableTimer(NULL, TRUE, NULL);
     292            if (pTimer->hTimer)
    354293            {
    355294                /*
     
    373312                        }
    374313                    }
    375                     ASMAtomicXchgU32(&pTimer->u32Magic, RTTIMER_MAGIC + 1);
    376                     RTThreadWait(pTimer->Thread, 250, NULL);
     314
     315                    /* bail out */
     316                    ASMAtomicXchgBool(&pTimer->fDestroyed, true);
     317                    ASMAtomicXchgU32(&pTimer->u32Magic, ~RTTIMER_MAGIC);
     318                    RTThreadWait(pTimer->Thread, 45*1000, NULL);
    377319                    CancelWaitableTimer(pTimer->hTimer);
    378320                }
    379 #ifdef USE_APC
    380                 CloseHandle(pTimer->hevWait);
    381 #endif
     321                CloseHandle(pTimer->hTimer);
    382322            }
    383             CloseHandle(pTimer->hTimer);
    384         }
    385 #endif /* !USE_WINMM */
    386 
    387         AssertMsgFailed(("Failed to create timer uMilliesInterval=%d. rc=%d\n", uMilliesInterval, rc));
     323            RTSemEventDestroy(pTimer->Event);
     324            pTimer->Event = NIL_RTSEMEVENT;
     325        }
     326
    388327        RTMemFree(pTimer);
    389328    }
     
    400339        return VINF_SUCCESS;
    401340
    402     /*
    403      * Validate handle first.
    404      */
    405     int rc;
    406     if (    VALID_PTR(pTimer)
    407         &&  pTimer->u32Magic == RTTIMER_MAGIC)
    408     {
    409 #ifdef USE_WINMM
    410         /*
    411          * Kill the timer and exit.
    412          */
    413         rc = timeKillEvent(pTimer->TimerId);
    414         AssertMsg(rc == TIMERR_NOERROR, ("timeKillEvent -> %d\n", rc));
    415         ASMAtomicXchgU32(&pTimer->u32Magic, RTTIMER_MAGIC + 1);
    416         RTThreadSleep(1);
    417 
    418 #else /* !USE_WINMM */
    419 
    420         /*
    421          * Signal that we want the thread to exit.
    422          */
    423         ASMAtomicXchgU32(&pTimer->u32Magic, RTTIMER_MAGIC + 1);
    424 #ifdef USE_APC
    425         SetEvent(pTimer->hevWait);
    426         CloseHandle(pTimer->hevWait);
    427         rc = CancelWaitableTimer(pTimer->hTimer);
    428         AssertMsg(rc, ("CancelWaitableTimer lasterr=%d\n", GetLastError()));
    429 #else
     341    int rc = VINF_SUCCESS;
     342    AssertPtrReturn(pTimer, VERR_INVALID_HANDLE);
     343    AssertReturn(pTimer->u32Magic == RTTIMER_MAGIC, VERR_INVALID_MAGIC);
     344    AssertReturn(pTimer->Thread != RTThreadSelf(), VERR_INTERNAL_ERROR);
     345
     346    /*
     347     * Signal that we want the thread to exit.
     348     */
     349    ASMAtomicWriteBool(&pTimer->fDestroyed, true);
     350    ASMAtomicWriteU32(&pTimer->u32Magic, ~RTTIMER_MAGIC);
     351
     352    /*
     353     * Suspend the timer if it's running.
     354     */
     355    if (!pTimer->fSuspended)
     356    {
    430357        LARGE_INTEGER ll = {0};
    431358        ll.LowPart = 100;
    432359        rc = SetWaitableTimer(pTimer->hTimer, &ll, 0, NULL, NULL, FALSE);
    433360        AssertMsg(rc, ("CancelWaitableTimer lasterr=%d\n", GetLastError()));
    434 #endif
    435 
    436         /*
    437          * Wait for the thread to exit.
    438          * And if it don't wanna exit, we'll get kill it.
    439          */
    440         rc = RTThreadWait(pTimer->Thread, 1000, NULL);
    441         if (RT_FAILURE(rc))
    442             TerminateThread((HANDLE)RTThreadGetNative(pTimer->Thread), UINT32_MAX);
    443 
    444         /*
    445          * Free resource.
    446          */
    447         rc = CloseHandle(pTimer->hTimer);
    448         AssertMsg(rc, ("CloseHandle lasterr=%d\n", GetLastError()));
    449 
    450 #endif /* !USE_WINMM */
    451         RTMemFree(pTimer);
    452         return rc;
    453     }
    454 
    455     rc = VERR_INVALID_HANDLE;
    456     AssertMsgFailed(("Failed to destroy timer %p. rc=%d\n", pTimer, rc));
     361    }
     362
     363    rc = RTSemEventSignal(pTimer->Event);
     364    AssertRC(rc);
     365
     366    /*
     367     * Wait for the thread to exit.
     368     * And if it don't wanna exit, we'll get kill it.
     369     */
     370    rc = RTThreadWait(pTimer->Thread, 30 * 1000, NULL);
     371    if (RT_FAILURE(rc))
     372        TerminateThread((HANDLE)RTThreadGetNative(pTimer->Thread), UINT32_MAX);
     373
     374    /*
     375     * Free resource.
     376     */
     377    rc = CloseHandle(pTimer->hTimer);
     378    AssertMsg(rc, ("CloseHandle lasterr=%d\n", GetLastError()));
     379
     380    RTSemEventDestroy(pTimer->Event);
     381    pTimer->Event = NIL_RTSEMEVENT;
     382
     383    RTMemFree(pTimer);
    457384    return rc;
    458385}
    459386
     387
     388RTDECL(int) RTTimerStart(PRTTIMER pTimer, uint64_t u64First)
     389{
     390    /*
     391     * Validate input.
     392     */
     393    AssertPtrReturn(pTimer, VERR_INVALID_POINTER);
     394    AssertReturn(pTimer->u32Magic == RTTIMER_MAGIC, VERR_INVALID_MAGIC);
     395    AssertReturn(pTimer->Thread != RTThreadSelf(), VERR_INTERNAL_ERROR);
     396
     397    RTThreadUserReset(pTimer->Thread);
     398
     399    /*
     400     * Already running?
     401     */
     402    if (!ASMAtomicXchgBool(&pTimer->fSuspended, false))
     403        return VERR_TIMER_ACTIVE;
     404    LogFlow(("RTTimerStart: pTimer=%p u64First=%llu u64NanoInterval=%llu\n", pTimer, u64First, pTimer->u64NanoInterval));
     405
     406    /*
     407     * Tell the thread to start servicing the timer.
     408     * Wait for it to ACK the request to avoid reset races.
     409     */
     410    ASMAtomicUoWriteU64(&pTimer->u64NanoFirst, u64First);
     411    ASMAtomicUoWriteU64(&pTimer->iTick, 0);
     412    int rc = RTSemEventSignal(pTimer->Event);
     413    if (RT_SUCCESS(rc))
     414    {
     415        rc = RTThreadUserWait(pTimer->Thread, 45*1000);
     416        AssertRC(rc);
     417        RTThreadUserReset(pTimer->Thread);
     418    }
     419    else
     420        AssertRC(rc);
     421
     422    if (RT_FAILURE(rc))
     423        ASMAtomicXchgBool(&pTimer->fSuspended, true);
     424    return rc;
     425}
     426
     427
     428RTDECL(int) RTTimerStop(PRTTIMER pTimer)
     429{
     430    /*
     431     * Validate input.
     432     */
     433    AssertPtrReturn(pTimer, VERR_INVALID_POINTER);
     434    AssertReturn(pTimer->u32Magic == RTTIMER_MAGIC, VERR_INVALID_MAGIC);
     435
     436    RTThreadUserReset(pTimer->Thread);
     437
     438    /*
     439     * Already running?
     440     */
     441    if (ASMAtomicXchgBool(&pTimer->fSuspended, true))
     442        return VERR_TIMER_SUSPENDED;
     443    LogFlow(("RTTimerStop: pTimer=%p\n", pTimer));
     444
     445    /*
     446     * Tell the thread to stop servicing the timer.
     447     */
     448    int rc = VINF_SUCCESS;
     449    if (RTThreadSelf() != pTimer->Thread)
     450    {
     451        LARGE_INTEGER ll = {0};
     452        ll.LowPart = 100;
     453        rc = SetWaitableTimer(pTimer->hTimer, &ll, 0, NULL, NULL, FALSE);
     454        AssertMsg(rc, ("SetWaitableTimer lasterr=%d\n", GetLastError()));
     455        rc = RTThreadUserWait(pTimer->Thread, 45*1000);
     456        AssertRC(rc);
     457        RTThreadUserReset(pTimer->Thread);
     458    }
     459
     460    return rc;
     461}
     462
     463
     464RTDECL(int) RTTimerChangeInterval(PRTTIMER pTimer, uint64_t u64NanoInterval)
     465{
     466    AssertPtrReturn(pTimer, VERR_INVALID_POINTER);
     467    AssertReturn(pTimer->u32Magic == RTTIMER_MAGIC, VERR_INVALID_MAGIC);
     468    NOREF(u64NanoInterval);
     469    return VERR_NOT_SUPPORTED;
     470}
  • trunk/src/VBox/Runtime/testcase/tstTimer.cpp

    r82968 r89762  
    5757    gcTicks++;
    5858
     59    if (iTick != gcTicks)
     60        RTPrintf("tstTimer: FAILURE - iTick=%llu expected %u\n", iTick, gcTicks);
     61
    5962    const uint64_t u64Now = RTTimeNanoTS();
    6063    if (gu64Prev)
     
    162165        gu64Prev = 0;
    163166        RT_ZERO(cFrequency);
    164 #ifdef RT_OS_WINDOWS
    165         if (aTests[i].uMicroInterval < 1000)
    166             continue;
    167         rc = RTTimerCreate(&pTimer, aTests[i].uMicroInterval / 1000, TimerCallback, NULL);
    168 #else
    169167        rc = RTTimerCreateEx(&pTimer, aTests[i].uMicroInterval * (uint64_t)1000, 0, TimerCallback, NULL);
    170 #endif
    171168        if (RT_FAILURE(rc))
    172169        {
     
    180177         */
    181178        uTSBegin = RTTimeNanoTS();
    182 #ifndef RT_OS_WINDOWS
    183179        rc = RTTimerStart(pTimer, 0);
    184180        if (RT_FAILURE(rc))
     
    187183            cErrors++;
    188184        }
    189 #endif
    190185
    191186        while (RTTimeNanoTS() - uTSBegin < (uint64_t)aTests[i].uMilliesWait * 1000000)
注意: 瀏覽 TracChangeset 來幫助您使用更動檢視器

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