VirtualBox

Ignore:
Timestamp:
Apr 17, 2012 4:43:28 PM (13 years ago)
Author:
vboxsync
Message:

Runtime/r0drv/solaris: Dissolve VBI into IPRT.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Runtime/r0drv/solaris/vbi/timer-r0drv-solaris.c

    r37275 r40966  
    4646#include "internal/magics.h"
    4747
     48#define SOL_TIMER_ANY_CPU       (-1)
    4849
    4950/*******************************************************************************
    5051*   Structures and Typedefs                                                    *
    5152*******************************************************************************/
     53/**
     54 * Single-CPU timer handle.
     55 */
     56typedef struct RTR0SINGLETIMERSOL
     57{
     58    /** Cyclic handler. */
     59    cyc_handler_t           hHandler;
     60    /** Cyclic time and interval representation. */
     61    cyc_time_t              hFireTime;
     62    /** Timer ticks. */
     63    uint64_t                u64Tick;
     64} RTR0SINGLETIMERSOL;
     65typedef RTR0SINGLETIMERSOL *PRTR0SINGLETIMERSOL;
     66
     67/**
     68 * Omni-CPU timer handle.
     69 */
     70typedef struct RTR0OMNITIMERSOL
     71{
     72    /** Absolute timestamp of when the timer should fire next. */
     73    uint64_t                u64When;
     74    /** Array of timer ticks per CPU. Reinitialized when a CPU is online'd. */
     75    uint64_t               *au64Ticks;
     76} RTR0OMNITIMERSOL;
     77typedef RTR0OMNITIMERSOL *PRTR0OMNITIMERSOL;
     78
    5279/**
    5380 * The internal representation of a Solaris timer handle.
     
    6188    /** Flag indicating that the timer is suspended. */
    6289    uint8_t volatile        fSuspended;
    63     /** Run on all CPUs if set */
     90    /** Whether the timer must run on all CPUs or not. */
    6491    uint8_t                 fAllCpu;
    6592    /** Whether the timer must run on a specific CPU or not. */
     
    6794    /** The CPU it must run on if fSpecificCpu is set. */
    6895    uint8_t                 iCpu;
    69     /** The nano second interval for repeating timers */
     96    /** The nano second interval for repeating timers. */
    7097    uint64_t                interval;
    71     /** simple Solaris timer handle. */
    72     vbi_stimer_t           *stimer;
    73     /** global Solaris timer handle. */
    74     vbi_gtimer_t           *gtimer;
     98    /** Cyclic timer Id. */
     99    cyclic_id_t             hCyclicId;
     100    /** @todo Make this a union unless we intend to support omni<=>single timers
     101     *        conversions. */
     102    /** Single-CPU timer handle. */
     103    PRTR0SINGLETIMERSOL     pSingleTimer;
     104    /** Omni-CPU timer handle. */
     105    PRTR0OMNITIMERSOL       pOmniTimer;
    75106    /** The user callback. */
    76107    PFNRTTIMER              pfnTimer;
     
    88119    { \
    89120        AssertPtrReturn(pTimer, VERR_INVALID_HANDLE); \
    90         AssertReturn((pTimer)->u32Magic == RTTIMER_MAGIC, VERR_INVALID_HANDLE); \
     121        AssertMsgReturn((pTimer)->u32Magic == RTTIMER_MAGIC, ("pTimer=%p u32Magic=%x expected %x\n", (pTimer), (pTimer)->u32Magic, RTTIMER_MAGIC), \
     122            VERR_INVALID_HANDLE); \
    91123    } while (0)
    92124
    93125
    94 /*
    95  * Need a wrapper to get the PRTTIMER passed through
    96  */
    97 static void rtTimerSolarisCallbackWrapper(PRTTIMER pTimer, uint64_t tick)
    98 {
    99     pTimer->pfnTimer(pTimer, pTimer->pvUser, tick);
    100 }
    101 
    102 
     126/**
     127 * Callback wrapper for Omni-CPU and single-CPU timers.
     128 *
     129 * @param    pvArg              Opaque pointer to the timer.
     130 *
     131 * @remarks This will be executed in interrupt context but only at the specified
     132 *          level i.e. CY_LOCK_LEVEL in our case. We -CANNOT- call into the
     133 *          cyclic subsystem here, neither should pfnTimer().
     134 */
     135static void rtTimerSolCallbackWrapper(void *pvArg)
     136{
     137    PRTTIMER pTimer = (PRTTIMER)pvArg;
     138    AssertPtrReturnVoid(pTimer);
     139
     140    if (pTimer->pSingleTimer)
     141    {
     142        uint64_t u64Tick = ++pTimer->pSingleTimer->u64Tick;
     143        pTimer->pfnTimer(pTimer, pTimer->pvUser, u64Tick);
     144    }
     145    else if (pTimer->pOmniTimer)
     146    {
     147        uint64_t u64Tick = ++pTimer->pOmniTimer->au64Ticks[CPU->cpu_id];
     148        pTimer->pfnTimer(pTimer, pTimer->pvUser, u64Tick);
     149    }
     150}
     151
     152
     153/**
     154 * Omni-CPU cyclic online event. This is called before the omni cycle begins to
     155 * fire on the specified CPU.
     156 *
     157 * @param    pvArg              Opaque pointer to the timer.
     158 * @param    pCpu               Pointer to the CPU on which it will fire.
     159 * @param    pCyclicHandler     Pointer to a cyclic handler to add to the CPU
     160 *                              specified in @a pCpu.
     161 * @param    pCyclicTime        Pointer to the cyclic time and interval object.
     162 *
     163 * @remarks We -CANNOT- call back into the cyclic subsystem here, we can however
     164 *          block (sleep).
     165 */
     166static void rtTimerSolOmniCpuOnline(void *pvArg, cpu_t *pCpu, cyc_handler_t *pCyclicHandler, cyc_time_t *pCyclicTime)
     167{
     168    PRTTIMER pTimer = (PRTTIMER)pvArg;
     169    AssertPtrReturnVoid(pTimer);
     170    AssertPtrReturnVoid(pCpu);
     171    AssertPtrReturnVoid(pCyclicHandler);
     172    AssertPtrReturnVoid(pCyclicTime);
     173
     174    pTimer->pOmniTimer->au64Ticks[pCpu->cpu_id] = 0;
     175    pCyclicHandler->cyh_func  = rtTimerSolCallbackWrapper;
     176    pCyclicHandler->cyh_arg   = pTimer;
     177    pCyclicHandler->cyh_level = CY_LOCK_LEVEL;
     178
     179    uint64_t u64Now = RTTimeNanoTS();
     180    if (pTimer->pOmniTimer->u64When < u64Now)
     181        pCyclicTime->cyt_when = u64Now + pTimer->interval / 2;
     182    else
     183        pCyclicTime->cyt_when = pTimer->pOmniTimer->u64When;
     184
     185    pCyclicTime->cyt_interval = pTimer->interval;
     186}
    103187
    104188
     
    152236    pTimer->pfnTimer = pfnTimer;
    153237    pTimer->pvUser = pvUser;
    154     pTimer->stimer = NULL;
    155     pTimer->gtimer = NULL;
    156 
     238    pTimer->pSingleTimer = NULL;
     239    pTimer->pOmniTimer = NULL;
     240    pTimer->hCyclicId = CYCLIC_NONE;
     241
     242    cmn_err(CE_NOTE, "Create pTimer->u32Magic=%x RTTIMER_MAGIC=%x\n",  pTimer->u32Magic, RTTIMER_MAGIC);
    157243    *ppTimer = pTimer;
    158244    return VINF_SUCCESS;
     
    179265RTDECL(int) RTTimerStart(PRTTIMER pTimer, uint64_t u64First)
    180266{
     267    cmn_err(CE_NOTE, "Start pTimer->u32Magic=%x RTTIMER_MAGIC=%x\n",  pTimer->u32Magic, RTTIMER_MAGIC);
    181268    RTTIMER_ASSERT_VALID_RET(pTimer);
    182269    RT_ASSERT_INTS_ON();
     
    185272        return VERR_TIMER_ACTIVE;
    186273
     274    /* One-shot timers are not supported by the cyclic system. */
     275    if (pTimer->interval == 0)
     276        return VERR_NOT_SUPPORTED;
     277
    187278    pTimer->fSuspended = false;
    188279    if (pTimer->fAllCpu)
    189280    {
    190         pTimer->gtimer = vbi_gtimer_begin(rtTimerSolarisCallbackWrapper, pTimer, u64First, pTimer->interval);
    191         if (pTimer->gtimer == NULL)
    192             return VERR_INVALID_PARAMETER;
     281        PRTR0OMNITIMERSOL pOmniTimer = RTMemAllocZ(sizeof(RTR0OMNITIMERSOL));
     282        if (RT_UNLIKELY(!pOmniTimer))
     283            return VERR_NO_MEMORY;
     284
     285        pOmniTimer->au64Ticks = RTMemAllocZ(RTMpGetCount() * sizeof(uint64_t));
     286        if (RT_UNLIKELY(!pOmniTimer->au64Ticks))
     287        {
     288            RTMemFree(pOmniTimer);
     289            return VERR_NO_MEMORY;
     290        }
     291
     292        /*
     293         * Setup omni (all CPU) timer. The Omni-CPU online event will fire
     294         * and from there we setup periodic timers per CPU.
     295         */
     296        pTimer->pOmniTimer = pOmniTimer;
     297        pOmniTimer->u64When     = pTimer->interval + RTTimeNanoTS();
     298
     299        cyc_omni_handler_t hOmni;
     300        hOmni.cyo_online        = rtTimerSolOmniCpuOnline;
     301        hOmni.cyo_offline       = NULL;
     302        hOmni.cyo_arg           = pTimer;
     303
     304        mutex_enter(&cpu_lock);
     305        pTimer->hCyclicId = cyclic_add_omni(&hOmni);
     306        mutex_exit(&cpu_lock);
    193307    }
    194308    else
    195309    {
    196         int iCpu = VBI_ANY_CPU;
     310        int iCpu = SOL_TIMER_ANY_CPU;
    197311        if (pTimer->fSpecificCpu)
     312        {
    198313            iCpu = pTimer->iCpu;
    199         pTimer->stimer = vbi_stimer_begin(rtTimerSolarisCallbackWrapper, pTimer, u64First, pTimer->interval, iCpu);
    200         if (pTimer->stimer == NULL)
     314            if (!RTMpIsCpuOnline(iCpu))    /* ASSUMES: index == cpuid */
     315                return VERR_CPU_OFFLINE;
     316        }
     317
     318        PRTR0SINGLETIMERSOL pSingleTimer = RTMemAllocZ(sizeof(RTR0SINGLETIMERSOL));
     319        if (RT_UNLIKELY(!pSingleTimer))
     320            return VERR_NO_MEMORY;
     321
     322        pTimer->pSingleTimer = pSingleTimer;
     323        pSingleTimer->hHandler.cyh_func  = rtTimerSolCallbackWrapper;
     324        pSingleTimer->hHandler.cyh_arg   = pTimer;
     325        pSingleTimer->hHandler.cyh_level = CY_LOCK_LEVEL;
     326
     327        mutex_enter(&cpu_lock);
     328        if (iCpu != SOL_TIMER_ANY_CPU && !cpu_is_online(cpu[iCpu]))
    201329        {
    202             if (iCpu != VBI_ANY_CPU)
    203                 return VERR_CPU_OFFLINE;
    204             return VERR_INVALID_PARAMETER;
     330            mutex_exit(&cpu_lock);
     331            RTMemFree(pSingleTimer);
     332            pTimer->pSingleTimer = NULL;
     333            return VERR_CPU_OFFLINE;
    205334        }
     335
     336        pSingleTimer->hFireTime.cyt_when = u64First + RTTimeNanoTS();
     337        if (pTimer->interval == 0)
     338        {
     339            /* @todo use gethrtime_max instead of LLONG_MAX? */
     340            AssertCompileSize(pSingleTimer->hFireTime.cyt_interval, sizeof(long long));
     341            pSingleTimer->hFireTime.cyt_interval = LLONG_MAX - pSingleTimer->hFireTime.cyt_when;
     342        }
     343        else
     344            pSingleTimer->hFireTime.cyt_interval = pTimer->interval;
     345
     346        pTimer->hCyclicId = cyclic_add(&pSingleTimer->hHandler, &pSingleTimer->hFireTime);
     347        if (iCpu != SOL_TIMER_ANY_CPU)
     348            cyclic_bind(pTimer->hCyclicId, cpu[iCpu], NULL /* cpupart */);
     349
     350        mutex_exit(&cpu_lock);
    206351    }
    207352
     
    219364
    220365    pTimer->fSuspended = true;
    221     if (pTimer->stimer)
    222     {
    223         vbi_stimer_end(pTimer->stimer);
    224         pTimer->stimer = NULL;
    225     }
    226     else if (pTimer->gtimer)
    227     {
    228         vbi_gtimer_end(pTimer->gtimer);
    229         pTimer->gtimer = NULL;
     366    if (pTimer->pSingleTimer)
     367    {
     368        mutex_enter(&cpu_lock);
     369        cyclic_remove(pTimer->hCyclicId);
     370        mutex_exit(&cpu_lock);
     371        RTMemFree(pTimer->pSingleTimer);
     372    }
     373    else if (pTimer->pOmniTimer)
     374    {
     375        mutex_enter(&cpu_lock);
     376        cyclic_remove(pTimer->hCyclicId);
     377        mutex_exit(&cpu_lock);
     378        RTMemFree(pTimer->pOmniTimer->au64Ticks);
     379        RTMemFree(pTimer->pOmniTimer);
    230380    }
    231381
     
    234384
    235385
    236 
    237386RTDECL(int) RTTimerChangeInterval(PRTTIMER pTimer, uint64_t u64NanoInterval)
    238387{
     
    247396RTDECL(uint32_t) RTTimerGetSystemGranularity(void)
    248397{
    249     return vbi_timer_granularity();
     398    return nsec_per_tick;
    250399}
    251400
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