VirtualBox

Changeset 1807 in vbox for trunk/src/VBox/Runtime


Ignore:
Timestamp:
Mar 29, 2007 5:24:21 PM (18 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
19989
Message:

Adopted the posix timer code to support the three new timer APIs

Location:
trunk/src/VBox/Runtime
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Runtime/Makefile

    r1781 r1807  
    263263        generic/RTFileMove-generic.cpp \
    264264        generic/RTLogWriteDebugger-generic.cpp \
     265        generic/RTTimerCreate-generic.cpp \
    265266        r3/posix/RTTimeNow-posix.cpp \
    266267        r3/posix/alloc-posix.cpp \
     
    295296        generic/RTFileMove-generic.cpp \
    296297        generic/RTLogWriteDebugger-generic.cpp \
     298        generic/RTTimerCreate-generic.cpp \
    297299        os2/RTErrConvertFromOS2.cpp \
    298300        r3/os2/sems-os2.cpp \
     
    314316        generic/sched-generic.cpp \
    315317        r3/os2/time-os2.cpp \
    316         r3/posix/timer-posix.cpp \
     318        generic/timer-generic.cpp \
    317319        r3/posix/RTTimeNow-posix.cpp \
    318320        generic/utf16locale-generic.cpp \
     
    355357        generic/RTFileMove-generic.cpp \
    356358        generic/RTLogWriteDebugger-generic.cpp \
     359        generic/RTTimerCreate-generic.cpp \
    357360        generic/pathhost-generic.cpp \
    358361        generic/sched-generic.cpp \
  • trunk/src/VBox/Runtime/generic/timer-generic.cpp

    r1781 r1807  
    3333#include <iprt/time.h>
    3434#include <iprt/log.h>
     35#include "internal/magics.h"
    3536
    3637
     
    7172    uint64_t volatile       iTick;
    7273} RTTIMER;
    73 /** Magic number for timer handles. (Jared Mason Diamond) */
    74 #define RTTIMER_MAGIC       0x19370910
    7574
    7675
  • trunk/src/VBox/Runtime/r3/posix/timer-posix.cpp

    r1470 r1807  
    3333#include <iprt/string.h>
    3434#include <iprt/err.h>
     35#include "internal/magics.h"
    3536
    3637#include <unistd.h>
     
    5960     * This is RTTIMER_MAGIC, but changes to something else before the timer
    6061     * is destroyed to indicate clearly that thread should exit. */
    61     volatile uint32_t       u32Magic;
    62     /** Win32 timer id. */
     62    uint32_t volatile       u32Magic;
     63    /** Flag indicating the the timer is suspended. */
     64    uint8_t volatile        fSuspended;
     65    /** Flag indicating that the timer has been destroyed. */
     66    uint8_t volatile        fDestroyed;
     67    /** The timer thread. */
    6368    RTTHREAD                Thread;
     69    /** Event semaphore on which the thread is blocked. */
     70    RTSEMEVENT              Event;
    6471    /** User argument. */
    6572    void                   *pvUser;
    6673    /** Callback. */
    6774    PFNRTTIMER              pfnTimer;
    68     /** The timeout values for the timer. */
    69     struct itimerval TimerVal;
     75    /** The timer interval. 0 if one-shot. */
     76    uint64_t                u64NanoInterval;
     77    /** The first shot interval. 0 if ASAP. */
     78    uint64_t volatile       u64NanoFirst;
    7079    /** The error/status of the timer.
    7180     * Initially -1, set to 0 when the timer have been successfully started, and
    7281     * to errno on failure in starting the timer. */
    73     volatile int            iError;
     82    int volatile            iError;
    7483
    7584} RTTIMER;
    76 /** Timer handle magic. */
    77 #define RTTIMER_MAGIC       0x42424242
    7885
    7986
     
    114121
    115122    /*
    116      * Mask most signals except those which might be used during
    117      * termination is by a pthread implementation.
     123     * Mask most signals except those which might be used by the pthread implementation (linux).
    118124     */
    119125    sigset_t SigSet;
     
    136142
    137143    /*
    138      * Start the timer.
    139      *
    140      * For some SunOS (/SysV?) threading compatibility Linux will only
    141      * deliver the SIGALRM to the thread calling setitimer(). Therefore
    142      * we have to call it here.
    143      *
    144      * It turns out this might not always be the case, see SIGALRM killing
    145      * processes on RH 2.4.21.
    146      */
    147     if (setitimer(ITIMER_REAL, &pTimer->TimerVal, NULL))
    148     {
    149         pTimer->iError = RTErrConvertFromErrno(errno);
     144     * The work loop.
     145     */
     146    RTThreadUserSignal(Thread);
     147    while (     !pTimer->fDestroyed
     148           &&   pTimer->u32Magic == RTTIMER_MAGIC)
     149    {
     150        /*
     151         * Wait for a start or destroy event.
     152         */
     153        if (pTimer->fSuspended)
     154        {
     155            int rc = RTSemEventWait(pTimer->Event, RT_INDEFINITE_WAIT);
     156            if (RT_FAILURE(rc) && rc != VERR_INTERRUPTED)
     157            {
     158                AssertRC(rc);
     159                RTThreadSleep(1000); /* Don't cause trouble! */
     160            }
     161            if (    pTimer->fSuspended
     162                ||  pTimer->fDestroyed)
     163                continue;
     164        }
     165
     166        /*
     167         * Start the timer.
     168         *
     169         * For some SunOS (/SysV?) threading compatibility Linux will only
     170         * deliver the SIGALRM to the thread calling setitimer(). Therefore
     171         * we have to call it here.
     172         *
     173         * It turns out this might not always be the case, see SIGALRM killing
     174         * processes on RH 2.4.21.
     175         */
     176        struct itimerval TimerVal;
     177        if (pTimer->u64NanoFirst)
     178        {
     179            uint64_t u64 = RT_MAX(1000, pTimer->u64NanoFirst);
     180            TimerVal.it_value.tv_sec     = u64 / 1000000000;
     181            TimerVal.it_value.tv_usec    = (u64 % 1000000000) / 1000;
     182        }
     183        else
     184        {
     185            TimerVal.it_value.tv_sec     = 0;
     186            TimerVal.it_value.tv_usec    = 10;
     187        }
     188        if (pTimer->u64NanoInterval)
     189        {
     190            uint64_t u64 = RT_MAX(1000, pTimer->u64NanoInterval);
     191            TimerVal.it_interval.tv_sec  = u64 / 1000000000;
     192            TimerVal.it_interval.tv_usec = (u64 % 1000000000) / 1000;
     193        }
     194        else
     195        {
     196            TimerVal.it_interval.tv_sec  = 0;
     197            TimerVal.it_interval.tv_usec = 0;
     198        }
     199
     200        if (setitimer(ITIMER_REAL, &TimerVal, NULL))
     201        {
     202            ASMAtomicXchgU8(&pTimer->fSuspended, true);
     203            pTimer->iError = RTErrConvertFromErrno(errno);
     204            RTThreadUserSignal(Thread);
     205            continue; /* back to suspended mode. */
     206        }
     207        pTimer->iError = 0;
    150208        RTThreadUserSignal(Thread);
    151         return errno;
    152     }
    153 
    154     /*
    155      * Signal wait loop-forever.
    156      */
    157     sigemptyset(&SigSet);
    158     sigaddset(&SigSet, SIGALRM);
     209
     210        /*
     211         * Timer Service Loop.
     212         */
     213        sigemptyset(&SigSet);
     214        sigaddset(&SigSet, SIGALRM);
     215        do
     216        {
     217            siginfo_t SigInfo = {0};
     218#ifdef __DARWIN__
     219            if (RT_LIKELY(sigwait(&SigSet, &SigInfo.si_signo) >= 0))
     220            {
     221#else
     222            if (RT_LIKELY(sigwaitinfo(&SigSet, &SigInfo) >= 0))
     223            {
     224                if (RT_LIKELY(SigInfo.si_signo == SIGALRM))
     225#endif
     226                {
     227                    if (RT_UNLIKELY(    pTimer->fSuspended
     228                                    ||  pTimer->fDestroyed
     229                                    ||  pTimer->u32Magic != RTTIMER_MAGIC))
     230                        break;
     231
     232                    pTimer->pfnTimer(pTimer, pTimer->pvUser);
     233
     234                    /* auto suspend one-shot timers. */
     235                    if (RT_UNLIKELY(!pTimer->u64NanoInterval))
     236                    {
     237                        ASMAtomicXchgU8(&pTimer->fSuspended, true);
     238                        break;
     239                    }
     240                }
     241            }
     242            else if (errno != EINTR)
     243                AssertMsgFailed(("sigwaitinfo -> errno=%d\n", errno));
     244        } while (RT_LIKELY(   !pTimer->fSuspended
     245                           && !pTimer->fDestroyed
     246                           &&  pTimer->u32Magic == RTTIMER_MAGIC));
     247
     248        /*
     249         * Disable the timer.
     250         */
     251        struct itimerval TimerVal2 = {{0,0}, {0,0}};
     252        if (setitimer(ITIMER_REAL, &TimerVal2, NULL))
     253            AssertMsgFailed(("setitimer(ITIMER_REAL,&{0}, NULL) failed, errno=%d\n", errno));
     254
     255        /*
     256         * ACK any pending suspend request.
     257         */
     258        if (!pTimer->fDestroyed)
     259        {
     260            pTimer->iError = 0;
     261            RTThreadUserSignal(Thread);
     262        }
     263    }
     264
     265    /*
     266     * Exit.
     267     */
     268    pTimer->iError = 0;
    159269    RTThreadUserSignal(Thread);
    160     while (pTimer->u32Magic == RTTIMER_MAGIC)
    161     {
    162         siginfo_t SigInfo = {0};
    163 #ifdef __DARWIN__
    164         if (sigwait(&SigSet, &SigInfo.si_signo) >= 0)
    165         {
    166 #else
    167         if (sigwaitinfo(&SigSet, &SigInfo) >= 0)
    168         {
    169             if (    SigInfo.si_signo == SIGALRM
    170                 &&  pTimer->u32Magic == RTTIMER_MAGIC)
    171 #endif
    172                 pTimer->pfnTimer(pTimer, pTimer->pvUser);
    173         }
    174         else if (errno != EINTR)
    175             AssertMsgFailed(("sigwaitinfo -> errno=%d\n", errno));
    176     }
    177 
    178     /*
    179      * Disable the timer.
    180      */
    181     struct itimerval TimerVal = {{0,0}, {0,0}};
    182     if (setitimer(ITIMER_REAL, &TimerVal, NULL))
    183         AssertMsgFailed(("setitimer(ITIMER_REAL,&{0}, NULL) failed, errno=%d\n", errno));
    184 
    185     /*
    186      * Exit.
    187      */
    188     RTThreadUserSignal(Thread);
     270
    189271    return VINF_SUCCESS;
    190272}
    191273
    192274
    193 /**
    194  * Create a recurring timer.
    195  *
    196  * @returns iprt status code.
    197  * @param   ppTimer             Where to store the timer handle.
    198  * @param   uMilliesInterval    Milliseconds between the timer ticks.
    199  *                              This is rounded up to the system granularity.
    200  * @param   pfnCallback         Callback function which shall be scheduled for execution
    201  *                              on every timer tick.
    202  * @param   pvUser              User argument for the callback.
    203  */
    204 RTR3DECL(int)     RTTimerCreate(PRTTIMER *ppTimer, unsigned uMilliesInterval, PFNRTTIMER pfnTimer, void *pvUser)
     275RTDECL(int) RTTimerCreateEx(PRTTIMER *ppTimer, uint64_t u64NanoInterval, unsigned fFlags, PFNRTTIMER pfnTimer, void *pvUser)
    205276{
    206277    /*
     
    224295     * Block SIGALRM from calling thread.
    225296     */
    226 #if defined(__FREEBSD__) /* sighold is missing and I don't wish to break anything atm. */
    227297    sigset_t SigSet;
    228298    sigemptyset(&SigSet);
    229299    sigaddset(&SigSet, SIGALRM);
    230300    sigprocmask(SIG_BLOCK, &SigSet, NULL);
    231 #else     
    232     sighold(SIGALRM);
    233 #endif   
     301
     302    /** @todo Move this RTC hack else where... */
    234303    static bool fDoneRTC;
    235304    if (!fDoneRTC)
     
    273342
    274343    /*
    275      * Create new timer.
     344     * Create a new timer.
    276345     */
    277346    int rc;
     
    280349    {
    281350        pTimer->u32Magic    = RTTIMER_MAGIC;
     351        pTimer->fSuspended  = true;
     352        pTimer->fDestroyed  = false;
     353        pTimer->Thread      = NIL_RTTHREAD;
     354        pTimer->Event       = NIL_RTSEMEVENT;
     355        pTimer->pfnTimer    = pfnTimer;
     356        pTimer->pvUser      = pvUser;
     357        pTimer->u64NanoInterval = u64NanoInterval;
    282358        pTimer->iError      = 0;
    283         pTimer->pvUser      = pvUser;
    284         pTimer->pfnTimer    = pfnTimer;
    285         pTimer->TimerVal.it_interval.tv_sec = uMilliesInterval / 1000;
    286         pTimer->TimerVal.it_interval.tv_usec = (uMilliesInterval % 1000) * 1000;
    287         pTimer->TimerVal.it_value = pTimer->TimerVal.it_interval;
    288         rc = RTThreadCreate(&pTimer->Thread, rttimerThread, pTimer, 0, RTTHREADTYPE_TIMER, RTTHREADFLAGS_WAITABLE, "Timer");
     359        rc = RTSemEventCreate(&pTimer->Event);
     360        AssertRC(rc);
    289361        if (RT_SUCCESS(rc))
    290362        {
    291             /*
    292              * Wait for the timer to successfully create the timer
    293              */
    294             /** @todo something is may cause this to take very long. We're waiting 30 seconds now and hope that'll workaround it... */
    295             rc = RTThreadUserWait(pTimer->Thread, 30*1000);
     363            rc = RTThreadCreate(&pTimer->Thread, rttimerThread, pTimer, 0, RTTHREADTYPE_TIMER, RTTHREADFLAGS_WAITABLE, "Timer");
     364            AssertRC(rc);
    296365            if (RT_SUCCESS(rc))
    297366            {
    298                 rc = pTimer->iError;
     367                /*
     368                 * Wait for the timer thread to initialize it self.
     369                 * This might take a little while...
     370                 */
     371                rc = RTThreadUserWait(pTimer->Thread, 45*1000);
     372                AssertRC(rc);
    299373                if (RT_SUCCESS(rc))
    300374                {
    301                     RTThreadYield(); /* Horrible hack to make tstTimer work. Something is really fucked related to scheduling here! (2.6.12) */
    302                     *ppTimer = pTimer;
    303                     return VINF_SUCCESS;
     375                    rc = RTThreadUserReset(pTimer->Thread); AssertRC(rc);
     376                    rc = pTimer->iError;
     377                    AssertRC(rc);
     378                    if (RT_SUCCESS(rc))
     379                    {
     380                        RTThreadYield(); /* <-- Horrible hack to make tstTimer work. (linux 2.6.12) */
     381                        *ppTimer = pTimer;
     382                        return VINF_SUCCESS;
     383                    }
    304384                }
     385
     386                /* bail out */
     387                ASMAtomicXchgU8(&pTimer->fDestroyed, true);
     388                ASMAtomicXchgU32(&pTimer->u32Magic, RTTIMER_MAGIC + 1);
     389                RTThreadWait(pTimer->Thread, 45*1000, NULL);
    305390            }
    306             ASMAtomicXchgU32(&pTimer->u32Magic, RTTIMER_MAGIC + 1);
    307         }
    308 
    309         AssertMsgFailed(("Failed to create timer uMilliesInterval=%d. rc=%Vrc\n", uMilliesInterval, rc));
     391            RTSemEventDestroy(pTimer->Event);
     392            pTimer->Event = NIL_RTSEMEVENT;
     393        }
    310394        RTMemFree(pTimer);
    311395    }
     
    316400
    317401
    318 RTDECL(int) RTTimerCreateEx(PRTTIMER *ppTimer, uint64_t u64NanoInterval, unsigned fFlags, PFNRTTIMER pfnTimer, void *pvUser)
    319 {
    320     /// @todo implement
    321     return VERR_NOT_IMPLEMENTED;
    322 }
    323 
    324 
    325 /**
    326  * Stops and destroys a running timer.
    327  *
    328  * @returns iprt status code.
    329  * @param   pTimer      Timer to stop and destroy.
    330  */
    331402RTR3DECL(int)     RTTimerDestroy(PRTTIMER pTimer)
    332403{
    333404    LogFlow(("RTTimerDestroy: pTimer=%p\n", pTimer));
    334405
     406    /*
     407     * Validate input.
     408     */
    335409    /* NULL is ok. */
    336410    if (!pTimer)
    337411        return VINF_SUCCESS;
    338 
    339     /*
    340      * Validate input.
    341      */
    342412    int rc = VINF_SUCCESS;
    343     if (VALID_PTR(pTimer))
    344     {
    345         /*
    346          * Modify the magic and kick it.
    347          */
    348         if (ASMAtomicXchgU32(&pTimer->u32Magic, RTTIMER_MAGIC + 1) == RTTIMER_MAGIC)
    349         {
     413    AssertPtrReturn(pTimer, VERR_INVALID_POINTER);
     414    AssertReturn(pTimer->u32Magic == RTTIMER_MAGIC, VERR_INVALID_MAGIC);
     415    AssertReturn(pTimer->Thread != RTThreadSelf(), VERR_INTERNAL_ERROR);
     416
     417    /*
     418     * Tell the thread to terminate and wait for it do complete.
     419     */
     420    ASMAtomicXchgU8(&pTimer->fDestroyed, true);
     421    ASMAtomicXchgU32(&pTimer->u32Magic, RTTIMER_MAGIC + 1);
     422    rc = RTSemEventSignal(pTimer->Event);
     423    AssertRC(rc);
     424    if (!pTimer->fSuspended)
     425    {
    350426#ifndef __OS2__
    351             pthread_kill((pthread_t)RTThreadGetNative(pTimer->Thread), SIGALRM);
    352 #endif
    353 
    354             /*
    355              * Wait for the thread to exit.
    356              */
    357             rc = RTThreadWait(pTimer->Thread, 30 * 1000, NULL);
    358             if (    RT_SUCCESS(rc)
    359                 ||  rc == VERR_INVALID_HANDLE /* we don't keep handles around, you gotta wait before it really exits! */)
    360             {
    361                 RTMemFree(pTimer);
    362                 return VINF_SUCCESS;
    363             }
    364             AssertMsgFailed(("Failed to destroy timer %p. rc=%Vrc\n", pTimer, rc));
    365         }
    366         else
    367         {
    368             AssertMsgFailed(("Timer %p is already being destroyed!\n", pTimer));
    369             rc = VERR_INVALID_MAGIC;
    370         }
    371     }
    372     else
    373     {
    374         AssertMsgFailed(("Bad pTimer pointer %p!\n", pTimer));
    375         rc = VERR_INVALID_HANDLE;
    376     }
     427        pthread_kill((pthread_t)RTThreadGetNative(pTimer->Thread), SIGALRM);
     428#endif
     429    }
     430    rc = RTThreadWait(pTimer->Thread, 30 * 1000, NULL);
     431    AssertRC(rc);
     432
     433    RTSemEventDestroy(pTimer->Event);
     434    pTimer->Event = NIL_RTSEMEVENT;
     435    if (RT_SUCCESS(rc))
     436        RTMemFree(pTimer);
    377437    return rc;
    378438}
     
    381441RTDECL(int) RTTimerStart(PRTTIMER pTimer, uint64_t u64First)
    382442{
    383     /// @todo implement
    384     return VERR_NOT_IMPLEMENTED;
     443    /*
     444     * Validate input.
     445     */
     446    AssertPtrReturn(pTimer, VERR_INVALID_POINTER);
     447    AssertReturn(pTimer->u32Magic == RTTIMER_MAGIC, VERR_INVALID_MAGIC);
     448    AssertReturn(pTimer->Thread != RTThreadSelf(), VERR_INTERNAL_ERROR);
     449
     450    /*
     451     * Already running?
     452     */
     453    if (!pTimer->fSuspended)
     454        return VERR_TIMER_ACTIVE;
     455
     456    /*
     457     * Tell the thread to start servicing the timer.
     458     */
     459    RTThreadUserReset(pTimer->Thread);
     460    ASMAtomicXchgU64(&pTimer->u64NanoFirst, u64First);
     461    ASMAtomicXchgU8(&pTimer->fSuspended, false);
     462    int rc = RTSemEventSignal(pTimer->Event);
     463    if (RT_SUCCESS(rc))
     464    {
     465        rc = RTThreadUserWait(pTimer->Thread, 45*1000);
     466        AssertRC(rc);
     467        RTThreadUserReset(pTimer->Thread);
     468    }
     469    else
     470        AssertRC(rc);
     471    if (RT_FAILURE(rc))
     472        ASMAtomicXchgU8(&pTimer->fSuspended, false);
     473
     474    return rc;
    385475}
    386476
     
    388478RTDECL(int) RTTimerStop(PRTTIMER pTimer)
    389479{
    390     /// @todo implement
    391     return VERR_NOT_IMPLEMENTED;
     480    /*
     481     * Validate input.
     482     */
     483    AssertPtrReturn(pTimer, VERR_INVALID_POINTER);
     484    AssertReturn(pTimer->u32Magic == RTTIMER_MAGIC, VERR_INVALID_MAGIC);
     485
     486    /*
     487     * Already running?
     488     */
     489    if (pTimer->fSuspended)
     490        return VERR_TIMER_SUSPENDED;
     491
     492    /*
     493     * Tell the thread to stop servicing the timer.
     494     */
     495    RTThreadUserReset(pTimer->Thread);
     496    ASMAtomicXchgU8(&pTimer->fSuspended, true);
     497    if (RTThreadSelf() != pTimer->Timer)
     498    {
     499#ifndef __OS2__
     500        pthread_kill((pthread_t)RTThreadGetNative(pTimer->Thread), SIGALRM);
     501#endif
     502        int rc = RTThreadUserWait(pTimer->Thread, 45*1000);
     503        AssertRC(rc);
     504        RTThreadUserReset(pTimer->Thread);
     505    }
     506
     507    return rc;
    392508}
     509
  • trunk/src/VBox/Runtime/r3/win32/timer-win32.cpp

    r197 r1807  
    6464#include <iprt/semaphore.h>
    6565#include <iprt/err.h>
    66 
    67 #include <errno.h>
     66#include "internal/magics.h"
    6867
    6968__BEGIN_DECLS
     
    113112#endif
    114113} RTTIMER;
    115 
    116 /** Timer handle magic. */
    117 #define RTTIMER_MAGIC       0x42424242
    118 
    119114
    120115
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