VirtualBox

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

Last change on this file since 78365 was 77120, checked in by vboxsync, 6 years ago

IPRT: Some license header cleanups.

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