VirtualBox

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


Ignore:
Timestamp:
Jul 28, 2008 6:44:26 PM (17 years ago)
Author:
vboxsync
Message:

POSIX timers with SIGEV_SIGNAL and a dedicated thread

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Runtime/r3/posix/timer-posix.cpp

    r10854 r10920  
    3737#endif /* !RT_OS_SOLARIS */
    3838
     39#define LOG_GROUP          RTLOGGROUP_TIMER
    3940
    4041/*******************************************************************************
     
    6566#endif
    6667
     68#ifdef IPRT_WITH_POSIX_TIMERS
     69#define RT_TIMER_SIGNAL SIGALRM
     70
     71/**
     72 * Global counter of RTTimer instances. The signal thread is
     73 * started when it changes from 0 to 1. The signal thread
     74 * terminates when it becomes 0 again.
     75 */
     76uint32_t   g_cTimerInstances;
     77/** The signal handling thread. */
     78RTTHREAD   g_Thread;
     79/**
     80 * Event semaphore on which the calling thread is blocked until
     81 * the signal thread has been initialized.
     82 */
     83RTSEMEVENT g_Event;
     84
     85#endif /* IPRT_WITH_POSIX_TIMERS */
    6786
    6887/*******************************************************************************
     
    93112    /** Event semaphore on which the thread is blocked. */
    94113    RTSEMEVENT              Event;
    95 #endif
     114#endif /* !IPRT_WITH_POSIX_TIMERS */
    96115    /** User argument. */
    97116    void                   *pvUser;
     
    111130     * to errno on failure in starting the timer. */
    112131    int volatile            iError;
    113 #else /* !IPRT_WITH_POSIX_TIMERS */
     132#else /* IPRT_WITH_POSIX_TIMERS */
    114133    timer_t                 timer;
    115 #endif /* !IPRT_WITH_POSIX_TIMERS */
     134#endif /* IPRT_WITH_POSIX_TIMERS */
    116135
    117136} RTTIMER;
    118 
    119 #ifndef IPRT_WITH_POSIX_TIMERS
    120137
    121138/**
     
    135152static DECLCALLBACK(int) rttimerThread(RTTHREAD Thread, void *pvArg)
    136153{
     154#ifndef IPRT_WITH_POSIX_TIMERS
    137155    PRTTIMER pTimer = (PRTTIMER)(void *)pvArg;
    138156    RTTIMER Timer = *pTimer;
    139157    Assert(pTimer->u32Magic == RTTIMER_MAGIC);
     158#endif /* !IPRT_WITH_POSIX_TIMERS */
    140159
    141160    /*
     
    170189    if (sigprocmask(SIG_SETMASK, &SigSet, NULL))
    171190    {
     191#ifndef IPRT_WITH_POSIX_TIMERS
    172192        int rc = pTimer->iError = RTErrConvertFromErrno(errno);
     193#else /* IPRT_WITH_POSIX_TIMERS */
     194        int rc = RTErrConvertFromErrno(errno);
     195#endif /* IPRT_WITH_POSIX_TIMERS */
    173196        AssertMsgFailed(("sigprocmask -> errno=%d\n", errno));
    174197        return rc;
     
    179202     */
    180203    RTThreadUserSignal(Thread);
     204
     205#ifndef IPRT_WITH_POSIX_TIMERS
    181206    while (     !pTimer->fDestroyed
    182207           &&   pTimer->u32Magic == RTTIMER_MAGIC)
     
    305330    return VINF_SUCCESS;
    306331}
    307 #else /* !IPRT_WITH_POSIX_TIMERS */
    308 void rttimerCallback(union sigval SigVal)
     332#else /* IPRT_WITH_POSIX_TIMERS */
     333    sigemptyset(&SigSet);
     334    sigaddset(&SigSet, RT_TIMER_SIGNAL);
     335    while (g_cTimerInstances)
     336    {
     337        siginfo_t SigInfo = {0};
     338        if (RT_LIKELY(sigwaitinfo(&SigSet, &SigInfo) >= 0))
     339        {
     340            LogFlow(("rttimerThread: signo=%d pTimer=%p\n", SigInfo.si_signo, SigInfo._sifields._timer.si_sigval.sival_ptr));
     341            if (RT_LIKELY(SigInfo.si_signo == RT_TIMER_SIGNAL))
     342            {
     343                PRTTIMER pTimer = (PRTTIMER)SigInfo._sifields._timer.si_sigval.sival_ptr;
     344                if (RT_UNLIKELY(    pTimer == NULL
     345                                ||  pTimer->fSuspended
     346                                ||  pTimer->fDestroyed
     347                                ||  pTimer->u32Magic != RTTIMER_MAGIC))
     348                    continue;
     349                pTimer->pfnTimer(pTimer, pTimer->pvUser, ++pTimer->iTick);
     350                /* auto suspend one-shot timers. */
     351                if (RT_UNLIKELY(!pTimer->u64NanoInterval))
     352                {
     353                    ASMAtomicXchgU8(&pTimer->fSuspended, true); /* @todo Can't we do a simple assigment here? */
     354                    //break;
     355                }
     356            }
     357        }
     358    }
     359
     360    return VINF_SUCCESS;
     361}
     362
     363/**
     364 * Create the SIGALRM handling thread and wait for it to get
     365 * ready.
     366 */
     367static int rttimerCreateSignalThread()
    309368{
    310     PRTTIMER pTimer = (PRTTIMER)SigVal.sival_ptr;
    311     /* Is the timer being destoyed/suspended at this very moment? */
    312     if (RT_LIKELY(pTimer->u32Magic == RTTIMER_MAGIC
    313                   && !pTimer->fSuspended
    314                   && !pTimer->fDestroyed))
    315     {
    316         pTimer->pfnTimer(pTimer, pTimer->pvUser, ++pTimer->iTick);
    317     }
     369    int rc = RTThreadCreate(&g_Thread, rttimerThread, NULL, 0, RTTHREADTYPE_TIMER, RTTHREADFLAGS_WAITABLE, "Timer");
     370    AssertRC(rc);
     371    if (RT_SUCCESS(rc))
     372    {
     373        /* Let's wait for the thread to get ready to handle signals. */
     374        rc = RTThreadUserWait(g_Thread, 5000); /* @todo 5 sec is enough? or is it too much? */
     375    }
     376    LogFlow(("rttimerCreateSignalThread: rc=%Vrc\n", rc));
     377
     378    return rc;
     379
    318380}
    319 #endif /* !IPRT_WITH_POSIX_TIMERS */
     381#endif /* IPRT_WITH_POSIX_TIMERS */
    320382
    321383
     
    328390        return VERR_NOT_SUPPORTED;
    329391
    330 #ifndef IPRT_WITH_POSIX_TIMERS /** @todo the signal blocking applies to the new code too, see comment in the struct. */
     392#ifndef IPRT_WITH_POSIX_TIMERS
    331393    /*
    332394     * Check if timer is busy.
     
    345407        return VERR_TIMER_BUSY;
    346408    }
     409#endif /* !IPRT_WITH_POSIX_TIMERS */
    347410
    348411    /*
     
    354417    sigprocmask(SIG_BLOCK, &SigSet, NULL);
    355418
     419#ifndef IPRT_WITH_POSIX_TIMERS
    356420    /** @todo Move this RTC hack else where... */
    357421    static bool fDoneRTC;
     
    452516    else
    453517        rc = VERR_NO_MEMORY;
    454 #else /* !IPRT_WITH_POSIX_TIMERS */
     518#else /* IPRT_WITH_POSIX_TIMERS */
    455519    /*
    456520     * Create a new timer.
    457521     */
    458     int rc;
     522    LogFlow(("RTTimerCreateEx: u64NanoInterval=%llu fFlags=%lu\n", u64NanoInterval, fFlags));
     523
     524    int rc = VINF_SUCCESS;
    459525    PRTTIMER pTimer = (PRTTIMER)RTMemAlloc(sizeof(*pTimer));
    460526    if (pTimer)
     
    471537        pTimer->iTick           = 0;
    472538
    473         /* Ask to call rttimerCallback in a separate thread context upon timer expiration. */
    474         memset(&evt, 0, sizeof(evt));
    475         evt.sigev_notify = SIGEV_THREAD;
    476         evt.sigev_value.sival_ptr = pTimer;
    477         evt.sigev_notify_function = rttimerCallback;
    478 
    479         rc = RTErrConvertFromErrno(timer_create(CLOCK_REALTIME, &evt, &pTimer->timer));
     539        /* Create the signal handling thread if it is the first instance. */
     540        if (ASMAtomicIncU32(&g_cTimerInstances) == 1)
     541            rc = rttimerCreateSignalThread();
     542
    480543        if (RT_SUCCESS(rc))
    481544        {
    482             *ppTimer = pTimer;
    483             return VINF_SUCCESS;
    484         }
     545            /* Ask to deliver RT_TIMER_SIGNAL upon timer expiration. */
     546            evt.sigev_notify = SIGEV_SIGNAL;
     547            evt.sigev_signo  = RT_TIMER_SIGNAL;
     548            evt.sigev_value.sival_ptr = pTimer; /* sigev_value gets copied to siginfo. */
     549
     550            rc = RTErrConvertFromErrno(timer_create(CLOCK_REALTIME, &evt, &pTimer->timer));
     551            LogFlow(("RTTimerCreateEx: rc=%Vrc pTimer=%p\n", rc, pTimer));
     552            if (RT_SUCCESS(rc))
     553            {
     554                *ppTimer = pTimer;
     555                return VINF_SUCCESS;
     556            }
     557        }
     558        /**
     559         * Roll back the timer instance counter. This will cause
     560         * termination of the signal handling thread if it is the only
     561         * timer.
     562         */
     563        ASMAtomicDecU32(&g_cTimerInstances);
    485564        RTMemFree(pTimer);
    486565    }
     
    488567        rc = VERR_NO_MEMORY;
    489568
    490 #endif /* !IPRT_WITH_POSIX_TIMERS */
     569#endif /* IPRT_WITH_POSIX_TIMERS */
    491570    return rc;
    492571}
     
    527606    RTSemEventDestroy(pTimer->Event);
    528607    pTimer->Event = NIL_RTSEMEVENT;
    529 #else /* !IPRT_WITH_POSIX_TIMERS */
     608#else /* IPRT_WITH_POSIX_TIMERS */
    530609    if (ASMAtomicXchgU8(&pTimer->fDestroyed, true))
    531610    {
     
    534613    }
    535614    rc = RTErrConvertFromErrno(timer_delete(pTimer->timer));
    536 #endif /* !IPRT_WITH_POSIX_TIMERS */
     615    /**
     616     * Decrement the timer instance counter. This will cause
     617     * termination of the signal handling thread if it is the last
     618     * remaining timer.
     619     */
     620    if (ASMAtomicDecU32(&g_cTimerInstances) == 0)
     621    {
     622        /* Wake up the timer thread so it can exit. */
     623        kill(getpid(), RT_TIMER_SIGNAL);
     624    }
     625#endif /* IPRT_WITH_POSIX_TIMERS */
    537626    if (RT_SUCCESS(rc))
    538627        RTMemFree(pTimer);
     
    575664    if (RT_FAILURE(rc))
    576665        ASMAtomicXchgU8(&pTimer->fSuspended, false);
    577 #else /* !IPRT_WITH_POSIX_TIMERS */
     666#else /* IPRT_WITH_POSIX_TIMERS */
     667    LogFlow(("RTTimerStart: pTimer=%p u64First=%llu u64NanoInterval=%llu\n", pTimer, u64First, pTimer->u64NanoInterval));
     668
    578669    struct itimerspec ts;
    579670
     
    582673
    583674    ts.it_value.tv_sec     = u64First / 1000000000; /* nanosec => sec */
    584     ts.it_value.tv_nsec    = u64First ? u64First % 1000000000 : 1; /* 0 means disable, replace it with 1. */
     675    ts.it_value.tv_nsec    = u64First ? u64First % 1000000000 : 10; /* 0 means disable, replace it with 10. */
    585676    ts.it_interval.tv_sec  = pTimer->u64NanoInterval / 1000000000;
    586677    ts.it_interval.tv_nsec = pTimer->u64NanoInterval % 1000000000;
    587678    int rc = RTErrConvertFromErrno(timer_settime(pTimer->timer, 0, &ts, NULL));
    588 #endif /* !IPRT_WITH_POSIX_TIMERS */
     679#endif /* IPRT_WITH_POSIX_TIMERS */
    589680
    590681    return rc;
     
    622713        RTThreadUserReset(pTimer->Thread);
    623714    }
    624 #else /* !IPRT_WITH_POSIX_TIMERS */
     715#else /* IPRT_WITH_POSIX_TIMERS */
     716    LogFlow(("RTTimerStop: pTimer=%p\n", pTimer));
     717
    625718    struct itimerspec ts;
    626719
     
    631724    ts.it_value.tv_nsec    = 0;
    632725    int rc = RTErrConvertFromErrno(timer_settime(pTimer->timer, 0, &ts, NULL));
    633 #endif /* !IPRT_WITH_POSIX_TIMERS */
     726#endif /* IPRT_WITH_POSIX_TIMERS */
    634727
    635728    return rc;
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