VirtualBox

source: vbox/trunk/src/VBox/Runtime/r0drv/os2/timer-r0drv-os2.cpp@ 1321

Last change on this file since 1321 was 1191, checked in by vboxsync, 18 years ago

svn properties.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 11.1 KB
Line 
1/* $Id: timer-r0drv-os2.cpp 1191 2007-03-04 20:46:04Z vboxsync $ */
2/** @file
3 * InnoTek Portable Runtime - Memory Allocation, Ring-0 Driver, OS/2.
4 */
5
6/*
7 * Copyright (c) 2007 knut st. osmundsen <[email protected]>
8 *
9 * Permission is hereby granted, free of charge, to any person
10 * obtaining a copy of this software and associated documentation
11 * files (the "Software"), to deal in the Software without
12 * restriction, including without limitation the rights to use,
13 * copy, modify, merge, publish, distribute, sublicense, and/or sell
14 * copies of the Software, and to permit persons to whom the
15 * Software is furnished to do so, subject to the following
16 * conditions:
17 *
18 * The above copyright notice and this permission notice shall be
19 * included in all copies or substantial portions of the Software.
20 *
21 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
23 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
24 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
25 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
26 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
27 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
28 * OTHER DEALINGS IN THE SOFTWARE.
29 */
30
31
32/*******************************************************************************
33* Header Files *
34*******************************************************************************/
35#include "the-os2-kernel.h"
36
37#include <iprt/timer.h>
38#include <iprt/time.h>
39#include <iprt/spinlock.h>
40#include <iprt/err.h>
41#include <iprt/asm.h>
42#include <iprt/assert.h>
43#include <iprt/alloc.h>
44
45
46/*******************************************************************************
47* Structures and Typedefs *
48*******************************************************************************/
49/**
50 * The internal representation of an OS/2 timer handle.
51 */
52typedef struct RTTIMER
53{
54 /** Magic.
55 * This is RTTIMER_MAGIC, but changes to something else before the timer
56 * is destroyed to indicate clearly that thread should exit. */
57 uint32_t volatile u32Magic;
58 /** The next timer in the timer list. */
59 PRTTIMER pNext;
60 /** Flag indicating the the timer is suspended. */
61 uint8_t volatile fSuspended;
62 /** Cleared at the start of timer processing, set when calling pfnTimer.
63 * If any timer changes occures while doing the callback this will be used to resume the cycle. */
64 bool fDone;
65 /** Callback. */
66 PFNRTTIMER pfnTimer;
67 /** User argument. */
68 void *pvUser;
69 /** The timer interval. 0 if one-shot. */
70 uint64_t u64NanoInterval;
71 /** The start of the current run.
72 * This is used to calculate when the timer ought to fire the next time. */
73 uint64_t volatile u64StartTS;
74 /** The start of the current run.
75 * This is used to calculate when the timer ought to fire the next time. */
76 uint64_t volatile u64NextTS;
77 /** The current tick number (since u64StartTS). */
78 uint64_t volatile iTick;
79} RTTIMER;
80
81/** Magic number for timer handles. (Jared Mason Diamond) */
82#define RTTIMER_MAGIC 0x19370910
83
84
85/*******************************************************************************
86* Global Variables *
87*******************************************************************************/
88/** Spinlock protecting the timers. */
89static RTSPINLOCK g_Spinlock = NIL_RTSPINLOCK;
90/** The timer head. */
91static PRTTIMER volatile g_pTimerHead = NULL;
92/** The number of active timers. */
93static uint32_t volatile g_cActiveTimers = 0;
94/** The number of active timers. */
95static uint32_t volatile g_cTimers = 0;
96/** The change number.
97 * This is used to detect list changes during the timer callback loop. */
98static uint32_t volatile g_u32ChangeNo;
99
100
101/*******************************************************************************
102* Internal Functions *
103*******************************************************************************/
104__BEGIN_DECLS
105DECLASM(void) rtTimerOs2Tick(void);
106DECLASM(int) rtTimerOs2Arm(void);
107DECLASM(int) rtTimerOs2Dearm(void);
108__END_DECLS
109
110
111
112RTDECL(int) RTTimerCreate(PRTTIMER *ppTimer, unsigned uMilliesInterval, PFNRTTIMER pfnTimer, void *pvUser)
113{
114 int rc = RTTimerCreateEx(ppTimer, uMilliesInterval * UINT64_C(1000000), 0, pfnTimer, pvUser);
115 if (RT_SUCCESS(rc))
116 {
117 rc = RTTimerStart(*ppTimer, 0);
118 if (RT_SUCCESS(rc))
119 return rc;
120 int rc2 = RTTimerDestroy(*ppTimer); AssertRC(rc2);
121 *ppTimer = NULL;
122 }
123 return rc;
124}
125
126
127RTDECL(int) RTTimerCreateEx(PRTTIMER *ppTimer, uint64_t u64NanoInterval, unsigned fFlags, PFNRTTIMER pfnTimer, void *pvUser)
128{
129 *ppTimer = NULL;
130
131 /*
132 * Lazy initialize the spinlock.
133 */
134 if (g_Spinlock == NIL_RTSPINLOCK)
135 {
136 RTSPINLOCK Spinlock;
137 int rc = RTSpinlockCreate(&Spinlock);
138 AssertRCReturn(rc, rc);
139 //bool fRc;
140 //ASMAtomicCmpXchgSize(&g_Spinlock, Spinlock, NIL_RTSPINLOCK, fRc);
141 //if (!fRc)
142 if (!ASMAtomicCmpXchgPtr((void * volatile *)&g_Spinlock, Spinlock, NIL_RTSPINLOCK))
143 RTSpinlockDestroy(Spinlock);
144 }
145
146 /*
147 * Allocate and initialize the timer handle.
148 */
149 PRTTIMER pTimer = (PRTTIMER)RTMemAlloc(sizeof(*pTimer));
150 if (!pTimer)
151 return VERR_NO_MEMORY;
152
153 pTimer->u32Magic = RTTIMER_MAGIC;
154 pTimer->pNext = NULL;
155 pTimer->fSuspended = true;
156 pTimer->pfnTimer = pfnTimer;
157 pTimer->pvUser = pvUser;
158 pTimer->u64NanoInterval = u64NanoInterval;
159 pTimer->u64StartTS = 0;
160
161 /*
162 * Insert the timer into the list (LIFO atm).
163 */
164 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
165 RTSpinlockAcquireNoInts(g_Spinlock, &Tmp);
166 g_u32ChangeNo++;
167 pTimer->pNext = g_pTimerHead;
168 g_pTimerHead = pTimer;
169 g_cTimers++;
170 RTSpinlockReleaseNoInts(g_Spinlock, &Tmp);
171
172 *ppTimer = pTimer;
173 return VINF_SUCCESS;
174}
175
176
177/**
178 * Validates the timer handle.
179 *
180 * @returns true if valid, false if invalid.
181 * @param pTimer The handle.
182 */
183DECLINLINE(bool) rtTimerIsValid(PRTTIMER pTimer)
184{
185 AssertReturn(VALID_PTR(pTimer), false);
186 AssertReturn(pTimer->u32Magic == RTTIMER_MAGIC, false);
187 return true;
188}
189
190
191RTDECL(int) RTTimerDestroy(PRTTIMER pTimer)
192{
193 /* It's ok to pass NULL pointer. */
194 if (pTimer == /*NIL_RTTIMER*/ NULL)
195 return VINF_SUCCESS;
196 if (!rtTimerIsValid(pTimer))
197 return VERR_INVALID_HANDLE;
198
199 /*
200 * Remove it from the list.
201 */
202 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
203 RTSpinlockAcquireNoInts(g_Spinlock, &Tmp);
204 g_u32ChangeNo++;
205 if (g_pTimerHead == pTimer)
206 g_pTimerHead = pTimer->pNext;
207 else
208 {
209 PRTTIMER pPrev = g_pTimerHead;
210 while (pPrev->pNext != pTimer)
211 {
212 pPrev = pPrev->pNext;
213 if (RT_UNLIKELY(!pPrev))
214 {
215 RTSpinlockReleaseNoInts(g_Spinlock, &Tmp);
216 return VERR_INVALID_HANDLE;
217 }
218 }
219 pPrev->pNext = pTimer->pNext;
220 }
221 Assert(g_cTimers > 0);
222 g_cTimers--;
223 if (!pTimer->fSuspended)
224 {
225 Assert(g_cActiveTimers > 0);
226 g_cActiveTimers--;
227 if (!g_cActiveTimers)
228 rtTimerOs2Dearm();
229 }
230 RTSpinlockReleaseNoInts(g_Spinlock, &Tmp);
231
232 /*
233 * Free the associated resources.
234 */
235 pTimer->u32Magic++;
236 RTMemFree(pTimer);
237 return VINF_SUCCESS;
238}
239
240
241RTDECL(int) RTTimerStart(PRTTIMER pTimer, uint64_t u64First)
242{
243 if (!rtTimerIsValid(pTimer))
244 return VERR_INVALID_HANDLE;
245 if (!pTimer->fSuspended)
246 return VERR_TIMER_ACTIVE;
247
248 /*
249 * Calc when it should start fireing and give the thread a kick so it get going.
250 */
251 u64First += RTTimeNanoTS();
252
253 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
254 RTSpinlockAcquireNoInts(g_Spinlock, &Tmp);
255 g_u32ChangeNo++;
256 if (!g_cActiveTimers)
257 {
258 int rc = rtTimerOs2Arm();
259 if (RT_FAILURE(rc))
260 {
261 RTSpinlockReleaseNoInts(g_Spinlock, &Tmp);
262 return rc;
263 }
264 }
265 g_cActiveTimers++;
266 pTimer->fSuspended = false;
267 pTimer->fDone = true; /* next tick, not current! */
268 pTimer->iTick = 0;
269 pTimer->u64StartTS = u64First;
270 pTimer->u64NextTS = u64First;
271 RTSpinlockReleaseNoInts(g_Spinlock, &Tmp);
272
273 return VINF_SUCCESS;
274}
275
276
277RTDECL(int) RTTimerStop(PRTTIMER pTimer)
278{
279 if (!rtTimerIsValid(pTimer))
280 return VERR_INVALID_HANDLE;
281 if (pTimer->fSuspended)
282 return VERR_TIMER_SUSPENDED;
283
284 /*
285 * Suspend the timer.
286 */
287 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
288 RTSpinlockAcquireNoInts(g_Spinlock, &Tmp);
289 g_u32ChangeNo++;
290 pTimer->fSuspended = true;
291 Assert(g_cActiveTimers > 0);
292 g_cActiveTimers--;
293 if (!g_cActiveTimers)
294 rtTimerOs2Dearm();
295 RTSpinlockReleaseNoInts(g_Spinlock, &Tmp);
296
297 return VINF_SUCCESS;
298}
299
300
301DECLASM(void) rtTimerOs2Tick(void)
302{
303 /*
304 * Query the current time and then take the lock.
305 */
306 const uint64_t u64NanoTS = RTTimeNanoTS();
307
308 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
309 RTSpinlockAcquireNoInts(g_Spinlock, &Tmp);
310
311 /*
312 * Clear the fDone flag.
313 */
314 PRTTIMER pTimer;
315 for (pTimer = g_pTimerHead; pTimer; pTimer = pTimer->pNext)
316 pTimer->fDone = false;
317
318 /*
319 * Walk the timer list and do the callbacks for any active timer.
320 */
321 uint32_t u32CurChangeNo = g_u32ChangeNo;
322 pTimer = g_pTimerHead;
323 while (pTimer)
324 {
325 PRTTIMER pNext = pTimer->pNext;
326 if ( !pTimer->fSuspended
327 && !pTimer->fDone
328 && pTimer->u64NextTS <= u64NanoTS)
329 {
330 pTimer->fDone = true;
331
332 /* calculate the next timeout */
333 if (!pTimer->u64NanoInterval)
334 pTimer->fSuspended = true;
335 else
336 {
337 pTimer->u64NextTS = pTimer->u64StartTS + pTimer->iTick * pTimer->u64NanoInterval;
338 if (pTimer->u64NextTS < u64NanoTS)
339 pTimer->u64NextTS = u64NanoTS + RTTimerGetSystemGranularity() / 2;
340 }
341
342 /* do the callout */
343 PFNRTTIMER pfnTimer = pTimer->pfnTimer;
344 void *pvUser = pTimer->pvUser;
345 RTSpinlockReleaseNoInts(g_Spinlock, &Tmp);
346 pfnTimer(pTimer, pvUser);
347
348 RTSpinlockAcquireNoInts(g_Spinlock, &Tmp);
349
350 /* check if anything changed. */
351 if (u32CurChangeNo != g_u32ChangeNo)
352 {
353 u32CurChangeNo = g_u32ChangeNo;
354 pNext = g_pTimerHead;
355 }
356 }
357
358 /* next */
359 pTimer = pNext;
360 }
361
362 RTSpinlockReleaseNoInts(g_Spinlock, &Tmp);
363}
364
365
366RTDECL(uint32_t) RTTimerGetSystemGranularity(void)
367{
368 return 32000000; /* 32ms */
369}
370
371
372RTDECL(int) RTTimerRequestSystemGranularity(uint32_t u32Request, uint32_t *pu32Granted)
373{
374 return VERR_NOT_SUPPORTED;
375}
376
377
378RTDECL(int) RTTimerReleaseSystemGranularity(uint32_t u32Granted)
379{
380 return VERR_NOT_SUPPORTED;
381}
382
Note: See TracBrowser for help on using the repository browser.

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