RTDECL(int) RTTimerChangeInterval(PRTTIMER pTimer, uint64_t u64NanoInterval)
{
    /*
     * Validate.
     */
    RTTIMER_ASSERT_VALID_RET(pTimer);
    AssertReturn(u64NanoInterval > 0, VERR_INVALID_PARAMETER);
    AssertReturn(u64NanoInterval < UINT64_MAX / 8, VERR_INVALID_PARAMETER);
    AssertReturn(pTimer->cNsInterval, VERR_INVALID_STATE);

    if (pTimer->fSuspended || pTimer->fSuspendedFromTimer)
        pTimer->cNsInterval = u64NanoInterval;
    else
    {
        ASMAtomicWriteU64(&pTimer->cNsInterval, u64NanoInterval);
        ASMAtomicWriteBool(&pTimer->fIntervalChanged, true);

        if (   !pTimer->fAllCpus
            && !pTimer->u.Single.nsNextTick
            && pTimer->hCyclicId != CYCLIC_NONE
            && rtTimerSolIsCallingFromTimerProc(pTimer))
            pTimer->u.Single.nsNextTick = RTTimeSystemNanoTS();
    }

    return VINF_SUCCESS;
}
Ejemplo n.º 2
0
RTDECL(int) RTTimerStop(PRTTIMER pTimer)
{
    RTTIMER_ASSERT_VALID_RET(pTimer);
    RT_ASSERT_INTS_ON();

    if (pTimer->fSuspended)
        return VERR_TIMER_SUSPENDED;

    pTimer->fSuspended = true;
    if (pTimer->pSingleTimer)
    {
        mutex_enter(&cpu_lock);
        cyclic_remove(pTimer->hCyclicId);
        mutex_exit(&cpu_lock);
        RTMemFree(pTimer->pSingleTimer);
    }
    else if (pTimer->pOmniTimer)
    {
        mutex_enter(&cpu_lock);
        cyclic_remove(pTimer->hCyclicId);
        mutex_exit(&cpu_lock);
        RTMemFree(pTimer->pOmniTimer->au64Ticks);
        RTMemFree(pTimer->pOmniTimer);
    }

    return VINF_SUCCESS;
}
RTDECL(int) RTTimerDestroy(PRTTIMER pTimer)
{
    if (pTimer == NULL)
        return VINF_SUCCESS;
    RTTIMER_ASSERT_VALID_RET(pTimer);
    RT_ASSERT_INTS_ON();

    /*
     * It is not possible to destroy a timer from it's callback function.
     * Cyclic makes that impossible (or at least extremely risky).
     */
    AssertReturn(!rtTimerSolIsCallingFromTimerProc(pTimer), VERR_INVALID_CONTEXT);

    /*
     * Invalidate the handle, make sure it's stopped and free the associated resources.
     */
    ASMAtomicWriteU32(&pTimer->u32Magic, ~RTTIMER_MAGIC);

    if (   !pTimer->fSuspended
        || pTimer->hCyclicId != CYCLIC_NONE) /* 2nd check shouldn't happen */
        rtTimerSolStopIt(pTimer);

    rtTimerSolRelease(pTimer);
    return VINF_SUCCESS;
}
Ejemplo n.º 4
0
RTDECL(int) RTTimerChangeInterval(PRTTIMER pTimer, uint64_t u64NanoInterval)
{
    RTTIMER_ASSERT_VALID_RET(pTimer);

    /** @todo implement me! */

    return VERR_NOT_SUPPORTED;
}
Ejemplo n.º 5
0
RTDECL(int) RTTimerDestroy(PRTTIMER pTimer)
{
    if (pTimer == NULL)
        return VINF_SUCCESS;
    RTTIMER_ASSERT_VALID_RET(pTimer);
    RT_ASSERT_INTS_ON();

    /*
     * Free the associated resources.
     */
    RTTimerStop(pTimer);
    ASMAtomicWriteU32(&pTimer->u32Magic, ~RTTIMER_MAGIC);
    RTMemFree(pTimer);
    return VINF_SUCCESS;
}
RTDECL(int) RTTimerStop(PRTTIMER pTimer)
{
    RTTIMER_ASSERT_VALID_RET(pTimer);
    RT_ASSERT_INTS_ON();

    if (pTimer->fSuspended)
        return VERR_TIMER_SUSPENDED;

    /* Trying the cpu_lock stuff and calling cyclic_remove may deadlock
       the system, so just mark the timer as suspened and deal with it in
       the callback wrapper function above. */
    if (rtTimerSolIsCallingFromTimerProc(pTimer))
        pTimer->fSuspendedFromTimer = true;
    else
        rtTimerSolStopIt(pTimer);

    return VINF_SUCCESS;
}
Ejemplo n.º 7
0
RTDECL(int) RTTimerStart(PRTTIMER pTimer, uint64_t u64First)
{
    RTTIMER_ASSERT_VALID_RET(pTimer);
    RT_ASSERT_INTS_ON();

    if (!pTimer->fSuspended)
        return VERR_TIMER_ACTIVE;

    /* One-shot timers are not supported by the cyclic system. */
    if (pTimer->interval == 0)
        return VERR_NOT_SUPPORTED;

    pTimer->fSuspended = false;
    if (pTimer->fAllCpu)
    {
        PRTR0OMNITIMERSOL pOmniTimer = RTMemAllocZ(sizeof(RTR0OMNITIMERSOL));
        if (RT_UNLIKELY(!pOmniTimer))
            return VERR_NO_MEMORY;

        pOmniTimer->au64Ticks = RTMemAllocZ(RTMpGetCount() * sizeof(uint64_t));
        if (RT_UNLIKELY(!pOmniTimer->au64Ticks))
        {
            RTMemFree(pOmniTimer);
            return VERR_NO_MEMORY;
        }

        /*
         * Setup omni (all CPU) timer. The Omni-CPU online event will fire
         * and from there we setup periodic timers per CPU.
         */
        pTimer->pOmniTimer = pOmniTimer;
        pOmniTimer->u64When     = pTimer->interval + RTTimeNanoTS();

        cyc_omni_handler_t hOmni;
        hOmni.cyo_online        = rtTimerSolOmniCpuOnline;
        hOmni.cyo_offline       = NULL;
        hOmni.cyo_arg           = pTimer;

        mutex_enter(&cpu_lock);
        pTimer->hCyclicId = cyclic_add_omni(&hOmni);
        mutex_exit(&cpu_lock);
    }
    else
    {
        int iCpu = SOL_TIMER_ANY_CPU;
        if (pTimer->fSpecificCpu)
        {
            iCpu = pTimer->iCpu;
            if (!RTMpIsCpuOnline(iCpu))    /* ASSUMES: index == cpuid */
                return VERR_CPU_OFFLINE;
        }

        PRTR0SINGLETIMERSOL pSingleTimer = RTMemAllocZ(sizeof(RTR0SINGLETIMERSOL));
        if (RT_UNLIKELY(!pSingleTimer))
            return VERR_NO_MEMORY;

        pTimer->pSingleTimer = pSingleTimer;
        pSingleTimer->hHandler.cyh_func  = rtTimerSolCallbackWrapper;
        pSingleTimer->hHandler.cyh_arg   = pTimer;
        pSingleTimer->hHandler.cyh_level = CY_LOCK_LEVEL;

        mutex_enter(&cpu_lock);
        if (iCpu != SOL_TIMER_ANY_CPU && !cpu_is_online(cpu[iCpu]))
        {
            mutex_exit(&cpu_lock);
            RTMemFree(pSingleTimer);
            pTimer->pSingleTimer = NULL;
            return VERR_CPU_OFFLINE;
        }

        pSingleTimer->hFireTime.cyt_when = u64First + RTTimeNanoTS();
        if (pTimer->interval == 0)
        {
            /** @todo use gethrtime_max instead of LLONG_MAX? */
            AssertCompileSize(pSingleTimer->hFireTime.cyt_interval, sizeof(long long));
            pSingleTimer->hFireTime.cyt_interval = LLONG_MAX - pSingleTimer->hFireTime.cyt_when;
        }
        else
            pSingleTimer->hFireTime.cyt_interval = pTimer->interval;

        pTimer->hCyclicId = cyclic_add(&pSingleTimer->hHandler, &pSingleTimer->hFireTime);
        if (iCpu != SOL_TIMER_ANY_CPU)
            cyclic_bind(pTimer->hCyclicId, cpu[iCpu], NULL /* cpupart */);

        mutex_exit(&cpu_lock);
    }

    return VINF_SUCCESS;
}
RTDECL(int) RTTimerStart(PRTTIMER pTimer, uint64_t u64First)
{
    RTTIMER_ASSERT_VALID_RET(pTimer);
    RT_ASSERT_INTS_ON();

    /*
     * It's not possible to restart a one-shot time from it's callback function,
     * at least not at the moment.
     */
    AssertReturn(!rtTimerSolIsCallingFromTimerProc(pTimer), VERR_INVALID_CONTEXT);

    mutex_enter(&cpu_lock);

    /*
     * Make sure it's not active already.  If it was suspended from a timer
     * callback function, we need to do some cleanup work here before we can
     * restart the timer.
     */
    if (!pTimer->fSuspended)
    {
        if (!pTimer->fSuspendedFromTimer)
        {
            mutex_exit(&cpu_lock);
            return VERR_TIMER_ACTIVE;
        }
        cyclic_remove(pTimer->hCyclicId);
        pTimer->hCyclicId = CYCLIC_NONE;
    }

    pTimer->fSuspended = false;
    pTimer->fSuspendedFromTimer = false;
    pTimer->fIntervalChanged = false;
    if (pTimer->fAllCpus)
    {
        /*
         * Setup omni (all CPU) timer. The Omni-CPU online event will fire
         * and from there we setup periodic timers per CPU.
         */
        pTimer->u.Omni.u64When  = RTTimeSystemNanoTS() + (u64First ? u64First : pTimer->cNsInterval);

        cyc_omni_handler_t HandlerOmni;
        HandlerOmni.cyo_online  = rtTimerSolOmniCpuOnline;
        HandlerOmni.cyo_offline = NULL;
        HandlerOmni.cyo_arg     = pTimer;

        pTimer->hCyclicId = cyclic_add_omni(&HandlerOmni);
    }
    else
    {
        cyc_handler_t Handler;
        cyc_time_t    FireTime;

        /*
         * Setup a single CPU timer.   If a specific CPU was requested, it
         * must be online or the timer cannot start.
         */
        if (   pTimer->fSpecificCpu
            && !RTMpIsCpuOnline(pTimer->iCpu)) /* ASSUMES: index == cpuid */
        {
            pTimer->fSuspended = true;

            mutex_exit(&cpu_lock);
            return VERR_CPU_OFFLINE;
        }

        Handler.cyh_func  = (cyc_func_t)rtTimerSolSingleCallbackWrapper;
        Handler.cyh_arg   = pTimer;
        Handler.cyh_level = CY_LOCK_LEVEL;

        /*
         * Use a large interval (1 hour) so that we don't get a timer-callback between
         * cyclic_add() and cyclic_bind(). Program the correct interval once cyclic_bind() is done.
         * See @bugref{7691#c20}.
         */
        if (!pTimer->fSpecificCpu)
            FireTime.cyt_when = RTTimeSystemNanoTS() + u64First;
        else
            FireTime.cyt_when = RTTimeSystemNanoTS() + u64First + RT_NS_1HOUR;
        FireTime.cyt_interval = pTimer->cNsInterval != 0
                              ? pTimer->cNsInterval
                              : CY_INFINITY /* Special value, see cyclic_fire(). */;
        pTimer->u.Single.u64Tick = 0;
        pTimer->u.Single.nsNextTick = 0;

        pTimer->hCyclicId = cyclic_add(&Handler, &FireTime);
        if (pTimer->fSpecificCpu)
        {
            cyclic_bind(pTimer->hCyclicId, cpu[pTimer->iCpu], NULL /* cpupart */);
            cyclic_reprogram(pTimer->hCyclicId, RTTimeSystemNanoTS() + u64First);
        }
    }

    mutex_exit(&cpu_lock);
    return VINF_SUCCESS;
}