Index: /trunk/src/VBox/Runtime/r0drv/solaris/timer-r0drv-solaris.c
===================================================================
--- /trunk/src/VBox/Runtime/r0drv/solaris/timer-r0drv-solaris.c	(revision 54182)
+++ /trunk/src/VBox/Runtime/r0drv/solaris/timer-r0drv-solaris.c	(revision 54183)
@@ -52,30 +52,4 @@
 *******************************************************************************/
 /**
- * Single-CPU timer handle.
- */
-typedef struct RTR0SINGLETIMERSOL
-{
-    /** Cyclic handler. */
-    cyc_handler_t           hHandler;
-    /** Cyclic time and interval representation. */
-    cyc_time_t              hFireTime;
-    /** Timer ticks. */
-    uint64_t                u64Tick;
-} RTR0SINGLETIMERSOL;
-typedef RTR0SINGLETIMERSOL *PRTR0SINGLETIMERSOL;
-
-/**
- * Omni-CPU timer handle.
- */
-typedef struct RTR0OMNITIMERSOL
-{
-    /** Absolute timestamp of when the timer should fire next. */
-    uint64_t                u64When;
-    /** Array of timer ticks per CPU. Reinitialized when a CPU is online'd. */
-    uint64_t               *au64Ticks;
-} RTR0OMNITIMERSOL;
-typedef RTR0OMNITIMERSOL *PRTR0OMNITIMERSOL;
-
-/**
  * The internal representation of a Solaris timer handle.
  */
@@ -86,8 +60,10 @@
      * is destroyed to indicate clearly that thread should exit. */
     uint32_t volatile       u32Magic;
+    /** Reference counter. */
+    uint32_t volatile       cRefs;
     /** Flag indicating that the timer is suspended. */
     uint8_t volatile        fSuspended;
     /** Whether the timer must run on all CPUs or not. */
-    uint8_t                 fAllCpu;
+    uint8_t                 fAllCpus;
     /** Whether the timer must run on a specific CPU or not. */
     uint8_t                 fSpecificCpu;
@@ -95,17 +71,35 @@
     uint8_t                 iCpu;
     /** The nano second interval for repeating timers. */
-    uint64_t                interval;
+    uint64_t                cNsInterval;
     /** Cyclic timer Id. */
     cyclic_id_t             hCyclicId;
-    /** @todo Make this a union unless we intend to support omni<=>single timers
-     *        conversions. */
-    /** Single-CPU timer handle. */
-    PRTR0SINGLETIMERSOL     pSingleTimer;
-    /** Omni-CPU timer handle. */
-    PRTR0OMNITIMERSOL       pOmniTimer;
     /** The user callback. */
     PFNRTTIMER              pfnTimer;
     /** The argument for the user callback. */
     void                   *pvUser;
+    /** Union with timer type specific data. */
+    union
+    {
+        /** Single timer (fAllCpus == false). */
+        struct
+        {
+            /** Cyclic handler. */
+            cyc_handler_t   hHandler;
+            /** Cyclic time and interval representation. */
+            cyc_time_t      hFireTime;
+            /** Timer ticks. */
+            uint64_t        u64Tick;
+        } Single;
+
+        /** Omni timer (fAllCpus == true). */
+        struct
+        {
+             /** Absolute timestamp of when the timer should fire next. */
+            uint64_t        u64When;
+            /** Array of timer ticks per CPU. Reinitialized when a CPU is online'd
+             *  (variable size). */
+            uint64_t        au64Ticks[1];
+        } Omni;
+    } u;
 } RTTIMER;
 
@@ -124,7 +118,49 @@
 
 
-/**
- * Callback wrapper for specific timers if they happened to have been fired on
- * the wrong CPU. See rtTimerSolCallbackWrapper().
+
+/**
+ * Retains a reference to the timer.
+ *
+ * @returns New reference counter value.
+ * @param   pTimer              The timer.
+ */
+DECLINLINE(uint32_t) rtTimerSolRetain(PRTTIMER pTimer)
+{
+    return ASMAtomicIncU32(&pTimer->cRefs);
+}
+
+
+/**
+ * Destroys the timer when the reference counter has reached zero.
+ *
+ * @returns 0 (new references counter value).
+ * @param   pTimer              The timer.
+ */
+static uint32_t rtTimeSolReleaseCleanup(PRTTIMER pTimer)
+{
+    Assert(pTimer->hCyclicId == CYCLIC_NONE);
+    ASMAtomicWriteU32(&pTimer->u32Magic, ~RTTIMER_MAGIC);
+    RTMemFree(pTimer);
+}
+
+
+/**
+ * Releases a reference to the timer.
+ *
+ * @returns New reference counter value.
+ * @param   pTimer              The timer.
+ */
+DECLINLINE(uint32_t) rtTimerSolRelease(PRTTIMER pTimer)
+{
+    uint32_t cRefs = ASMAtomicDecU32(&pTimer->cRefs);
+    if (!cRefs)
+        return rtTimeSolReleaseCleanup(pTimer);
+    return cRefs;
+}
+
+
+/**
+ * RTMpOnSpecific callback used by rtTimerSolCallbackWrapper() to deal with
+ * callouts on the wrong CPU (race with cyclic_bind).
  *
  * @param   idCpu       The CPU this is fired on.
@@ -138,16 +174,16 @@
     Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
     Assert(pTimer->iCpu == RTMpCpuId());    /* ASSUMES: index == cpuid */
-    Assert(pTimer->pSingleTimer);
+    Assert(!pTimer->fAllCpus);
     NOREF(pvUser2);
 
     /* Make sure one-shots do not fire another time. */
     Assert(   !pTimer->fSuspended
-           || pTimer->interval != 0);
+           || pTimer->cNsInterval != 0);
 
     /* For one-shot specific timers, allow RTTimer to restart them. */
-    if (pTimer->interval == 0)
+    if (pTimer->cNsInterval == 0)
         pTimer->fSuspended = true;
 
-    uint64_t u64Tick = ++pTimer->pSingleTimer->u64Tick;
+    uint64_t u64Tick = ++pTimer->u.Single.u64Tick;
     pTimer->pfnTimer(pTimer, pTimer->pvUser, u64Tick);
 }
@@ -155,5 +191,5 @@
 
 /**
- * Callback wrapper for Omni-CPU and single-CPU timers.
+ * Callback wrapper for single-CPU timers.
  *
  * @param    pvArg              Opaque pointer to the timer.
@@ -163,37 +199,51 @@
  *          cyclic subsystem here, neither should pfnTimer().
  */
-static void rtTimerSolCallbackWrapper(void *pvArg)
+static void rtTimerSolSingleCallbackWrapper(void *pvArg)
 {
     PRTTIMER pTimer = (PRTTIMER)pvArg;
     AssertPtrReturnVoid(pTimer);
     Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
-
-    if (pTimer->pSingleTimer)
-    {
-        /* Make sure one-shots do not fire another time. */
-        Assert(   !pTimer->fSuspended
-               || pTimer->interval != 0);
-
-        /* For specific timers, we might fire on the wrong CPU between cyclic_add() and cyclic_bind().
-           Redirect these shots to the right CPU as we are temporarily rebinding to the right CPU. */
-        if (   pTimer->fSpecificCpu
-            && pTimer->iCpu != RTMpCpuId())          /* ASSUMES: index == cpuid */
-        {
-            RTMpOnSpecific(pTimer->iCpu, rtTimerSolMpCallbackWrapper, pTimer, NULL);
-            return;
-        }
-
-        /* For one-shot any-cpu timers, allow RTTimer to restart them. */
-        if (pTimer->interval == 0)
-            pTimer->fSuspended = true;
-
-        uint64_t u64Tick = ++pTimer->pSingleTimer->u64Tick;
-        pTimer->pfnTimer(pTimer, pTimer->pvUser, u64Tick);
-    }
-    else if (pTimer->pOmniTimer)
-    {
-        uint64_t u64Tick = ++pTimer->pOmniTimer->au64Ticks[CPU->cpu_id];
-        pTimer->pfnTimer(pTimer, pTimer->pvUser, u64Tick);
-    }
+    Assert(!pTimer->fAllCpus);
+
+    /* Make sure one-shots do not fire another time. */
+    Assert(   !pTimer->fSuspended
+           || pTimer->cNsInterval != 0);
+
+    /* For specific timers, we might fire on the wrong CPU between cyclic_add() and cyclic_bind().
+       Redirect these shots to the right CPU as we are temporarily rebinding to the right CPU. */
+    if (   pTimer->fSpecificCpu
+        && pTimer->iCpu != RTMpCpuId())          /* ASSUMES: index == cpuid */
+    {
+        RTMpOnSpecific(pTimer->iCpu, rtTimerSolMpCallbackWrapper, pTimer, NULL);
+        return;
+    }
+
+    /* For one-shot any-cpu timers, allow RTTimer to restart them. */
+    if (pTimer->cNsInterval == 0)
+        pTimer->fSuspended = true;
+
+    uint64_t u64Tick = ++pTimer->u.Single.u64Tick;
+    pTimer->pfnTimer(pTimer, pTimer->pvUser, u64Tick);
+}
+
+
+/**
+ * Callback wrapper for Omni-CPU timers.
+ *
+ * @param    pvArg              Opaque pointer to the timer.
+ *
+ * @remarks This will be executed in interrupt context but only at the specified
+ *          level i.e. CY_LOCK_LEVEL in our case. We -CANNOT- call into the
+ *          cyclic subsystem here, neither should pfnTimer().
+ */
+static void rtTimerSolOmniCallbackWrapper(void *pvArg)
+{
+    PRTTIMER pTimer = (PRTTIMER)pvArg;
+    AssertPtrReturnVoid(pTimer);
+    Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
+    Assert(pTimer->fAllCpus);
+
+    uint64_t u64Tick = ++pTimer->u.Omni.au64Ticks[CPU->cpu_id];
+    pTimer->pfnTimer(pTimer, pTimer->pvUser, u64Tick);
 }
 
@@ -220,16 +270,16 @@
     AssertPtrReturnVoid(pCyclicTime);
 
-    pTimer->pOmniTimer->au64Ticks[pCpu->cpu_id] = 0;
-    pCyclicHandler->cyh_func  = (cyc_func_t)rtTimerSolCallbackWrapper;
+    pTimer->u.Omni.au64Ticks[pCpu->cpu_id] = 0;
+    pCyclicHandler->cyh_func  = (cyc_func_t)rtTimerSolOmniCallbackWrapper;
     pCyclicHandler->cyh_arg   = pTimer;
     pCyclicHandler->cyh_level = CY_LOCK_LEVEL;
 
     uint64_t u64Now = RTTimeSystemNanoTS();
-    if (pTimer->pOmniTimer->u64When < u64Now)
-        pCyclicTime->cyt_when = u64Now + pTimer->interval / 2;
+    if (pTimer->u.Omni.u64When < u64Now)
+        pCyclicTime->cyt_when = u64Now + pTimer->cNsInterval / 2;
     else
-        pCyclicTime->cyt_when = pTimer->pOmniTimer->u64When;
-
-    pCyclicTime->cyt_interval = pTimer->interval;
+        pCyclicTime->cyt_when = pTimer->u.Omni.u64When;
+
+    pCyclicTime->cyt_interval = pTimer->cNsInterval;
 }
 
@@ -254,20 +304,22 @@
     if (   (fFlags & RTTIMER_FLAGS_CPU_ALL) == RTTIMER_FLAGS_CPU_ALL
         && u64NanoInterval == 0)
-    {
         return VERR_NOT_SUPPORTED;
-    }
 
     /*
-     * Allocate and initialize the timer handle.
+     * Allocate and initialize the timer handle.  The omni variant has a
+     * variable sized array of ticks counts, thus the size calculation.
      */
-    PRTTIMER pTimer = (PRTTIMER)RTMemAlloc(sizeof(*pTimer));
+    PRTTIMER pTimer = (PRTTIMER)RTMemAllocZ(  (fFlags & RTTIMER_FLAGS_CPU_ALL) == RTTIMER_FLAGS_CPU_ALL
+                                            ? RT_OFFSETOF(RTTIMER, u.Omni.au64Ticks[RTMpGetCount()])
+                                            : sizeof(RTTIMER));
     if (!pTimer)
         return VERR_NO_MEMORY;
 
     pTimer->u32Magic = RTTIMER_MAGIC;
+    pTimer->cRefs = 1;
     pTimer->fSuspended = true;
     if ((fFlags & RTTIMER_FLAGS_CPU_ALL) == RTTIMER_FLAGS_CPU_ALL)
     {
-        pTimer->fAllCpu = true;
+        pTimer->fAllCpus = true;
         pTimer->fSpecificCpu = false;
         pTimer->iCpu = 255;
@@ -275,5 +327,5 @@
     else if (fFlags & RTTIMER_FLAGS_CPU_SPECIFIC)
     {
-        pTimer->fAllCpu = false;
+        pTimer->fAllCpus = false;
         pTimer->fSpecificCpu = true;
         pTimer->iCpu = fFlags & RTTIMER_FLAGS_CPU_MASK; /* ASSUMES: index == cpuid */
@@ -281,13 +333,11 @@
     else
     {
-        pTimer->fAllCpu = false;
+        pTimer->fAllCpus = false;
         pTimer->fSpecificCpu = false;
         pTimer->iCpu = 255;
     }
-    pTimer->interval = u64NanoInterval;
+    pTimer->cNsInterval = u64NanoInterval;
     pTimer->pfnTimer = pfnTimer;
     pTimer->pvUser = pvUser;
-    pTimer->pSingleTimer = NULL;
-    pTimer->pOmniTimer = NULL;
     pTimer->hCyclicId = CYCLIC_NONE;
 
@@ -309,5 +359,6 @@
     RTTimerStop(pTimer);
     ASMAtomicWriteU32(&pTimer->u32Magic, ~RTTIMER_MAGIC);
-    RTMemFree(pTimer);
+
+    rtTimerSolRelease(pTimer);
     return VINF_SUCCESS;
 }
@@ -323,32 +374,19 @@
 
     pTimer->fSuspended = false;
-    if (pTimer->fAllCpu)
-    {
-        Assert(pTimer->interval);
-        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;
-        }
-
+    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->pOmniTimer = pOmniTimer;
-        pOmniTimer->u64When     = pTimer->interval + RTTimeSystemNanoTS();
-
-        cyc_omni_handler_t hOmni;
-        hOmni.cyo_online        = rtTimerSolOmniCpuOnline;
-        hOmni.cyo_offline       = NULL;
-        hOmni.cyo_arg           = pTimer;
+        pTimer->u.Omni.u64When  = pTimer->cNsInterval + RTTimeSystemNanoTS();
+
+        cyc_omni_handler_t HandlerOmni;
+        HandlerOmni.cyo_online  = rtTimerSolOmniCpuOnline;
+        HandlerOmni.cyo_offline = NULL;
+        HandlerOmni.cyo_arg     = pTimer;
 
         mutex_enter(&cpu_lock);
-        pTimer->hCyclicId = cyclic_add_omni(&hOmni);
+        pTimer->hCyclicId = cyclic_add_omni(&HandlerOmni);
         mutex_exit(&cpu_lock);
     }
@@ -363,25 +401,18 @@
         }
 
-        PRTR0SINGLETIMERSOL pSingleTimer = RTMemAllocZ(sizeof(RTR0SINGLETIMERSOL));
-        if (RT_UNLIKELY(!pSingleTimer))
-            return VERR_NO_MEMORY;
-
-        pTimer->pSingleTimer = pSingleTimer;
-        pSingleTimer->hHandler.cyh_func  = (cyc_func_t)rtTimerSolCallbackWrapper;
-        pSingleTimer->hHandler.cyh_arg   = pTimer;
-        pSingleTimer->hHandler.cyh_level = CY_LOCK_LEVEL;
+        pTimer->u.Single.hHandler.cyh_func  = (cyc_func_t)rtTimerSolSingleCallbackWrapper;
+        pTimer->u.Single.hHandler.cyh_arg   = pTimer;
+        pTimer->u.Single.hHandler.cyh_level = CY_LOCK_LEVEL;
 
         mutex_enter(&cpu_lock);
-        if (   iCpu != SOL_TIMER_ANY_CPU
-            && !cpu_is_online(cpu[iCpu]))
+        if (RT_UNLIKELY(   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 + RTTimeSystemNanoTS();
-        if (pTimer->interval == 0)
+        pTimer->u.Single.hFireTime.cyt_when = u64First + RTTimeSystemNanoTS();
+        if (pTimer->cNsInterval == 0)
         {
             /*
@@ -390,10 +421,10 @@
              * a valid, special value. See cyclic_fire().
              */
-            pSingleTimer->hFireTime.cyt_interval = CY_INFINITY;
+            pTimer->u.Single.hFireTime.cyt_interval = CY_INFINITY;
         }
         else
-            pSingleTimer->hFireTime.cyt_interval = pTimer->interval;
-
-        pTimer->hCyclicId = cyclic_add(&pSingleTimer->hHandler, &pSingleTimer->hFireTime);
+            pTimer->u.Single.hFireTime.cyt_interval = pTimer->cNsInterval;
+
+        pTimer->hCyclicId = cyclic_add(&pTimer->u.Single.hHandler, &pTimer->u.Single.hFireTime);
         if (iCpu != SOL_TIMER_ANY_CPU)
             cyclic_bind(pTimer->hCyclicId, cpu[iCpu], NULL /* cpupart */);
@@ -416,20 +447,12 @@
     /** @remarks Do -not- call this function from a timer callback,
      *           cyclic_remove() will deadlock the system. */
+    mutex_enter(&cpu_lock);
+
     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);
-    }
+    cyclic_remove(pTimer->hCyclicId);
+    pTimer->hCyclicId = CYCLIC_NONE;
+
+    mutex_exit(&cpu_lock);
+
     return VINF_SUCCESS;
 }
@@ -438,4 +461,16 @@
 RTDECL(int) RTTimerChangeInterval(PRTTIMER pTimer, uint64_t u64NanoInterval)
 {
+    /*
+     * Validate.
+     */
+    RTTIMER_ASSERT_VALID_RET(pTimer);
+    AssertReturn(u64NanoInterval, VERR_INVALID_PARAMETER);
+
+    if (pTimer->fSuspended)
+    {
+        pTimer->cNsInterval = u64NanoInterval;
+        return VINF_SUCCESS;
+    }
+
     return VERR_NOT_SUPPORTED;
 }
