Changeset 54183 in vbox for trunk/src/VBox/Runtime/r0drv/solaris/timer-r0drv-solaris.c
- Timestamp:
- Feb 12, 2015 8:50:29 PM (10 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Runtime/r0drv/solaris/timer-r0drv-solaris.c
r53404 r54183 52 52 *******************************************************************************/ 53 53 /** 54 * Single-CPU timer handle.55 */56 typedef struct RTR0SINGLETIMERSOL57 {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 RTR0OMNITIMERSOL71 {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 /**80 54 * The internal representation of a Solaris timer handle. 81 55 */ … … 86 60 * is destroyed to indicate clearly that thread should exit. */ 87 61 uint32_t volatile u32Magic; 62 /** Reference counter. */ 63 uint32_t volatile cRefs; 88 64 /** Flag indicating that the timer is suspended. */ 89 65 uint8_t volatile fSuspended; 90 66 /** Whether the timer must run on all CPUs or not. */ 91 uint8_t fAllCpu ;67 uint8_t fAllCpus; 92 68 /** Whether the timer must run on a specific CPU or not. */ 93 69 uint8_t fSpecificCpu; … … 95 71 uint8_t iCpu; 96 72 /** The nano second interval for repeating timers. */ 97 uint64_t interval;73 uint64_t cNsInterval; 98 74 /** Cyclic timer Id. */ 99 75 cyclic_id_t hCyclicId; 100 /** @todo Make this a union unless we intend to support omni<=>single timers101 * conversions. */102 /** Single-CPU timer handle. */103 PRTR0SINGLETIMERSOL pSingleTimer;104 /** Omni-CPU timer handle. */105 PRTR0OMNITIMERSOL pOmniTimer;106 76 /** The user callback. */ 107 77 PFNRTTIMER pfnTimer; 108 78 /** The argument for the user callback. */ 109 79 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; 110 104 } RTTIMER; 111 105 … … 124 118 125 119 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 */ 127 DECLINLINE(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 */ 139 static 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 */ 153 DECLINLINE(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). 129 165 * 130 166 * @param idCpu The CPU this is fired on. … … 138 174 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD)); 139 175 Assert(pTimer->iCpu == RTMpCpuId()); /* ASSUMES: index == cpuid */ 140 Assert( pTimer->pSingleTimer);176 Assert(!pTimer->fAllCpus); 141 177 NOREF(pvUser2); 142 178 143 179 /* Make sure one-shots do not fire another time. */ 144 180 Assert( !pTimer->fSuspended 145 || pTimer-> interval != 0);181 || pTimer->cNsInterval != 0); 146 182 147 183 /* For one-shot specific timers, allow RTTimer to restart them. */ 148 if (pTimer-> interval == 0)184 if (pTimer->cNsInterval == 0) 149 185 pTimer->fSuspended = true; 150 186 151 uint64_t u64Tick = ++pTimer-> pSingleTimer->u64Tick;187 uint64_t u64Tick = ++pTimer->u.Single.u64Tick; 152 188 pTimer->pfnTimer(pTimer, pTimer->pvUser, u64Tick); 153 189 } … … 155 191 156 192 /** 157 * Callback wrapper for Omni-CPU andsingle-CPU timers.193 * Callback wrapper for single-CPU timers. 158 194 * 159 195 * @param pvArg Opaque pointer to the timer. … … 163 199 * cyclic subsystem here, neither should pfnTimer(). 164 200 */ 165 static void rtTimerSol CallbackWrapper(void *pvArg)201 static void rtTimerSolSingleCallbackWrapper(void *pvArg) 166 202 { 167 203 PRTTIMER pTimer = (PRTTIMER)pvArg; 168 204 AssertPtrReturnVoid(pTimer); 169 205 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 */ 239 static 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); 198 248 } 199 249 … … 220 270 AssertPtrReturnVoid(pCyclicTime); 221 271 222 pTimer-> pOmniTimer->au64Ticks[pCpu->cpu_id] = 0;223 pCyclicHandler->cyh_func = (cyc_func_t)rtTimerSol CallbackWrapper;272 pTimer->u.Omni.au64Ticks[pCpu->cpu_id] = 0; 273 pCyclicHandler->cyh_func = (cyc_func_t)rtTimerSolOmniCallbackWrapper; 224 274 pCyclicHandler->cyh_arg = pTimer; 225 275 pCyclicHandler->cyh_level = CY_LOCK_LEVEL; 226 276 227 277 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; 230 280 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; 234 284 } 235 285 … … 254 304 if ( (fFlags & RTTIMER_FLAGS_CPU_ALL) == RTTIMER_FLAGS_CPU_ALL 255 305 && u64NanoInterval == 0) 256 {257 306 return VERR_NOT_SUPPORTED; 258 }259 307 260 308 /* 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. 262 311 */ 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)); 264 315 if (!pTimer) 265 316 return VERR_NO_MEMORY; 266 317 267 318 pTimer->u32Magic = RTTIMER_MAGIC; 319 pTimer->cRefs = 1; 268 320 pTimer->fSuspended = true; 269 321 if ((fFlags & RTTIMER_FLAGS_CPU_ALL) == RTTIMER_FLAGS_CPU_ALL) 270 322 { 271 pTimer->fAllCpu = true;323 pTimer->fAllCpus = true; 272 324 pTimer->fSpecificCpu = false; 273 325 pTimer->iCpu = 255; … … 275 327 else if (fFlags & RTTIMER_FLAGS_CPU_SPECIFIC) 276 328 { 277 pTimer->fAllCpu = false;329 pTimer->fAllCpus = false; 278 330 pTimer->fSpecificCpu = true; 279 331 pTimer->iCpu = fFlags & RTTIMER_FLAGS_CPU_MASK; /* ASSUMES: index == cpuid */ … … 281 333 else 282 334 { 283 pTimer->fAllCpu = false;335 pTimer->fAllCpus = false; 284 336 pTimer->fSpecificCpu = false; 285 337 pTimer->iCpu = 255; 286 338 } 287 pTimer-> interval = u64NanoInterval;339 pTimer->cNsInterval = u64NanoInterval; 288 340 pTimer->pfnTimer = pfnTimer; 289 341 pTimer->pvUser = pvUser; 290 pTimer->pSingleTimer = NULL;291 pTimer->pOmniTimer = NULL;292 342 pTimer->hCyclicId = CYCLIC_NONE; 293 343 … … 309 359 RTTimerStop(pTimer); 310 360 ASMAtomicWriteU32(&pTimer->u32Magic, ~RTTIMER_MAGIC); 311 RTMemFree(pTimer); 361 362 rtTimerSolRelease(pTimer); 312 363 return VINF_SUCCESS; 313 364 } … … 323 374 324 375 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 { 339 378 /* 340 379 * Setup omni (all CPU) timer. The Omni-CPU online event will fire 341 380 * and from there we setup periodic timers per CPU. 342 381 */ 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; 350 388 351 389 mutex_enter(&cpu_lock); 352 pTimer->hCyclicId = cyclic_add_omni(& hOmni);390 pTimer->hCyclicId = cyclic_add_omni(&HandlerOmni); 353 391 mutex_exit(&cpu_lock); 354 392 } … … 363 401 } 364 402 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; 373 406 374 407 mutex_enter(&cpu_lock); 375 if ( iCpu != SOL_TIMER_ANY_CPU376 && !cpu_is_online(cpu[iCpu]))408 if (RT_UNLIKELY( iCpu != SOL_TIMER_ANY_CPU 409 && !cpu_is_online(cpu[iCpu]))) 377 410 { 378 411 mutex_exit(&cpu_lock); 379 RTMemFree(pSingleTimer);380 pTimer->pSingleTimer = NULL;381 412 return VERR_CPU_OFFLINE; 382 413 } 383 414 384 p SingleTimer->hFireTime.cyt_when = u64First + RTTimeSystemNanoTS();385 if (pTimer-> interval == 0)415 pTimer->u.Single.hFireTime.cyt_when = u64First + RTTimeSystemNanoTS(); 416 if (pTimer->cNsInterval == 0) 386 417 { 387 418 /* … … 390 421 * a valid, special value. See cyclic_fire(). 391 422 */ 392 p SingleTimer->hFireTime.cyt_interval = CY_INFINITY;423 pTimer->u.Single.hFireTime.cyt_interval = CY_INFINITY; 393 424 } 394 425 else 395 p SingleTimer->hFireTime.cyt_interval = pTimer->interval;396 397 pTimer->hCyclicId = cyclic_add(&p SingleTimer->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); 398 429 if (iCpu != SOL_TIMER_ANY_CPU) 399 430 cyclic_bind(pTimer->hCyclicId, cpu[iCpu], NULL /* cpupart */); … … 416 447 /** @remarks Do -not- call this function from a timer callback, 417 448 * cyclic_remove() will deadlock the system. */ 449 mutex_enter(&cpu_lock); 450 418 451 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 434 457 return VINF_SUCCESS; 435 458 } … … 438 461 RTDECL(int) RTTimerChangeInterval(PRTTIMER pTimer, uint64_t u64NanoInterval) 439 462 { 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 440 475 return VERR_NOT_SUPPORTED; 441 476 }
Note:
See TracChangeset
for help on using the changeset viewer.