VirtualBox

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

Last change on this file since 85561 was 82968, checked in by vboxsync, 5 years ago

Copyright year updates by scm.

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