Changeset 80665 in vbox for trunk/src/VBox/Runtime/generic/timerlr-generic.cpp
- Timestamp:
- Sep 9, 2019 10:43:23 AM (5 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Runtime/generic/timerlr-generic.cpp
r76553 r80665 47 47 48 48 /********************************************************************************************************************************* 49 * Defined Constants And Macros * 50 *********************************************************************************************************************************/ 51 /** The smallest interval for low resolution timers. */ 52 #define RTTIMERLR_MIN_INTERVAL RT_NS_100MS 53 54 55 /********************************************************************************************************************************* 49 56 * Structures and Typedefs * 50 57 *********************************************************************************************************************************/ … … 62 69 /** Flag indicating that the timer has been destroyed. */ 63 70 bool volatile fDestroyed; 71 /** Set when the thread is blocked. */ 72 bool volatile fBlocked; 73 bool fPadding; 74 /** The timer interval. 0 if one-shot. */ 75 uint64_t volatile u64NanoInterval; 76 /** The start of the current run (ns). 77 * This is used to calculate when the timer ought to fire the next time. */ 78 uint64_t volatile u64StartTS; 79 /** The start of the current run (ns). 80 * This is used to calculate when the timer ought to fire the next time. */ 81 uint64_t volatile u64NextTS; 82 /** The current tick number (since u64StartTS). */ 83 uint64_t volatile iTick; 84 64 85 /** Callback. */ 65 86 PFNRTTIMERLR pfnTimer; … … 70 91 /** Event semaphore on which the thread is blocked. */ 71 92 RTSEMEVENT hEvent; 72 /** The timer interval. 0 if one-shot. */73 uint64_t u64NanoInterval;74 /** The start of the current run (ns).75 * This is used to calculate when the timer ought to fire the next time. */76 uint64_t volatile u64StartTS;77 /** The start of the current run (ns).78 * This is used to calculate when the timer ought to fire the next time. */79 uint64_t volatile u64NextTS;80 /** The current tick number (since u64StartTS). */81 uint64_t volatile iTick;82 93 } RTTIMERLRINT; 83 94 typedef RTTIMERLRINT *PRTTIMERLRINT; … … 98 109 * We don't support the fancy MP features, nor intervals lower than 100 ms. 99 110 */ 100 if (fFlags & RTTIMER_FLAGS_CPU_SPECIFIC) 101 return VERR_NOT_SUPPORTED; 102 if (u64NanoInterval && u64NanoInterval < 100*1000*1000) 103 return VERR_INVALID_PARAMETER; 111 AssertReturn(!(fFlags & RTTIMER_FLAGS_CPU_SPECIFIC), VERR_NOT_SUPPORTED); 112 AssertReturn(!u64NanoInterval || u64NanoInterval >= RTTIMERLR_MIN_INTERVAL, VERR_OUT_OF_RANGE); 104 113 105 114 /* … … 113 122 pThis->fSuspended = true; 114 123 pThis->fDestroyed = false; 124 pThis->fBlocked = false; 125 pThis->fPadding = false; 115 126 pThis->pfnTimer = pfnTimer; 116 127 pThis->pvUser = pvUser; … … 173 184 174 185 175 RTDECL(int) RTTimerLRStart(RTTIMERLR hTimerLR, uint64_t u64First) 176 { 177 /* 178 * Validate input. 179 */ 180 PRTTIMERLRINT pThis = hTimerLR; 181 AssertPtrReturn(pThis, VERR_INVALID_HANDLE); 182 AssertReturn(pThis->u32Magic == RTTIMERLR_MAGIC, VERR_INVALID_HANDLE); 183 AssertReturn(!pThis->fDestroyed, VERR_INVALID_HANDLE); 184 185 if (u64First && u64First < 100*1000*1000) 186 return VERR_INVALID_PARAMETER; 187 186 /** 187 * Internal worker fro RTTimerLRStart and RTTiemrLRChangeInterval. 188 */ 189 static int rtTimerLRStart(PRTTIMERLRINT pThis, uint64_t u64First) 190 { 188 191 if (!pThis->fSuspended) 189 192 return VERR_TIMER_ACTIVE; … … 203 206 return rc; 204 207 } 205 RT_EXPORT_SYMBOL(RTTimerLRStart); 206 207 208 RTDECL(int) RTTimerLRStop(RTTIMERLR hTimerLR) 208 209 210 RTDECL(int) RTTimerLRStart(RTTIMERLR hTimerLR, uint64_t u64First) 209 211 { 210 212 /* … … 215 217 AssertReturn(pThis->u32Magic == RTTIMERLR_MAGIC, VERR_INVALID_HANDLE); 216 218 AssertReturn(!pThis->fDestroyed, VERR_INVALID_HANDLE); 217 219 AssertReturn(!u64First || u64First >= RTTIMERLR_MIN_INTERVAL, VERR_OUT_OF_RANGE); 220 221 /* 222 * Do the job. 223 */ 224 return rtTimerLRStart(pThis, u64First); 225 } 226 RT_EXPORT_SYMBOL(RTTimerLRStart); 227 228 229 /** 230 * Internal worker for RTTimerLRStop and RTTimerLRChangeInterval 231 */ 232 static int rtTimerLRStop(PRTTIMERLRINT pThis, bool fSynchronous) 233 { 234 /* 235 * Fail if already suspended. 236 */ 218 237 if (pThis->fSuspended) 219 238 return VERR_TIMER_SUSPENDED; … … 221 240 /* 222 241 * Mark it as suspended and kick the thread. 223 */ 242 * It's simpler to always reset the thread user semaphore, so we do that first. 243 */ 244 int rc = RTThreadUserReset(pThis->hThread); 245 AssertRC(rc); 246 224 247 ASMAtomicWriteBool(&pThis->fSuspended, true); 225 intrc = RTSemEventSignal(pThis->hEvent);248 rc = RTSemEventSignal(pThis->hEvent); 226 249 if (rc == VERR_ALREADY_POSTED) 227 250 rc = VINF_SUCCESS; 228 251 AssertRC(rc); 252 253 /* 254 * Wait for the thread to stop running if synchronous. 255 */ 256 if (fSynchronous && RT_SUCCESS(rc)) 257 { 258 rc = RTThreadUserWait(pThis->hThread, RT_MS_1MIN); 259 AssertRC(rc); 260 } 261 229 262 return rc; 230 263 } 231 RT_EXPORT_SYMBOL(RTTimerLRStop); 232 233 RTDECL(int) RTTimerLRChangeInterval(RTTIMERLR hTimerLR, uint64_t u64NanoInterval) 234 { 264 265 266 RTDECL(int) RTTimerLRStop(RTTIMERLR hTimerLR) 267 { 268 /* 269 * Validate input. 270 */ 235 271 PRTTIMERLRINT pThis = hTimerLR; 236 272 AssertPtrReturn(pThis, VERR_INVALID_HANDLE); … … 238 274 AssertReturn(!pThis->fDestroyed, VERR_INVALID_HANDLE); 239 275 240 if (u64NanoInterval && u64NanoInterval < 100*1000*1000) 241 return VERR_INVALID_PARAMETER; 242 243 #if 0 244 if (!pThis->fSuspended) 245 { 246 int rc = RTTimerLRStop(hTimerLR); 247 if (RT_FAILURE(rc)) 248 return rc; 249 276 /* 277 * Do the job. 278 */ 279 return rtTimerLRStop(pThis, false); 280 } 281 RT_EXPORT_SYMBOL(RTTimerLRStop); 282 283 284 RTDECL(int) RTTimerLRChangeInterval(RTTIMERLR hTimerLR, uint64_t u64NanoInterval) 285 { 286 /* 287 * Validate input. 288 */ 289 PRTTIMERLRINT pThis = hTimerLR; 290 AssertPtrReturn(pThis, VERR_INVALID_HANDLE); 291 AssertReturn(pThis->u32Magic == RTTIMERLR_MAGIC, VERR_INVALID_HANDLE); 292 AssertReturn(!pThis->fDestroyed, VERR_INVALID_HANDLE); 293 AssertReturn(!u64NanoInterval || u64NanoInterval >= RTTIMERLR_MIN_INTERVAL, VERR_OUT_OF_RANGE); 294 295 /* 296 * Do the job accoring to state and caller. 297 */ 298 int rc; 299 if (pThis->fSuspended) 300 { 301 /* Stopped: Just update the interval. */ 250 302 ASMAtomicWriteU64(&pThis->u64NanoInterval, u64NanoInterval); 251 252 rc = RTTimerLRStart(hTimerLR, 0); 253 if (RT_FAILURE(rc)) 254 return rc; 303 rc = VINF_SUCCESS; 304 } 305 else if (RTThreadSelf() == pThis->hThread) 306 { 307 /* Running: Updating interval from the callback. */ 308 uint64_t u64Now = RTTimeNanoTS(); 309 pThis->iTick = 0; 310 pThis->u64StartTS = u64Now; 311 pThis->u64NextTS = u64Now; 312 ASMAtomicWriteU64(&pThis->u64NanoInterval, u64NanoInterval); 313 rc = VINF_SUCCESS; 255 314 } 256 315 else 257 #endif 258 {259 uint64_t u64Now = RTTimeNanoTS();260 ASMAtomicWriteU64(&pThis->iTick, 0);261 ASMAtomicWriteU64(&pThis->u64StartTS, u64Now);262 ASMAtomicWriteU64(&pThis->u64NextTS, u64Now);263 ASMAtomicWriteU64(&pThis->u64NanoInterval, u64NanoInterval);264 RTSemEventSignal(pThis->hEvent);265 } 266 267 return VINF_SUCCESS;316 { 317 /* Running: Stopping */ 318 rc = rtTimerLRStop(pThis, true); 319 if (RT_SUCCESS(rc)) 320 { 321 ASMAtomicWriteU64(&pThis->u64NanoInterval, u64NanoInterval); 322 rc = rtTimerLRStart(pThis, 0); 323 } 324 } 325 326 return rc; 268 327 } 269 328 RT_EXPORT_SYMBOL(RTTimerLRChangeInterval); 329 270 330 271 331 static DECLCALLBACK(int) rtTimerLRThread(RTTHREAD hThreadSelf, void *pvUser) … … 281 341 if (ASMAtomicUoReadBool(&pThis->fSuspended)) 282 342 { 283 int rc = RTSemEventWait(pThis->hEvent, RT_INDEFINITE_WAIT); 343 /* Signal rtTimerLRStop thread. */ 344 int rc = RTThreadUserSignal(hThreadSelf); 345 AssertRC(rc); 346 347 ASMAtomicWriteBool(&pThis->fBlocked, true); 348 rc = RTSemEventWait(pThis->hEvent, RT_INDEFINITE_WAIT); 284 349 if (RT_FAILURE(rc) && rc != VERR_INTERRUPTED) 285 350 { … … 287 352 RTThreadSleep(1000); /* Don't cause trouble! */ 288 353 } 354 ASMAtomicWriteBool(&pThis->fBlocked, false); 289 355 } 290 356 else … … 292 358 uint64_t cNanoSeconds; 293 359 const uint64_t u64NanoTS = RTTimeNanoTS(); 294 if (u64NanoTS >= pThis->u64NextTS) 360 uint64_t u64NextTS = pThis->u64NextTS; 361 if (u64NanoTS >= u64NextTS) 295 362 { 296 pThis->iTick++;297 pThis->pfnTimer(pThis, pThis->pvUser, pThis->iTick);363 uint64_t iTick = ++pThis->iTick; 364 pThis->pfnTimer(pThis, pThis->pvUser, iTick); 298 365 299 366 /* status changed? */ 300 if ( 301 || 367 if ( ASMAtomicUoReadBool(&pThis->fSuspended) 368 || ASMAtomicUoReadBool(&pThis->fDestroyed)) 302 369 continue; 303 370 304 /* one shot? */ 305 if (!pThis->u64NanoInterval) 371 /* 372 * Read timer data (it's all volatile and better if we read it all at once): 373 */ 374 iTick = pThis->iTick; 375 uint64_t const u64StartTS = pThis->u64StartTS; 376 uint64_t const u64NanoInterval = pThis->u64NanoInterval; 377 ASMCompilerBarrier(); 378 379 /* 380 * Suspend if one shot. 381 */ 382 if (!u64NanoInterval) 306 383 { 307 384 ASMAtomicWriteBool(&pThis->fSuspended, true); … … 318 395 * if we're using a non-monotonic clock as time source. 319 396 */ 320 pThis->u64NextTS = pThis->u64StartTS + pThis->iTick * pThis->u64NanoInterval;321 if (RT_LIKELY( pThis->u64NextTS > u64NanoTS))322 cNanoSeconds = pThis->u64NextTS - u64NanoTS;397 u64NextTS = u64StartTS + iTick * u64NanoInterval; 398 if (RT_LIKELY(u64NextTS > u64NanoTS)) 399 cNanoSeconds = u64NextTS - u64NanoTS; 323 400 else 324 401 { 325 uint64_t iActualTick = (u64NanoTS - pThis->u64StartTS) / pThis->u64NanoInterval;326 if (iActualTick - pThis->iTick > 60)402 uint64_t iActualTick = (u64NanoTS - u64StartTS) / u64NanoInterval; 403 if (iActualTick - iTick > 60) 327 404 pThis->iTick = iActualTick - 1; 328 405 #ifdef IN_RING0 329 406 cNanoSeconds = RTTimerGetSystemGranularity() / 2; 330 407 #else 331 cNanoSeconds = 1000000; /* 1ms */408 cNanoSeconds = RT_NS_1MS; 332 409 #endif 333 pThis->u64NextTS = u64NanoTS + cNanoSeconds;410 u64NextTS = u64NanoTS + cNanoSeconds; 334 411 } 412 413 pThis->u64NextTS = u64NextTS; 335 414 } 336 415 else 337 cNanoSeconds = pThis->u64NextTS - u64NanoTS;416 cNanoSeconds = u64NextTS - u64NanoTS; 338 417 339 418 /* block. */ 419 ASMAtomicWriteBool(&pThis->fBlocked, true); 340 420 int rc = RTSemEventWait(pThis->hEvent, 341 421 (RTMSINTERVAL)(cNanoSeconds < 1000000 ? 1 : cNanoSeconds / 1000000)); … … 345 425 RTThreadSleep(1000); /* Don't cause trouble! */ 346 426 } 427 ASMAtomicWriteBool(&pThis->fBlocked, false); 347 428 } 348 429 }
Note:
See TracChangeset
for help on using the changeset viewer.