VirtualBox

source: vbox/trunk/src/VBox/Runtime/generic/timerlr-generic.cpp@ 17658

Last change on this file since 17658 was 14298, checked in by vboxsync, 16 years ago

Corrected a couple of grammos.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 10.1 KB
Line 
1/** $Id: timerlr-generic.cpp 14298 2008-11-18 12:47:26Z vboxsync $ */
2/** @file
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.
7 */
8
9/*
10 * Copyright (C) 2006-2008 Sun Microsystems, Inc.
11 *
12 * This file is part of VirtualBox Open Source Edition (OSE), as
13 * available from http://www.virtualbox.org. This file is free software;
14 * you can redistribute it and/or modify it under the terms of the GNU
15 * General Public License (GPL) as published by the Free Software
16 * Foundation, in version 2 as it comes in the "COPYING" file of the
17 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
18 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
19 *
20 * The contents of this file may alternatively be used under the terms
21 * of the Common Development and Distribution License Version 1.0
22 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
23 * VirtualBox OSE distribution, in which case the provisions of the
24 * CDDL are applicable instead of those of the GPL.
25 *
26 * You may elect to license modified versions of this file under the
27 * terms and conditions of either the GPL or the CDDL or both.
28 *
29 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
30 * Clara, CA 95054 USA or visit http://www.sun.com if you need
31 * additional information or have any questions.
32 */
33
34
35/*******************************************************************************
36* Header Files *
37*******************************************************************************/
38#include <iprt/timer.h>
39#include <iprt/thread.h>
40#include <iprt/err.h>
41#include <iprt/assert.h>
42#include <iprt/alloc.h>
43#include <iprt/asm.h>
44#include <iprt/semaphore.h>
45#include <iprt/time.h>
46#include <iprt/log.h>
47#include "internal/magics.h"
48
49
50/*******************************************************************************
51* Structures and Typedefs *
52*******************************************************************************/
53/**
54 * The internal representation of a timer handle.
55 */
56typedef struct RTTIMERLRINT
57{
58 /** Magic.
59 * This is RTTIMERRT_MAGIC, but changes to something else before the timer
60 * is destroyed to indicate clearly that thread should exit. */
61 uint32_t volatile u32Magic;
62 /** Flag indicating the timer is suspended. */
63 bool volatile fSuspended;
64 /** Flag indicating that the timer has been destroyed. */
65 bool volatile fDestroyed;
66 /** Callback. */
67 PFNRTTIMERLR pfnTimer;
68 /** User argument. */
69 void *pvUser;
70 /** The timer thread. */
71 RTTHREAD hThread;
72 /** Event semaphore on which the thread is blocked. */
73 RTSEMEVENT hEvent;
74 /** The timer interval. 0 if one-shot. */
75 uint64_t 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} RTTIMERLRINT;
85typedef RTTIMERLRINT *PRTTIMERLRINT;
86
87
88/*******************************************************************************
89* Internal Functions *
90*******************************************************************************/
91static DECLCALLBACK(int) rtTimerLRThread(RTTHREAD hThread, void *pvUser);
92
93
94RTDECL(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.
101 */
102 if (fFlags & RTTIMER_FLAGS_CPU_SPECIFIC)
103 return VERR_NOT_SUPPORTED;
104 if (u64NanoInterval && u64NanoInterval < 100*1000*1000)
105 return VERR_INVALID_PARAMETER;
106
107 /*
108 * Allocate and initialize the timer handle.
109 */
110 PRTTIMERLRINT pThis = (PRTTIMERLRINT)RTMemAlloc(sizeof(*pThis));
111 if (!pThis)
112 return VERR_NO_MEMORY;
113
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);
125 if (RT_SUCCESS(rc))
126 {
127 rc = RTThreadCreate(&pThis->hThread, rtTimerLRThread, pThis, 0, RTTHREADTYPE_TIMER, RTTHREADFLAGS_WAITABLE, "TIMER");
128 if (RT_SUCCESS(rc))
129 {
130 *phTimerLR = pThis;
131 return VINF_SUCCESS;
132 }
133
134 pThis->u32Magic = 0;
135 RTSemEventDestroy(pThis->hEvent);
136 pThis->hEvent = NIL_RTSEMEVENT;
137 }
138 RTMemFree(pThis);
139
140 return rc;
141}
142
143
144RTDECL(int) RTTimerLRDestroy(RTTIMERLR hTimerLR)
145{
146 /*
147 * Validate input, NIL is fine though.
148 */
149 if (hTimerLR == NIL_RTTIMERLR)
150 return VINF_SUCCESS;
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);
155
156 /*
157 * If the timer is active, we just flag it to self destruct on the next tick.
158 * If it's suspended we can safely set the destroy flag and signal it.
159 */
160 RTTHREAD hThread = pThis->hThread;
161 if (!pThis->fSuspended)
162 {
163 ASMAtomicWriteBool(&pThis->fSuspended, true);
164 ASMAtomicWriteBool(&pThis->fDestroyed, true);
165 }
166 else
167 {
168 ASMAtomicWriteBool(&pThis->fDestroyed, true);
169 int rc = RTSemEventSignal(pThis->hEvent);
170 if (rc == VERR_ALREADY_POSTED)
171 rc = VINF_SUCCESS;
172 AssertRC(rc);
173 }
174
175 RTThreadWait(hThread, 250, NULL);
176 return VINF_SUCCESS;
177}
178
179
180RTDECL(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)
194 return VERR_TIMER_ACTIVE;
195
196 /*
197 * Calc when it should start fireing and give the thread a kick so it get going.
198 */
199 u64First += RTTimeNanoTS();
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);
205 if (rc == VERR_ALREADY_POSTED)
206 rc = VINF_SUCCESS;
207 AssertRC(rc);
208 return rc;
209}
210
211
212RTDECL(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)
223 return VERR_TIMER_SUSPENDED;
224
225 /*
226 * Mark it as suspended and kick the thread.
227 */
228 ASMAtomicWriteBool(&pThis->fSuspended, true);
229 int rc = RTSemEventSignal(pThis->hEvent);
230 if (rc == VERR_ALREADY_POSTED)
231 rc = VINF_SUCCESS;
232 AssertRC(rc);
233 return rc;
234}
235
236
237static DECLCALLBACK(int) rtTimerLRThread(RTTHREAD hThread, void *pvUser)
238{
239 PRTTIMERLRINT pThis = (PRTTIMERLRINT)pvUser;
240
241 /*
242 * The loop.
243 */
244 while (!ASMAtomicUoReadBool(&pThis->fDestroyed))
245 {
246 if (ASMAtomicUoReadBool(&pThis->fSuspended))
247 {
248 int rc = RTSemEventWait(pThis->hEvent, RT_INDEFINITE_WAIT);
249 if (RT_FAILURE(rc) && rc != VERR_INTERRUPTED)
250 {
251 AssertRC(rc);
252 RTThreadSleep(1000); /* Don't cause trouble! */
253 }
254 }
255 else
256 {
257 const uint64_t u64NanoTS = RTTimeNanoTS();
258 if (u64NanoTS >= pThis->u64NextTS)
259 {
260 pThis->iTick++;
261 pThis->pfnTimer(pThis, pThis->pvUser, pThis->iTick);
262
263 /* status changed? */
264 if ( ASMAtomicUoReadBool(&pThis->fSuspended)
265 || ASMAtomicUoReadBool(&pThis->fDestroyed))
266 continue;
267
268 /* one shot? */
269 if (!pThis->u64NanoInterval)
270 {
271 ASMAtomicWriteBool(&pThis->fSuspended, true);
272 continue;
273 }
274
275 /* calc the next time we should fire. */
276 pThis->u64NextTS = pThis->u64StartTS + pThis->iTick * pThis->u64NanoInterval;
277 if (pThis->u64NextTS < u64NanoTS)
278#ifdef IN_RING3 /* In ring-3 we'll catch up lost ticks immediately. */
279 pThis->u64NextTS = u64NanoTS + 1;
280#else
281 pThis->u64NextTS = u64NanoTS + RTTimerGetSystemGranularity() / 2;
282#endif
283 }
284
285 /* block. */
286 uint64_t cNanoSeconds = pThis->u64NextTS - u64NanoTS;
287#ifdef IN_RING3 /* In ring-3 we'll catch up lost ticks immediately. */
288 if (cNanoSeconds > 10)
289#endif
290 {
291 int rc = RTSemEventWait(pThis->hEvent, cNanoSeconds < 1000000 ? 1 : cNanoSeconds / 1000000);
292 if (RT_FAILURE(rc) && rc != VERR_INTERRUPTED && rc != VERR_TIMEOUT)
293 {
294 AssertRC(rc);
295 RTThreadSleep(1000); /* Don't cause trouble! */
296 }
297 }
298 }
299 }
300
301 /*
302 * Release the timer resources.
303 */
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);
309
310 return VINF_SUCCESS;
311}
312
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette