Changeset 40966 in vbox for trunk/src/VBox/Runtime/r0drv/solaris/vbi/timer-r0drv-solaris.c
- Timestamp:
- Apr 17, 2012 4:43:28 PM (13 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Runtime/r0drv/solaris/vbi/timer-r0drv-solaris.c
r37275 r40966 46 46 #include "internal/magics.h" 47 47 48 #define SOL_TIMER_ANY_CPU (-1) 48 49 49 50 /******************************************************************************* 50 51 * Structures and Typedefs * 51 52 *******************************************************************************/ 53 /** 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 52 79 /** 53 80 * The internal representation of a Solaris timer handle. … … 61 88 /** Flag indicating that the timer is suspended. */ 62 89 uint8_t volatile fSuspended; 63 /** Run on all CPUs if set*/90 /** Whether the timer must run on all CPUs or not. */ 64 91 uint8_t fAllCpu; 65 92 /** Whether the timer must run on a specific CPU or not. */ … … 67 94 /** The CPU it must run on if fSpecificCpu is set. */ 68 95 uint8_t iCpu; 69 /** The nano second interval for repeating timers */96 /** The nano second interval for repeating timers. */ 70 97 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; 75 106 /** The user callback. */ 76 107 PFNRTTIMER pfnTimer; … … 88 119 { \ 89 120 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); \ 91 123 } while (0) 92 124 93 125 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 */ 135 static 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 */ 166 static 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 } 103 187 104 188 … … 152 236 pTimer->pfnTimer = pfnTimer; 153 237 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); 157 243 *ppTimer = pTimer; 158 244 return VINF_SUCCESS; … … 179 265 RTDECL(int) RTTimerStart(PRTTIMER pTimer, uint64_t u64First) 180 266 { 267 cmn_err(CE_NOTE, "Start pTimer->u32Magic=%x RTTIMER_MAGIC=%x\n", pTimer->u32Magic, RTTIMER_MAGIC); 181 268 RTTIMER_ASSERT_VALID_RET(pTimer); 182 269 RT_ASSERT_INTS_ON(); … … 185 272 return VERR_TIMER_ACTIVE; 186 273 274 /* One-shot timers are not supported by the cyclic system. */ 275 if (pTimer->interval == 0) 276 return VERR_NOT_SUPPORTED; 277 187 278 pTimer->fSuspended = false; 188 279 if (pTimer->fAllCpu) 189 280 { 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); 193 307 } 194 308 else 195 309 { 196 int iCpu = VBI_ANY_CPU;310 int iCpu = SOL_TIMER_ANY_CPU; 197 311 if (pTimer->fSpecificCpu) 312 { 198 313 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])) 201 329 { 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; 205 334 } 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); 206 351 } 207 352 … … 219 364 220 365 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); 230 380 } 231 381 … … 234 384 235 385 236 237 386 RTDECL(int) RTTimerChangeInterval(PRTTIMER pTimer, uint64_t u64NanoInterval) 238 387 { … … 247 396 RTDECL(uint32_t) RTTimerGetSystemGranularity(void) 248 397 { 249 return vbi_timer_granularity();398 return nsec_per_tick; 250 399 } 251 400
Note:
See TracChangeset
for help on using the changeset viewer.