Changeset 10944 in vbox for trunk/src/VBox/Runtime/generic/timerlr-generic.cpp
- Timestamp:
- Jul 29, 2008 6:08:58 PM (17 years ago)
- svn:sync-xref-src-repo-rev:
- 33809
- File:
-
- 1 copied
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Runtime/generic/timerlr-generic.cpp
r10934 r10944 1 1 /** $Id$ */ 2 2 /** @file 3 * IPRT - Timers, Generic. 3 * IPRT - Low Resolution Timers, Generic. 4 * 5 * This code is more or less identicial to timer-generic.cpp, so 6 * bugfixes goes into both files. 4 7 */ 5 8 6 9 /* 7 * Copyright (C) 2006-200 7Sun Microsystems, Inc.10 * Copyright (C) 2006-2008 Sun Microsystems, Inc. 8 11 * 9 12 * This file is part of VirtualBox Open Source Edition (OSE), as … … 45 48 46 49 47 48 50 /******************************************************************************* 49 51 * Structures and Typedefs * … … 52 54 * The internal representation of a timer handle. 53 55 */ 54 typedef struct RTTIMER 56 typedef struct RTTIMERLRINT 55 57 { 56 58 /** Magic. 57 * This is RTTIMER _MAGIC, but changes to something else before the timer59 * This is RTTIMERRT_MAGIC, but changes to something else before the timer 58 60 * is destroyed to indicate clearly that thread should exit. */ 59 61 uint32_t volatile u32Magic; 60 62 /** Flag indicating the the timer is suspended. */ 61 uint8_t volatilefSuspended;63 bool volatile fSuspended; 62 64 /** Flag indicating that the timer has been destroyed. */ 63 uint8_t volatilefDestroyed;65 bool volatile fDestroyed; 64 66 /** Callback. */ 65 PFNRTTIMER 67 PFNRTTIMERLR pfnTimer; 66 68 /** User argument. */ 67 69 void *pvUser; 68 70 /** The timer thread. */ 69 RTTHREAD Thread;71 RTTHREAD hThread; 70 72 /** Event semaphore on which the thread is blocked. */ 71 RTSEMEVENT Event;73 RTSEMEVENT hEvent; 72 74 /** The timer interval. 0 if one-shot. */ 73 75 uint64_t u64NanoInterval; … … 80 82 /** The current tick number (since u64StartTS). */ 81 83 uint64_t volatile iTick; 82 } RTTIMER; 84 } RTTIMERLRINT; 85 typedef RTTIMERLRINT *PRTTIMERLRINT; 83 86 84 87 … … 86 89 * Internal Functions * 87 90 *******************************************************************************/ 88 static DECLCALLBACK(int) rtTimerThread(RTTHREAD Thread, void *pvUser); 89 90 91 RTDECL(int) RTTimerCreateEx(PRTTIMER *ppTimer, uint64_t u64NanoInterval, unsigned fFlags, PFNRTTIMER pfnTimer, void *pvUser) 92 { 93 *ppTimer = NULL; 94 95 /* 96 * We don't support the fancy MP features. 91 static DECLCALLBACK(int) rtTimerLRThread(RTTHREAD hThread, void *pvUser); 92 93 94 RTDECL(int) RTTimerLRCreateEx(RTTIMERLR *phTimerLR, uint64_t u64NanoInterval, uint32_t fFlags, PFNRTTIMERLR pfnTimer, void *pvUser) 95 { 96 AssertPtr(phTimerLR); 97 *phTimerLR = NIL_RTTIMERLR; 98 99 /* 100 * We don't support the fancy MP features, nor intervals lower than 100 ms. 97 101 */ 98 102 if (fFlags & RTTIMER_FLAGS_CPU_SPECIFIC) 99 103 return VERR_NOT_SUPPORTED; 104 if (u64NanoInterval < 100*1000*1000) 105 return VERR_INVALID_PARAMETER; 100 106 101 107 /* 102 108 * Allocate and initialize the timer handle. 103 109 */ 104 PRTTIMER pTimer = (PRTTIMER)RTMemAlloc(sizeof(*pTimer));105 if (!pT imer)110 PRTTIMERLRINT pThis = (PRTTIMERLRINT)RTMemAlloc(sizeof(*pThis)); 111 if (!pThis) 106 112 return VERR_NO_MEMORY; 107 113 108 pT imer->u32Magic = RTTIMER_MAGIC;109 pT imer->fSuspended = true;110 pT imer->fDestroyed = false;111 pT imer->pfnTimer = pfnTimer;112 pT imer->pvUser = pvUser;113 pT imer->Thread = NIL_RTTHREAD;114 pT imer->Event = NIL_RTSEMEVENT;115 pT imer->u64NanoInterval = u64NanoInterval;116 pT imer->u64StartTS = 0;117 118 int rc = RTSemEventCreate(&pT imer->Event);114 pThis->u32Magic = RTTIMERLR_MAGIC; 115 pThis->fSuspended = true; 116 pThis->fDestroyed = false; 117 pThis->pfnTimer = pfnTimer; 118 pThis->pvUser = pvUser; 119 pThis->hThread = NIL_RTTHREAD; 120 pThis->hEvent = NIL_RTSEMEVENT; 121 pThis->u64NanoInterval = u64NanoInterval; 122 pThis->u64StartTS = 0; 123 124 int rc = RTSemEventCreate(&pThis->hEvent); 119 125 if (RT_SUCCESS(rc)) 120 126 { 121 rc = RTThreadCreate(&pT imer->Thread, rtTimerThread, pTimer, 0, RTTHREADTYPE_TIMER, RTTHREADFLAGS_WAITABLE, "TIMER");127 rc = RTThreadCreate(&pThis->hThread, rtTimerLRThread, pThis, 0, RTTHREADTYPE_TIMER, RTTHREADFLAGS_WAITABLE, "TIMER"); 122 128 if (RT_SUCCESS(rc)) 123 129 { 124 *p pTimer = pTimer;130 *phTimerLR = pThis; 125 131 return VINF_SUCCESS; 126 132 } 127 133 128 pT imer->u32Magic = 0;129 RTSemEventDestroy(pT imer->Event);130 pT imer->Event = NIL_RTSEMEVENT;134 pThis->u32Magic = 0; 135 RTSemEventDestroy(pThis->hEvent); 136 pThis->hEvent = NIL_RTSEMEVENT; 131 137 } 132 RTMemFree(pT imer);138 RTMemFree(pThis); 133 139 134 140 return rc; … … 136 142 137 143 138 /** 139 * Validates the timer handle. 140 * 141 * @returns true if valid, false if invalid. 142 * @param pTimer The handle. 143 */ 144 DECLINLINE(bool) rtTimerIsValid(PRTTIMER pTimer) 145 { 146 AssertReturn(VALID_PTR(pTimer), false); 147 AssertReturn(pTimer->u32Magic == RTTIMER_MAGIC, false); 148 AssertReturn(!pTimer->fDestroyed, false); 149 return true; 150 } 151 152 153 RTDECL(int) RTTimerDestroy(PRTTIMER pTimer) 154 { 155 /* It's ok to pass NULL pointer. */ 156 if (pTimer == /*NIL_RTTIMER*/ NULL) 144 RTDECL(int) RTTimerLRDestroy(RTTIMERLR hTimerLR) 145 { 146 /* 147 * Validate input, NIL is fine though. 148 */ 149 if (hTimerLR == NIL_RTTIMERLR) 157 150 return VINF_SUCCESS; 158 if (!rtTimerIsValid(pTimer)) 159 return VERR_INVALID_HANDLE; 151 PRTTIMERLRINT pThis = hTimerLR; 152 AssertPtrReturn(pThis, VERR_INVALID_HANDLE); 153 AssertReturn(pThis->u32Magic == RTTIMERLR_MAGIC, VERR_INVALID_HANDLE); 154 AssertReturn(!pThis->fDestroyed, VERR_INVALID_HANDLE); 160 155 161 156 /* … … 163 158 * If it's suspended we can safely set the destroy flag and signal it. 164 159 */ 165 RTTHREAD Thread = pTimer->Thread;166 if (!pT imer->fSuspended)160 RTTHREAD hThread = pThis->hThread; 161 if (!pThis->fSuspended) 167 162 { 168 ASMAtomic XchgU8(&pTimer->fSuspended, true);169 ASMAtomic XchgU8(&pTimer->fDestroyed, true);163 ASMAtomicWriteBool(&pThis->fSuspended, true); 164 ASMAtomicWriteBool(&pThis->fDestroyed, true); 170 165 } 171 166 else 172 167 { 173 ASMAtomic XchgU8(&pTimer->fDestroyed, true);174 int rc = RTSemEventSignal(pT imer->Event);168 ASMAtomicWriteBool(&pThis->fDestroyed, true); 169 int rc = RTSemEventSignal(pThis->hEvent); 175 170 if (rc == VERR_ALREADY_POSTED) 176 171 rc = VINF_SUCCESS; … … 178 173 } 179 174 180 RTThreadWait( Thread, 250, NULL);175 RTThreadWait(hThread, 250, NULL); 181 176 return VINF_SUCCESS; 182 177 } 183 178 184 179 185 RTDECL(int) RTTimerStart(PRTTIMER pTimer, uint64_t u64First) 186 { 187 if (!rtTimerIsValid(pTimer)) 188 return VERR_INVALID_HANDLE; 189 if (!pTimer->fSuspended) 180 RTDECL(int) RTTimerLRStart(RTTIMERLR hTimerLR, uint64_t u64First) 181 { 182 /* 183 * Validate input. 184 */ 185 PRTTIMERLRINT pThis = hTimerLR; 186 AssertPtrReturn(pThis, VERR_INVALID_HANDLE); 187 AssertReturn(pThis->u32Magic == RTTIMERLR_MAGIC, VERR_INVALID_HANDLE); 188 AssertReturn(!pThis->fDestroyed, VERR_INVALID_HANDLE); 189 190 if (u64First && u64First < 100*1000*1000) 191 return VERR_INVALID_PARAMETER; 192 193 if (!pThis->fSuspended) 190 194 return VERR_TIMER_ACTIVE; 191 195 … … 194 198 */ 195 199 u64First += RTTimeNanoTS(); 196 ASMAtomic XchgU64(&pTimer->iTick, 0);197 ASMAtomic XchgU64(&pTimer->u64StartTS, u64First);198 ASMAtomic XchgU64(&pTimer->u64NextTS, u64First);199 ASMAtomic XchgU8(&pTimer->fSuspended, false);200 int rc = RTSemEventSignal(pT imer->Event);200 ASMAtomicWriteU64(&pThis->iTick, 0); 201 ASMAtomicWriteU64(&pThis->u64StartTS, u64First); 202 ASMAtomicWriteU64(&pThis->u64NextTS, u64First); 203 ASMAtomicWriteBool(&pThis->fSuspended, false); 204 int rc = RTSemEventSignal(pThis->hEvent); 201 205 if (rc == VERR_ALREADY_POSTED) 202 206 rc = VINF_SUCCESS; … … 206 210 207 211 208 RTDECL(int) RTTimerStop(PRTTIMER pTimer) 209 { 210 if (!rtTimerIsValid(pTimer)) 211 return VERR_INVALID_HANDLE; 212 if (pTimer->fSuspended) 212 RTDECL(int) RTTimerLRStop(RTTIMERLR hTimerLR) 213 { 214 /* 215 * Validate input. 216 */ 217 PRTTIMERLRINT pThis = hTimerLR; 218 AssertPtrReturn(pThis, VERR_INVALID_HANDLE); 219 AssertReturn(pThis->u32Magic == RTTIMERLR_MAGIC, VERR_INVALID_HANDLE); 220 AssertReturn(!pThis->fDestroyed, VERR_INVALID_HANDLE); 221 222 if (pThis->fSuspended) 213 223 return VERR_TIMER_SUSPENDED; 214 224 … … 216 226 * Mark it as suspended and kick the thread. 217 227 */ 218 ASMAtomic XchgU8(&pTimer->fSuspended, true);219 int rc = RTSemEventSignal(pT imer->Event);228 ASMAtomicWriteBool(&pThis->fSuspended, true); 229 int rc = RTSemEventSignal(pThis->hEvent); 220 230 if (rc == VERR_ALREADY_POSTED) 221 231 rc = VINF_SUCCESS; … … 225 235 226 236 227 static DECLCALLBACK(int) rtTimer Thread(RTTHREADThread, void *pvUser)228 { 229 PRTTIMER pTimer = (PRTTIMER)pvUser;237 static DECLCALLBACK(int) rtTimerLRThread(RTTHREAD hThread, void *pvUser) 238 { 239 PRTTIMERLRINT pThis = (PRTTIMERLRINT)pvUser; 230 240 231 241 /* 232 242 * The loop. 233 243 */ 234 while (! pTimer->fDestroyed)244 while (!ASMAtomicUoReadBool(&pThis->fDestroyed)) 235 245 { 236 if ( pTimer->fSuspended)246 if (ASMAtomicUoReadBool(&pThis->fSuspended)) 237 247 { 238 int rc = RTSemEventWait(pT imer->Event, RT_INDEFINITE_WAIT);248 int rc = RTSemEventWait(pThis->hEvent, RT_INDEFINITE_WAIT); 239 249 if (RT_FAILURE(rc) && rc != VERR_INTERRUPTED) 240 250 { … … 246 256 { 247 257 const uint64_t u64NanoTS = RTTimeNanoTS(); 248 if (u64NanoTS >= pT imer->u64NextTS)258 if (u64NanoTS >= pThis->u64NextTS) 249 259 { 250 pT imer->iTick++;251 pT imer->pfnTimer(pTimer, pTimer->pvUser, pTimer->iTick);260 pThis->iTick++; 261 pThis->pfnTimer(pThis, pThis->pvUser, pThis->iTick); 252 262 253 263 /* status changed? */ 254 if (pTimer->fSuspended || pTimer->fDestroyed) 264 if ( ASMAtomicUoReadBool(&pThis->fSuspended) 265 || ASMAtomicUoReadBool(&pThis->fDestroyed)) 255 266 continue; 256 267 257 268 /* one shot? */ 258 if (!pT imer->u64NanoInterval)269 if (!pThis->u64NanoInterval) 259 270 { 260 ASMAtomic XchgU8(&pTimer->fSuspended, true);271 ASMAtomicWriteBool(&pThis->fSuspended, true); 261 272 continue; 262 273 } 263 274 264 275 /* calc the next time we should fire. */ 265 pT imer->u64NextTS = pTimer->u64StartTS + pTimer->iTick * pTimer->u64NanoInterval;266 if (pT imer->u64NextTS < u64NanoTS)276 pThis->u64NextTS = pThis->u64StartTS + pThis->iTick * pThis->u64NanoInterval; 277 if (pThis->u64NextTS < u64NanoTS) 267 278 #ifdef IN_RING3 /* In ring-3 we'll catch up lost ticks immediately. */ 268 pT imer->u64NextTS = u64NanoTS + 1;279 pThis->u64NextTS = u64NanoTS + 1; 269 280 #else 270 pT imer->u64NextTS = u64NanoTS + RTTimerGetSystemGranularity() / 2;281 pThis->u64NextTS = u64NanoTS + RTTimerGetSystemGranularity() / 2; 271 282 #endif 272 283 } 273 284 274 285 /* block. */ 275 uint64_t cNanoSeconds = pT imer->u64NextTS - u64NanoTS;286 uint64_t cNanoSeconds = pThis->u64NextTS - u64NanoTS; 276 287 #ifdef IN_RING3 /* In ring-3 we'll catch up lost ticks immediately. */ 277 288 if (cNanoSeconds > 10) 278 289 #endif 279 290 { 280 int rc = RTSemEventWait(pT imer->Event, cNanoSeconds < 1000000 ? 1 : cNanoSeconds / 1000000);291 int rc = RTSemEventWait(pThis->hEvent, cNanoSeconds < 1000000 ? 1 : cNanoSeconds / 1000000); 281 292 if (RT_FAILURE(rc) && rc != VERR_INTERRUPTED && rc != VERR_TIMEOUT) 282 293 { … … 291 302 * Release the timer resources. 292 303 */ 293 ASMAtomic IncU32(&pTimer->u32Magic); /* make the handle invalid. */294 int rc = RTSemEventDestroy(pT imer->Event); AssertRC(rc);295 pT imer->Event = NIL_RTSEMEVENT;296 pT imer->Thread = NIL_RTTHREAD;297 RTMemFree(pT imer);304 ASMAtomicWriteU32(&pThis->u32Magic, ~RTTIMERLR_MAGIC); /* make the handle invalid. */ 305 int rc = RTSemEventDestroy(pThis->hEvent); AssertRC(rc); 306 pThis->hEvent = NIL_RTSEMEVENT; 307 pThis->hThread = NIL_RTTHREAD; 308 RTMemFree(pThis); 298 309 299 310 return VINF_SUCCESS; 300 311 } 301 312 302 303 304 305 RTDECL(uint32_t) RTTimerGetSystemGranularity(void)306 {307 return 10000000; /* 10ms */308 }309 310 311 RTDECL(int) RTTimerRequestSystemGranularity(uint32_t u32Request, uint32_t *pu32Granted)312 {313 return VERR_NOT_SUPPORTED;314 }315 316 317 RTDECL(int) RTTimerReleaseSystemGranularity(uint32_t u32Granted)318 {319 return VERR_NOT_SUPPORTED;320 }321
Note:
See TracChangeset
for help on using the changeset viewer.