VirtualBox

source: vbox/trunk/src/VBox/Runtime/testcase/tstRTR0Timer.cpp@ 32669

最後變更 在這個檔案從32669是 32669,由 vboxsync 提交於 14 年 前

tstRTR0Timer: Some more tests.

  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keywords 設為 Author Date Id Revision
檔案大小: 15.0 KB
 
1/* $Id: tstRTR0Timer.cpp 32669 2010-09-21 16:18:22Z vboxsync $ */
2/** @file
3 * IPRT R0 Testcase - Timers.
4 */
5
6/*
7 * Copyright (C) 2009-2010 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.alldomusa.eu.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * The contents of this file may alternatively be used under the terms
18 * of the Common Development and Distribution License Version 1.0
19 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20 * VirtualBox OSE distribution, in which case the provisions of the
21 * CDDL are applicable instead of those of the GPL.
22 *
23 * You may elect to license modified versions of this file under the
24 * terms and conditions of either the GPL or the CDDL or both.
25 */
26
27/*******************************************************************************
28* Header Files *
29*******************************************************************************/
30#include <iprt/timer.h>
31
32#include <iprt/asm.h>
33#include <iprt/err.h>
34#include <iprt/param.h>
35#include <iprt/string.h>
36#include <iprt/thread.h>
37#include <iprt/time.h>
38#include <VBox/sup.h>
39#include "tstRTR0Timer.h"
40#include "tstRTR0Common.h"
41
42/*******************************************************************************
43* Structures and Typedefs *
44*******************************************************************************/
45typedef struct
46{
47 /** Array of nano second timestamp of the first few shots. */
48 uint64_t volatile aShotNsTSes[10];
49 /** The number of shots. */
50 uint32_t volatile cShots;
51 /** The shot at which action is to be taken. */
52 uint32_t iActionShot;
53 /** The RC of whatever operation performed in the handler. */
54 int volatile rc;
55} TSTRTR0TIMERS1;
56typedef TSTRTR0TIMERS1 *PTSTRTR0TIMERS1;
57
58
59/**
60 * Callback which increments destroy the timer when it fires.
61 *
62 * @param pTimer The timer.
63 * @param iTick The current tick.
64 * @param pvUser The user argument.
65 */
66static DECLCALLBACK(void) tstRTR0TimerCallbackDestroyOnce(PRTTIMER pTimer, void *pvUser, uint64_t iTick)
67{
68 PTSTRTR0TIMERS1 pState = (PTSTRTR0TIMERS1)pvUser;
69 uint32_t iShot = ASMAtomicIncU32(&pState->cShots);
70
71 if (iShot <= RT_ELEMENTS(pState->aShotNsTSes))
72 pState->aShotNsTSes[iShot - 1] = RTTimeSystemNanoTS();
73
74 if (iShot == pState->iActionShot + 1)
75 RTR0TESTR0_CHECK_RC(pState->rc = RTTimerDestroy(pTimer), VINF_SUCCESS);
76}
77
78
79/**
80 * Callback which increments restarts a timer once.
81 *
82 * @param pTimer The timer.
83 * @param iTick The current tick.
84 * @param pvUser The user argument.
85 */
86static DECLCALLBACK(void) tstRTR0TimerCallbackRestartOnce(PRTTIMER pTimer, void *pvUser, uint64_t iTick)
87{
88 PTSTRTR0TIMERS1 pState = (PTSTRTR0TIMERS1)pvUser;
89 uint32_t iShot = ASMAtomicIncU32(&pState->cShots);
90
91 if (iShot <= RT_ELEMENTS(pState->aShotNsTSes))
92 pState->aShotNsTSes[iShot - 1] = RTTimeSystemNanoTS();
93
94 if (iShot == pState->iActionShot + 1)
95 RTR0TESTR0_CHECK_RC(pState->rc = RTTimerStart(pTimer, 10000000 /* 10ms */), VINF_SUCCESS);
96}
97
98
99/**
100 * Callback which increments a 32-bit counter.
101 *
102 * @param pTimer The timer.
103 * @param iTick The current tick.
104 * @param pvUser The user argument.
105 */
106static DECLCALLBACK(void) tstRTR0TimerCallbackU32Counter(PRTTIMER pTimer, void *pvUser, uint64_t iTick)
107{
108 PTSTRTR0TIMERS1 pState = (PTSTRTR0TIMERS1)pvUser;
109 uint32_t iShot = ASMAtomicIncU32(&pState->cShots);
110
111 if (iShot <= RT_ELEMENTS(pState->aShotNsTSes))
112 pState->aShotNsTSes[iShot - 1] = RTTimeSystemNanoTS();
113}
114
115
116/**
117 * Checks that the interval between two timer shots are within the specified
118 * range.
119 *
120 * @returns 0 if ok, 1 if bad.
121 * @param iShot The shot number (for bitching).
122 * @param uPrevTS The time stamp of the previous shot (ns).
123 * @param uThisTS The timer stamp of this shot (ns).
124 * @param uMin The minimum interval (ns).
125 * @param uMax The maximum interval (ns).
126 */
127static int tstRTR0TimerCheckShotInterval(uint32_t iShot, uint64_t uPrevTS, uint64_t uThisTS, uint32_t uMin, uint32_t uMax)
128{
129 uint64_t uDelta = uThisTS - uPrevTS;
130 RTR0TESTR0_CHECK_MSG_RET(uDelta >= uMin, ("iShot=%u uDelta=%lld uMin=%u\n", iShot, uDelta, uMin), 1);
131 RTR0TESTR0_CHECK_MSG_RET(uDelta <= uMax, ("iShot=%u uDelta=%lld uMax=%u\n", iShot, uDelta, uMax), 1);
132 return 0;
133}
134
135
136/**
137 * Checks that the interval between timer shots are within a certain range.
138 *
139 * @returns Number of violations (i.e. 0 is ok).
140 * @param pState The state.
141 * @param uStartNsTS The start time stamp (ns).
142 * @param uMin The minimum interval (ns).
143 * @param uMax The maximum interval (ns).
144 */
145static int tstRTR0TimerCheckShotIntervals(PTSTRTR0TIMERS1 pState, uint64_t uStartNsTS, uint32_t uMin, uint32_t uMax)
146{
147 uint64_t uMaxDelta = 0;
148 uint64_t uMinDelta = UINT64_MAX;
149 uint32_t cBadShots = 0;
150 uint32_t cShots = pState->cShots;
151 uint64_t uPrevTS = uStartNsTS;
152 for (uint32_t iShot = 0; iShot < cShots; iShot++)
153 {
154 uint64_t uThisTS = pState->aShotNsTSes[iShot];
155 uint64_t uDelta = uThisTS - uPrevTS;
156 if (uDelta > uMaxDelta)
157 uMaxDelta = uDelta;
158 if (uDelta < uMinDelta)
159 uMinDelta = uDelta;
160 cBadShots += !(uDelta >= uMin && uDelta <= uMax);
161
162 RTR0TESTR0_CHECK_MSG(uDelta >= uMin, ("iShot=%u uDelta=%lld uMin=%u\n", iShot, uDelta, uMin));
163 RTR0TESTR0_CHECK_MSG(uDelta <= uMax, ("iShot=%u uDelta=%lld uMax=%u\n", iShot, uDelta, uMax));
164
165 uPrevTS = uThisTS;
166 }
167
168 RTR0TestR0Info("uMaxDelta=%llu uMinDelta=%llu\n", uMaxDelta, uMinDelta);
169 return cBadShots;
170}
171
172
173/**
174 * Service request callback function.
175 *
176 * @returns VBox status code.
177 * @param pSession The caller's session.
178 * @param u64Arg 64-bit integer argument.
179 * @param pReqHdr The request header. Input / Output. Optional.
180 */
181DECLEXPORT(int) TSTRTR0TimerSrvReqHandler(PSUPDRVSESSION pSession, uint32_t uOperation,
182 uint64_t u64Arg, PSUPR0SERVICEREQHDR pReqHdr)
183{
184 RTR0TESTR0_SRV_REQ_PROLOG_RET(pReqHdr);
185 if (u64Arg)
186 return VERR_INVALID_PARAMETER;
187
188 /*
189 * The big switch.
190 */
191 uint32_t const cNsSysHz = RTTimerGetSystemGranularity();
192 TSTRTR0TIMERS1 State;
193 switch (uOperation)
194 {
195 RTR0TESTR0_IMPLEMENT_SANITY_CASES();
196 RTR0TESTR0_IMPLEMENT_DEFAULT_CASE(uOperation);
197
198 case TSTRTR0TIMER_ONE_SHOT_BASIC:
199 case TSTRTR0TIMER_ONE_SHOT_BASIC_HIRES:
200 {
201 /* Check that RTTimerGetSystemGranularity works. */
202 RTR0TESTR0_CHECK_MSG_BREAK(cNsSysHz > UINT32_C(0) && cNsSysHz < UINT32_C(1000000000), ("%u", cNsSysHz));
203
204 /* Create a one-shot timer and take one shot. */
205 PRTTIMER pTimer;
206 uint32_t fFlags = uOperation != TSTRTR0TIMER_ONE_SHOT_BASIC_HIRES ? RTTIMER_FLAGS_HIGH_RES : 0;
207 RTR0TESTR0_CHECK_RC_BREAK(RTTimerCreateEx(&pTimer, 0, fFlags, tstRTR0TimerCallbackU32Counter, &State),
208 VINF_SUCCESS);
209
210 do /* break loop */
211 {
212 RT_ZERO(State);
213 RTR0TESTR0_CHECK_RC_BREAK(RTTimerStart(pTimer, 0), VINF_SUCCESS);
214 for (uint32_t i = 0; i < 1000 && !ASMAtomicUoReadU32(&State.cShots); i++)
215 RTThreadSleep(5);
216 RTR0TESTR0_CHECK_MSG_BREAK(ASMAtomicUoReadU32(&State.cShots) == 1, ("cShots=%u\n", State.cShots));
217
218 /* check that it is restartable. */
219 RT_ZERO(State);
220 RTR0TESTR0_CHECK_RC_BREAK(RTTimerStart(pTimer, 0), VINF_SUCCESS);
221 for (uint32_t i = 0; i < 1000 && !ASMAtomicUoReadU32(&State.cShots); i++)
222 RTThreadSleep(5);
223 RTR0TESTR0_CHECK_MSG_BREAK(ASMAtomicUoReadU32(&State.cShots) == 1, ("cShots=%u\n", State.cShots));
224
225 /* check that it respects the timeout value and can be cancelled. */
226 RT_ZERO(State);
227 RTR0TESTR0_CHECK_RC(RTTimerStart(pTimer, 5*UINT64_C(1000000000)), VINF_SUCCESS);
228 RTR0TESTR0_CHECK_RC(RTTimerStop(pTimer), VINF_SUCCESS);
229 RTThreadSleep(1);
230 RTR0TESTR0_CHECK_MSG_BREAK(ASMAtomicUoReadU32(&State.cShots) == 0, ("cShots=%u\n", State.cShots));
231
232 /* Check some double starts and stops (shall not assert). */
233 RT_ZERO(State);
234 RTR0TESTR0_CHECK_RC(RTTimerStart(pTimer, 5*UINT64_C(1000000000)), VINF_SUCCESS);
235 RTR0TESTR0_CHECK_RC(RTTimerStart(pTimer, 0), VERR_TIMER_ACTIVE);
236 RTR0TESTR0_CHECK_RC(RTTimerStop(pTimer), VINF_SUCCESS);
237 RTR0TESTR0_CHECK_RC(RTTimerStop(pTimer), VERR_TIMER_SUSPENDED);
238 RTThreadSleep(1);
239 RTR0TESTR0_CHECK_MSG_BREAK(ASMAtomicUoReadU32(&State.cShots) == 0, ("cShots=%u\n", State.cShots));
240 } while (0);
241 RTR0TESTR0_CHECK_RC(RTTimerDestroy(pTimer), VINF_SUCCESS);
242 RTR0TESTR0_CHECK_RC(RTTimerDestroy(NULL), VINF_SUCCESS);
243 break;
244 }
245
246#if 1 /* might have to disable this for some host... */
247 case TSTRTR0TIMER_ONE_SHOT_RESTART:
248 case TSTRTR0TIMER_ONE_SHOT_RESTART_HIRES:
249 {
250 /* Create a one-shot timer and restart it in the callback handler. */
251 PRTTIMER pTimer;
252 uint32_t fFlags = uOperation != TSTRTR0TIMER_ONE_SHOT_RESTART_HIRES ? RTTIMER_FLAGS_HIGH_RES : 0;
253 for (uint32_t iTest = 0; iTest < 2; iTest++)
254 {
255 RTR0TESTR0_CHECK_RC_BREAK(RTTimerCreateEx(&pTimer, 0, fFlags, tstRTR0TimerCallbackRestartOnce, &State),
256 VINF_SUCCESS);
257
258 RT_ZERO(State);
259 State.iActionShot = 0;
260 do /* break loop */
261 {
262 RTR0TESTR0_CHECK_RC_BREAK(RTTimerStart(pTimer, cNsSysHz * iTest), VINF_SUCCESS);
263 for (uint32_t i = 0; i < 1000 && ASMAtomicUoReadU32(&State.cShots) < 2; i++)
264 RTThreadSleep(5);
265 RTR0TESTR0_CHECK_MSG_BREAK(ASMAtomicUoReadU32(&State.cShots) == 2, ("cShots=%u\n", State.cShots));
266 } while (0);
267 RTR0TESTR0_CHECK_RC(RTTimerDestroy(pTimer), VINF_SUCCESS);
268 }
269 break;
270 }
271#endif
272
273#if 1 /* might have to disable this for some host... */
274 case TSTRTR0TIMER_ONE_SHOT_DESTROY:
275 case TSTRTR0TIMER_ONE_SHOT_DESTROY_HIRES:
276 {
277 /* Create a one-shot timer and destroy it in the callback handler. */
278 PRTTIMER pTimer;
279 uint32_t fFlags = uOperation != TSTRTR0TIMER_ONE_SHOT_DESTROY_HIRES ? RTTIMER_FLAGS_HIGH_RES : 0;
280 for (uint32_t iTest = 0; iTest < 2; iTest++)
281 {
282 RTR0TESTR0_CHECK_RC_BREAK(RTTimerCreateEx(&pTimer, 0, fFlags, tstRTR0TimerCallbackDestroyOnce, &State),
283 VINF_SUCCESS);
284
285 RT_ZERO(State);
286 State.rc = VERR_IPE_UNINITIALIZED_STATUS;
287 State.iActionShot = 0;
288 do /* break loop */
289 {
290 RTR0TESTR0_CHECK_RC_BREAK(RTTimerStart(pTimer, cNsSysHz * iTest), VINF_SUCCESS);
291 for (uint32_t i = 0; i < 1000 && ASMAtomicUoReadU32(&State.cShots) < 1; i++)
292 RTThreadSleep(5);
293 RTR0TESTR0_CHECK_MSG_BREAK(ASMAtomicReadU32(&State.cShots) == 1, ("cShots=%u\n", State.cShots));
294 RTR0TESTR0_CHECK_MSG_BREAK(State.rc == VINF_SUCCESS, ("rc=%Rrc\n", State.rc));
295 } while (0);
296 if (RT_FAILURE(State.rc))
297 RTR0TESTR0_CHECK_RC(RTTimerDestroy(pTimer), VINF_SUCCESS);
298 }
299 break;
300 }
301#endif
302
303 case TSTRTR0TIMER_PERIODIC_BASIC:
304 case TSTRTR0TIMER_PERIODIC_BASIC_HIRES:
305 {
306 /* Create a periodic timer running at 10 HZ. */
307 uint32_t const u10HzAsNs = 100000000;
308 uint32_t const u10HzAsNsMin = u10HzAsNs - u10HzAsNs / 2;
309 uint32_t const u10HzAsNsMax = u10HzAsNs + u10HzAsNs / 2;
310 PRTTIMER pTimer;
311 uint32_t fFlags = uOperation != TSTRTR0TIMER_ONE_SHOT_BASIC_HIRES ? RTTIMER_FLAGS_HIGH_RES : 0;
312 RTR0TESTR0_CHECK_RC_BREAK(RTTimerCreateEx(&pTimer, u10HzAsNs, fFlags, tstRTR0TimerCallbackU32Counter, &State),
313 VINF_SUCCESS);
314
315 for (uint32_t iTest = 0; iTest < 2; iTest++)
316 {
317 RT_ZERO(State);
318 uint64_t uStartNsTS = RTTimeSystemNanoTS();
319 RTR0TESTR0_CHECK_RC_BREAK(RTTimerStart(pTimer, u10HzAsNs), VINF_SUCCESS);
320 for (uint32_t i = 0; i < 1000 && ASMAtomicUoReadU32(&State.cShots) < 10; i++)
321 RTThreadSleep(10);
322 RTR0TESTR0_CHECK_RC_BREAK(RTTimerStop(pTimer), VINF_SUCCESS);
323 RTR0TESTR0_CHECK_MSG_BREAK(ASMAtomicUoReadU32(&State.cShots) == 10, ("cShots=%u\n", State.cShots));
324 if (tstRTR0TimerCheckShotIntervals(&State, uStartNsTS, u10HzAsNsMin, u10HzAsNsMax))
325 break;
326 }
327 RTR0TESTR0_CHECK_RC(RTTimerDestroy(pTimer), VINF_SUCCESS);
328 RTR0TESTR0_CHECK_RC(RTTimerDestroy(NULL), VINF_SUCCESS);
329 break;
330 }
331
332 case TSTRTR0TIMER_PERIODIC_CSSD_LOOPS:
333 case TSTRTR0TIMER_PERIODIC_CSSD_LOOPS_HIRES:
334 {
335 /* create, start, stop & destroy high res timers a number of times. */
336 uint32_t fFlags = uOperation != TSTRTR0TIMER_PERIODIC_CSSD_LOOPS_HIRES ? RTTIMER_FLAGS_HIGH_RES : 0;
337 for (uint32_t i = 0; i < 40; i++)
338 {
339 PRTTIMER pTimer;
340 RTR0TESTR0_CHECK_RC_BREAK(RTTimerCreateEx(&pTimer, cNsSysHz, fFlags, tstRTR0TimerCallbackU32Counter, &State),
341 VINF_SUCCESS);
342 for (uint32_t j = 0; j < 10; j++)
343 {
344 RT_ZERO(State);
345 RTR0TESTR0_CHECK_RC_BREAK(RTTimerStart(pTimer, i < 20 ? 0 : cNsSysHz), VINF_SUCCESS);
346 for (uint32_t k = 0; k < 1000 && ASMAtomicUoReadU32(&State.cShots) < 2; k++)
347 RTThreadSleep(1);
348 RTR0TESTR0_CHECK_RC_BREAK(RTTimerStop(pTimer), VINF_SUCCESS);
349 }
350 RTR0TESTR0_CHECK_RC(RTTimerDestroy(pTimer), VINF_SUCCESS);
351 }
352 break;
353 }
354
355 }
356
357 RTR0TESTR0_SRV_REQ_EPILOG(pReqHdr);
358 /* The error indicator is the '!' in the message buffer. */
359 return VINF_SUCCESS;
360}
361
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

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