VirtualBox

Ignore:
Timestamp:
Feb 12, 2015 8:50:29 PM (10 years ago)
Author:
vboxsync
Message:

timer-r0drv-solaris.c: Cleanups. Got rid of 2-3 allocations in RTTimerStart, by embedding the data into the timer structure itself and allocated it all in one go in RTTimerCreate.

File:
1 edited

Legend:

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

    r53404 r54183  
    5252*******************************************************************************/
    5353/**
    54  * Single-CPU timer handle.
    55  */
    56 typedef 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;
    65 typedef RTR0SINGLETIMERSOL *PRTR0SINGLETIMERSOL;
    66 
    67 /**
    68  * Omni-CPU timer handle.
    69  */
    70 typedef 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;
    77 typedef RTR0OMNITIMERSOL *PRTR0OMNITIMERSOL;
    78 
    79 /**
    8054 * The internal representation of a Solaris timer handle.
    8155 */
     
    8660     * is destroyed to indicate clearly that thread should exit. */
    8761    uint32_t volatile       u32Magic;
     62    /** Reference counter. */
     63    uint32_t volatile       cRefs;
    8864    /** Flag indicating that the timer is suspended. */
    8965    uint8_t volatile        fSuspended;
    9066    /** Whether the timer must run on all CPUs or not. */
    91     uint8_t                 fAllCpu;
     67    uint8_t                 fAllCpus;
    9268    /** Whether the timer must run on a specific CPU or not. */
    9369    uint8_t                 fSpecificCpu;
     
    9571    uint8_t                 iCpu;
    9672    /** The nano second interval for repeating timers. */
    97     uint64_t                interval;
     73    uint64_t                cNsInterval;
    9874    /** Cyclic timer Id. */
    9975    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;
    10676    /** The user callback. */
    10777    PFNRTTIMER              pfnTimer;
    10878    /** The argument for the user callback. */
    10979    void                   *pvUser;
     80    /** Union with timer type specific data. */
     81    union
     82    {
     83        /** Single timer (fAllCpus == false). */
     84        struct
     85        {
     86            /** Cyclic handler. */
     87            cyc_handler_t   hHandler;
     88            /** Cyclic time and interval representation. */
     89            cyc_time_t      hFireTime;
     90            /** Timer ticks. */
     91            uint64_t        u64Tick;
     92        } Single;
     93
     94        /** Omni timer (fAllCpus == true). */
     95        struct
     96        {
     97             /** Absolute timestamp of when the timer should fire next. */
     98            uint64_t        u64When;
     99            /** Array of timer ticks per CPU. Reinitialized when a CPU is online'd
     100             *  (variable size). */
     101            uint64_t        au64Ticks[1];
     102        } Omni;
     103    } u;
    110104} RTTIMER;
    111105
     
    124118
    125119
    126 /**
    127  * Callback wrapper for specific timers if they happened to have been fired on
    128  * the wrong CPU. See rtTimerSolCallbackWrapper().
     120
     121/**
     122 * Retains a reference to the timer.
     123 *
     124 * @returns New reference counter value.
     125 * @param   pTimer              The timer.
     126 */
     127DECLINLINE(uint32_t) rtTimerSolRetain(PRTTIMER pTimer)
     128{
     129    return ASMAtomicIncU32(&pTimer->cRefs);
     130}
     131
     132
     133/**
     134 * Destroys the timer when the reference counter has reached zero.
     135 *
     136 * @returns 0 (new references counter value).
     137 * @param   pTimer              The timer.
     138 */
     139static uint32_t rtTimeSolReleaseCleanup(PRTTIMER pTimer)
     140{
     141    Assert(pTimer->hCyclicId == CYCLIC_NONE);
     142    ASMAtomicWriteU32(&pTimer->u32Magic, ~RTTIMER_MAGIC);
     143    RTMemFree(pTimer);
     144}
     145
     146
     147/**
     148 * Releases a reference to the timer.
     149 *
     150 * @returns New reference counter value.
     151 * @param   pTimer              The timer.
     152 */
     153DECLINLINE(uint32_t) rtTimerSolRelease(PRTTIMER pTimer)
     154{
     155    uint32_t cRefs = ASMAtomicDecU32(&pTimer->cRefs);
     156    if (!cRefs)
     157        return rtTimeSolReleaseCleanup(pTimer);
     158    return cRefs;
     159}
     160
     161
     162/**
     163 * RTMpOnSpecific callback used by rtTimerSolCallbackWrapper() to deal with
     164 * callouts on the wrong CPU (race with cyclic_bind).
    129165 *
    130166 * @param   idCpu       The CPU this is fired on.
     
    138174    Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
    139175    Assert(pTimer->iCpu == RTMpCpuId());    /* ASSUMES: index == cpuid */
    140     Assert(pTimer->pSingleTimer);
     176    Assert(!pTimer->fAllCpus);
    141177    NOREF(pvUser2);
    142178
    143179    /* Make sure one-shots do not fire another time. */
    144180    Assert(   !pTimer->fSuspended
    145            || pTimer->interval != 0);
     181           || pTimer->cNsInterval != 0);
    146182
    147183    /* For one-shot specific timers, allow RTTimer to restart them. */
    148     if (pTimer->interval == 0)
     184    if (pTimer->cNsInterval == 0)
    149185        pTimer->fSuspended = true;
    150186
    151     uint64_t u64Tick = ++pTimer->pSingleTimer->u64Tick;
     187    uint64_t u64Tick = ++pTimer->u.Single.u64Tick;
    152188    pTimer->pfnTimer(pTimer, pTimer->pvUser, u64Tick);
    153189}
     
    155191
    156192/**
    157  * Callback wrapper for Omni-CPU and single-CPU timers.
     193 * Callback wrapper for single-CPU timers.
    158194 *
    159195 * @param    pvArg              Opaque pointer to the timer.
     
    163199 *          cyclic subsystem here, neither should pfnTimer().
    164200 */
    165 static void rtTimerSolCallbackWrapper(void *pvArg)
     201static void rtTimerSolSingleCallbackWrapper(void *pvArg)
    166202{
    167203    PRTTIMER pTimer = (PRTTIMER)pvArg;
    168204    AssertPtrReturnVoid(pTimer);
    169205    Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
    170 
    171     if (pTimer->pSingleTimer)
    172     {
    173         /* Make sure one-shots do not fire another time. */
    174         Assert(   !pTimer->fSuspended
    175                || pTimer->interval != 0);
    176 
    177         /* For specific timers, we might fire on the wrong CPU between cyclic_add() and cyclic_bind().
    178            Redirect these shots to the right CPU as we are temporarily rebinding to the right CPU. */
    179         if (   pTimer->fSpecificCpu
    180             && pTimer->iCpu != RTMpCpuId())          /* ASSUMES: index == cpuid */
    181         {
    182             RTMpOnSpecific(pTimer->iCpu, rtTimerSolMpCallbackWrapper, pTimer, NULL);
    183             return;
    184         }
    185 
    186         /* For one-shot any-cpu timers, allow RTTimer to restart them. */
    187         if (pTimer->interval == 0)
    188             pTimer->fSuspended = true;
    189 
    190         uint64_t u64Tick = ++pTimer->pSingleTimer->u64Tick;
    191         pTimer->pfnTimer(pTimer, pTimer->pvUser, u64Tick);
    192     }
    193     else if (pTimer->pOmniTimer)
    194     {
    195         uint64_t u64Tick = ++pTimer->pOmniTimer->au64Ticks[CPU->cpu_id];
    196         pTimer->pfnTimer(pTimer, pTimer->pvUser, u64Tick);
    197     }
     206    Assert(!pTimer->fAllCpus);
     207
     208    /* Make sure one-shots do not fire another time. */
     209    Assert(   !pTimer->fSuspended
     210           || pTimer->cNsInterval != 0);
     211
     212    /* For specific timers, we might fire on the wrong CPU between cyclic_add() and cyclic_bind().
     213       Redirect these shots to the right CPU as we are temporarily rebinding to the right CPU. */
     214    if (   pTimer->fSpecificCpu
     215        && pTimer->iCpu != RTMpCpuId())          /* ASSUMES: index == cpuid */
     216    {
     217        RTMpOnSpecific(pTimer->iCpu, rtTimerSolMpCallbackWrapper, pTimer, NULL);
     218        return;
     219    }
     220
     221    /* For one-shot any-cpu timers, allow RTTimer to restart them. */
     222    if (pTimer->cNsInterval == 0)
     223        pTimer->fSuspended = true;
     224
     225    uint64_t u64Tick = ++pTimer->u.Single.u64Tick;
     226    pTimer->pfnTimer(pTimer, pTimer->pvUser, u64Tick);
     227}
     228
     229
     230/**
     231 * Callback wrapper for Omni-CPU timers.
     232 *
     233 * @param    pvArg              Opaque pointer to the timer.
     234 *
     235 * @remarks This will be executed in interrupt context but only at the specified
     236 *          level i.e. CY_LOCK_LEVEL in our case. We -CANNOT- call into the
     237 *          cyclic subsystem here, neither should pfnTimer().
     238 */
     239static void rtTimerSolOmniCallbackWrapper(void *pvArg)
     240{
     241    PRTTIMER pTimer = (PRTTIMER)pvArg;
     242    AssertPtrReturnVoid(pTimer);
     243    Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
     244    Assert(pTimer->fAllCpus);
     245
     246    uint64_t u64Tick = ++pTimer->u.Omni.au64Ticks[CPU->cpu_id];
     247    pTimer->pfnTimer(pTimer, pTimer->pvUser, u64Tick);
    198248}
    199249
     
    220270    AssertPtrReturnVoid(pCyclicTime);
    221271
    222     pTimer->pOmniTimer->au64Ticks[pCpu->cpu_id] = 0;
    223     pCyclicHandler->cyh_func  = (cyc_func_t)rtTimerSolCallbackWrapper;
     272    pTimer->u.Omni.au64Ticks[pCpu->cpu_id] = 0;
     273    pCyclicHandler->cyh_func  = (cyc_func_t)rtTimerSolOmniCallbackWrapper;
    224274    pCyclicHandler->cyh_arg   = pTimer;
    225275    pCyclicHandler->cyh_level = CY_LOCK_LEVEL;
    226276
    227277    uint64_t u64Now = RTTimeSystemNanoTS();
    228     if (pTimer->pOmniTimer->u64When < u64Now)
    229         pCyclicTime->cyt_when = u64Now + pTimer->interval / 2;
     278    if (pTimer->u.Omni.u64When < u64Now)
     279        pCyclicTime->cyt_when = u64Now + pTimer->cNsInterval / 2;
    230280    else
    231         pCyclicTime->cyt_when = pTimer->pOmniTimer->u64When;
    232 
    233     pCyclicTime->cyt_interval = pTimer->interval;
     281        pCyclicTime->cyt_when = pTimer->u.Omni.u64When;
     282
     283    pCyclicTime->cyt_interval = pTimer->cNsInterval;
    234284}
    235285
     
    254304    if (   (fFlags & RTTIMER_FLAGS_CPU_ALL) == RTTIMER_FLAGS_CPU_ALL
    255305        && u64NanoInterval == 0)
    256     {
    257306        return VERR_NOT_SUPPORTED;
    258     }
    259307
    260308    /*
    261      * Allocate and initialize the timer handle.
     309     * Allocate and initialize the timer handle.  The omni variant has a
     310     * variable sized array of ticks counts, thus the size calculation.
    262311     */
    263     PRTTIMER pTimer = (PRTTIMER)RTMemAlloc(sizeof(*pTimer));
     312    PRTTIMER pTimer = (PRTTIMER)RTMemAllocZ(  (fFlags & RTTIMER_FLAGS_CPU_ALL) == RTTIMER_FLAGS_CPU_ALL
     313                                            ? RT_OFFSETOF(RTTIMER, u.Omni.au64Ticks[RTMpGetCount()])
     314                                            : sizeof(RTTIMER));
    264315    if (!pTimer)
    265316        return VERR_NO_MEMORY;
    266317
    267318    pTimer->u32Magic = RTTIMER_MAGIC;
     319    pTimer->cRefs = 1;
    268320    pTimer->fSuspended = true;
    269321    if ((fFlags & RTTIMER_FLAGS_CPU_ALL) == RTTIMER_FLAGS_CPU_ALL)
    270322    {
    271         pTimer->fAllCpu = true;
     323        pTimer->fAllCpus = true;
    272324        pTimer->fSpecificCpu = false;
    273325        pTimer->iCpu = 255;
     
    275327    else if (fFlags & RTTIMER_FLAGS_CPU_SPECIFIC)
    276328    {
    277         pTimer->fAllCpu = false;
     329        pTimer->fAllCpus = false;
    278330        pTimer->fSpecificCpu = true;
    279331        pTimer->iCpu = fFlags & RTTIMER_FLAGS_CPU_MASK; /* ASSUMES: index == cpuid */
     
    281333    else
    282334    {
    283         pTimer->fAllCpu = false;
     335        pTimer->fAllCpus = false;
    284336        pTimer->fSpecificCpu = false;
    285337        pTimer->iCpu = 255;
    286338    }
    287     pTimer->interval = u64NanoInterval;
     339    pTimer->cNsInterval = u64NanoInterval;
    288340    pTimer->pfnTimer = pfnTimer;
    289341    pTimer->pvUser = pvUser;
    290     pTimer->pSingleTimer = NULL;
    291     pTimer->pOmniTimer = NULL;
    292342    pTimer->hCyclicId = CYCLIC_NONE;
    293343
     
    309359    RTTimerStop(pTimer);
    310360    ASMAtomicWriteU32(&pTimer->u32Magic, ~RTTIMER_MAGIC);
    311     RTMemFree(pTimer);
     361
     362    rtTimerSolRelease(pTimer);
    312363    return VINF_SUCCESS;
    313364}
     
    323374
    324375    pTimer->fSuspended = false;
    325     if (pTimer->fAllCpu)
    326     {
    327         Assert(pTimer->interval);
    328         PRTR0OMNITIMERSOL pOmniTimer = RTMemAllocZ(sizeof(RTR0OMNITIMERSOL));
    329         if (RT_UNLIKELY(!pOmniTimer))
    330             return VERR_NO_MEMORY;
    331 
    332         pOmniTimer->au64Ticks = RTMemAllocZ(RTMpGetCount() * sizeof(uint64_t));
    333         if (RT_UNLIKELY(!pOmniTimer->au64Ticks))
    334         {
    335             RTMemFree(pOmniTimer);
    336             return VERR_NO_MEMORY;
    337         }
    338 
     376    if (pTimer->fAllCpus)
     377    {
    339378        /*
    340379         * Setup omni (all CPU) timer. The Omni-CPU online event will fire
    341380         * and from there we setup periodic timers per CPU.
    342381         */
    343         pTimer->pOmniTimer = pOmniTimer;
    344         pOmniTimer->u64When     = pTimer->interval + RTTimeSystemNanoTS();
    345 
    346         cyc_omni_handler_t hOmni;
    347         hOmni.cyo_online        = rtTimerSolOmniCpuOnline;
    348         hOmni.cyo_offline       = NULL;
    349         hOmni.cyo_arg           = pTimer;
     382        pTimer->u.Omni.u64When  = pTimer->cNsInterval + RTTimeSystemNanoTS();
     383
     384        cyc_omni_handler_t HandlerOmni;
     385        HandlerOmni.cyo_online  = rtTimerSolOmniCpuOnline;
     386        HandlerOmni.cyo_offline = NULL;
     387        HandlerOmni.cyo_arg     = pTimer;
    350388
    351389        mutex_enter(&cpu_lock);
    352         pTimer->hCyclicId = cyclic_add_omni(&hOmni);
     390        pTimer->hCyclicId = cyclic_add_omni(&HandlerOmni);
    353391        mutex_exit(&cpu_lock);
    354392    }
     
    363401        }
    364402
    365         PRTR0SINGLETIMERSOL pSingleTimer = RTMemAllocZ(sizeof(RTR0SINGLETIMERSOL));
    366         if (RT_UNLIKELY(!pSingleTimer))
    367             return VERR_NO_MEMORY;
    368 
    369         pTimer->pSingleTimer = pSingleTimer;
    370         pSingleTimer->hHandler.cyh_func  = (cyc_func_t)rtTimerSolCallbackWrapper;
    371         pSingleTimer->hHandler.cyh_arg   = pTimer;
    372         pSingleTimer->hHandler.cyh_level = CY_LOCK_LEVEL;
     403        pTimer->u.Single.hHandler.cyh_func  = (cyc_func_t)rtTimerSolSingleCallbackWrapper;
     404        pTimer->u.Single.hHandler.cyh_arg   = pTimer;
     405        pTimer->u.Single.hHandler.cyh_level = CY_LOCK_LEVEL;
    373406
    374407        mutex_enter(&cpu_lock);
    375         if (   iCpu != SOL_TIMER_ANY_CPU
    376             && !cpu_is_online(cpu[iCpu]))
     408        if (RT_UNLIKELY(   iCpu != SOL_TIMER_ANY_CPU
     409                        && !cpu_is_online(cpu[iCpu])))
    377410        {
    378411            mutex_exit(&cpu_lock);
    379             RTMemFree(pSingleTimer);
    380             pTimer->pSingleTimer = NULL;
    381412            return VERR_CPU_OFFLINE;
    382413        }
    383414
    384         pSingleTimer->hFireTime.cyt_when = u64First + RTTimeSystemNanoTS();
    385         if (pTimer->interval == 0)
     415        pTimer->u.Single.hFireTime.cyt_when = u64First + RTTimeSystemNanoTS();
     416        if (pTimer->cNsInterval == 0)
    386417        {
    387418            /*
     
    390421             * a valid, special value. See cyclic_fire().
    391422             */
    392             pSingleTimer->hFireTime.cyt_interval = CY_INFINITY;
     423            pTimer->u.Single.hFireTime.cyt_interval = CY_INFINITY;
    393424        }
    394425        else
    395             pSingleTimer->hFireTime.cyt_interval = pTimer->interval;
    396 
    397         pTimer->hCyclicId = cyclic_add(&pSingleTimer->hHandler, &pSingleTimer->hFireTime);
     426            pTimer->u.Single.hFireTime.cyt_interval = pTimer->cNsInterval;
     427
     428        pTimer->hCyclicId = cyclic_add(&pTimer->u.Single.hHandler, &pTimer->u.Single.hFireTime);
    398429        if (iCpu != SOL_TIMER_ANY_CPU)
    399430            cyclic_bind(pTimer->hCyclicId, cpu[iCpu], NULL /* cpupart */);
     
    416447    /** @remarks Do -not- call this function from a timer callback,
    417448     *           cyclic_remove() will deadlock the system. */
     449    mutex_enter(&cpu_lock);
     450
    418451    pTimer->fSuspended = true;
    419     if (pTimer->pSingleTimer)
    420     {
    421         mutex_enter(&cpu_lock);
    422         cyclic_remove(pTimer->hCyclicId);
    423         mutex_exit(&cpu_lock);
    424         RTMemFree(pTimer->pSingleTimer);
    425     }
    426     else if (pTimer->pOmniTimer)
    427     {
    428         mutex_enter(&cpu_lock);
    429         cyclic_remove(pTimer->hCyclicId);
    430         mutex_exit(&cpu_lock);
    431         RTMemFree(pTimer->pOmniTimer->au64Ticks);
    432         RTMemFree(pTimer->pOmniTimer);
    433     }
     452    cyclic_remove(pTimer->hCyclicId);
     453    pTimer->hCyclicId = CYCLIC_NONE;
     454
     455    mutex_exit(&cpu_lock);
     456
    434457    return VINF_SUCCESS;
    435458}
     
    438461RTDECL(int) RTTimerChangeInterval(PRTTIMER pTimer, uint64_t u64NanoInterval)
    439462{
     463    /*
     464     * Validate.
     465     */
     466    RTTIMER_ASSERT_VALID_RET(pTimer);
     467    AssertReturn(u64NanoInterval, VERR_INVALID_PARAMETER);
     468
     469    if (pTimer->fSuspended)
     470    {
     471        pTimer->cNsInterval = u64NanoInterval;
     472        return VINF_SUCCESS;
     473    }
     474
    440475    return VERR_NOT_SUPPORTED;
    441476}
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