VirtualBox

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

Last change on this file since 47737 was 47642, checked in by vboxsync, 12 years ago

tstRTR0Timer: one-shot timers are not supported on Solaris

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 35.2 KB
Line 
1/* $Id: tstRTR0Timer.cpp 47642 2013-08-09 13:27:24Z vboxsync $ */
2/** @file
3 * IPRT R0 Testcase - Timers.
4 */
5
6/*
7 * Copyright (C) 2009-2013 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.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/*******************************************************************************
29* Header Files *
30*******************************************************************************/
31#include <iprt/timer.h>
32
33#include <iprt/asm.h>
34#include <iprt/cpuset.h>
35#include <iprt/err.h>
36#include <iprt/mem.h>
37#include <iprt/mp.h>
38#include <iprt/param.h>
39#include <iprt/string.h>
40#include <iprt/thread.h>
41#include <iprt/time.h>
42#include <VBox/sup.h>
43#include "tstRTR0Timer.h"
44#include "tstRTR0Common.h"
45
46
47/*******************************************************************************
48* Structures and Typedefs *
49*******************************************************************************/
50typedef struct
51{
52 /** Array of nano second timestamp of the first few shots. */
53 uint64_t volatile aShotNsTSes[10];
54 /** The number of shots. */
55 uint32_t volatile cShots;
56 /** The shot at which action is to be taken. */
57 uint32_t iActionShot;
58 /** The RC of whatever operation performed in the handler. */
59 int volatile rc;
60 /** Set if it's a periodic test. */
61 bool fPeriodic;
62 /** Test specific stuff. */
63 union
64 {
65 /** tstRTR0TimerCallbackU32ChangeInterval parameters. */
66 struct
67 {
68 /** The interval change step. */
69 uint32_t cNsChangeStep;
70 /** The current timer interval. */
71 uint32_t cNsCurInterval;
72 /** The minimum interval. */
73 uint32_t cNsMinInterval;
74 /** The maximum interval. */
75 uint32_t cNsMaxInterval;
76 /** Direction flag; false = decrement, true = increment. */
77 bool fDirection;
78 /** The number of steps between each change. */
79 uint8_t cStepsBetween;
80 } ChgInt;
81 /** tstRTR0TimerCallbackSpecific parameters. */
82 struct
83 {
84 /** The expected CPU. */
85 RTCPUID idCpu;
86 /** Set if this failed. */
87 bool fFailed;
88 } Specific;
89 } u;
90} TSTRTR0TIMERS1;
91typedef TSTRTR0TIMERS1 *PTSTRTR0TIMERS1;
92
93
94/**
95 * Per cpu state for an omni timer test.
96 */
97typedef struct TSTRTR0TIMEROMNI1
98{
99 /** When we started receiving timer callbacks on this CPU. */
100 uint64_t u64Start;
101 /** When we received the last tick on this timer. */
102 uint64_t u64Last;
103 /** The number of ticks received on this CPU. */
104 uint32_t volatile cTicks;
105 uint32_t u32Padding;
106} TSTRTR0TIMEROMNI1;
107typedef TSTRTR0TIMEROMNI1 *PTSTRTR0TIMEROMNI1;
108
109
110/**
111 * Callback which increments a 32-bit counter.
112 *
113 * @param pTimer The timer.
114 * @param iTick The current tick.
115 * @param pvUser The user argument.
116 */
117static DECLCALLBACK(void) tstRTR0TimerCallbackOmni(PRTTIMER pTimer, void *pvUser, uint64_t iTick)
118{
119 PTSTRTR0TIMEROMNI1 paStates = (PTSTRTR0TIMEROMNI1)pvUser;
120 RTCPUID idCpu = RTMpCpuId();
121 uint32_t iCpu = RTMpCpuIdToSetIndex(idCpu);
122 NOREF(pTimer);
123
124 RTR0TESTR0_CHECK_MSG(iCpu < RTCPUSET_MAX_CPUS, ("iCpu=%d idCpu=%u\n", iCpu, idCpu));
125 if (iCpu < RTCPUSET_MAX_CPUS)
126 {
127 uint32_t iCountedTick = ASMAtomicIncU32(&paStates[iCpu].cTicks);
128 RTR0TESTR0_CHECK_MSG(iCountedTick == iTick,
129 ("iCountedTick=%u iTick=%u iCpu=%d idCpu=%u\n", iCountedTick, iTick, iCpu, idCpu));
130 paStates[iCpu].u64Last = RTTimeSystemNanoTS();
131 if (!paStates[iCpu].u64Start)
132 {
133 paStates[iCpu].u64Start = paStates[iCpu].u64Last;
134 RTR0TESTR0_CHECK_MSG(iCountedTick == 1, ("iCountedTick=%u iCpu=%d idCpu=%u\n", iCountedTick, iCpu, idCpu));
135 }
136 }
137}
138
139
140/**
141 * Callback which increments a 32-bit counter.
142 *
143 * @param pTimer The timer.
144 * @param iTick The current tick.
145 * @param pvUser The user argument.
146 */
147static DECLCALLBACK(void) tstRTR0TimerCallbackSpecific(PRTTIMER pTimer, void *pvUser, uint64_t iTick)
148{
149 PTSTRTR0TIMERS1 pState = (PTSTRTR0TIMERS1)pvUser;
150 uint32_t iShot = ASMAtomicIncU32(&pState->cShots);
151 NOREF(pTimer);
152
153 if (iShot <= RT_ELEMENTS(pState->aShotNsTSes))
154 pState->aShotNsTSes[iShot - 1] = RTTimeSystemNanoTS();
155
156 RTCPUID idCpu = RTMpCpuId();
157 if (pState->u.Specific.idCpu != idCpu)
158 pState->u.Specific.fFailed = true;
159 RTR0TESTR0_CHECK_MSG(pState->u.Specific.idCpu == idCpu, ("idCpu=%u, expected %u\n", idCpu, pState->u.Specific.idCpu));
160
161 if (pState->fPeriodic)
162 RTR0TESTR0_CHECK_MSG(iShot == iTick, ("iShot=%u iTick=%u\n", iShot, iTick));
163 else
164 RTR0TESTR0_CHECK_MSG(iTick == 1, ("iShot=%u iTick=%u\n", iShot, iTick));
165}
166
167
168/**
169 * Callback which changes the interval at each invocation.
170 *
171 * The changes are governed by TSTRTR0TIMERS1::ChangeInterval. The callback
172 * calls RTTimerStop at iActionShot.
173 *
174 * @param pTimer The timer.
175 * @param iTick The current tick.
176 * @param pvUser The user argument.
177 */
178static DECLCALLBACK(void) tstRTR0TimerCallbackChangeInterval(PRTTIMER pTimer, void *pvUser, uint64_t iTick)
179{
180 PTSTRTR0TIMERS1 pState = (PTSTRTR0TIMERS1)pvUser;
181 uint32_t iShot = ASMAtomicIncU32(&pState->cShots) - 1;
182
183 if (iShot < RT_ELEMENTS(pState->aShotNsTSes))
184 pState->aShotNsTSes[iShot] = RTTimeSystemNanoTS();
185 if (pState->fPeriodic)
186 RTR0TESTR0_CHECK_MSG(iShot + 1 == iTick, ("iShot=%u iTick=%u\n", iShot, iTick));
187 else
188 RTR0TESTR0_CHECK_MSG(iTick == 1, ("iShot=%u iTick=%u\n", iShot, iTick));
189
190 if (!(iShot % pState->u.ChgInt.cStepsBetween))
191 {
192 if (pState->u.ChgInt.fDirection)
193 {
194 pState->u.ChgInt.cNsCurInterval += pState->u.ChgInt.cNsChangeStep;
195 if ( pState->u.ChgInt.cNsCurInterval > pState->u.ChgInt.cNsMaxInterval
196 || pState->u.ChgInt.cNsCurInterval < pState->u.ChgInt.cNsMinInterval
197 || !pState->u.ChgInt.cNsCurInterval)
198 {
199 pState->u.ChgInt.cNsCurInterval = pState->u.ChgInt.cNsMaxInterval;
200 pState->u.ChgInt.fDirection = false;
201 }
202 }
203 else
204 {
205 pState->u.ChgInt.cNsCurInterval -= pState->u.ChgInt.cNsChangeStep;
206 if ( pState->u.ChgInt.cNsCurInterval < pState->u.ChgInt.cNsMinInterval
207 || pState->u.ChgInt.cNsCurInterval > pState->u.ChgInt.cNsMaxInterval
208 || pState->u.ChgInt.cNsCurInterval)
209 {
210 pState->u.ChgInt.cNsCurInterval = pState->u.ChgInt.cNsMinInterval;
211 pState->u.ChgInt.fDirection = true;
212 }
213 }
214
215 RTR0TESTR0_CHECK_RC(RTTimerChangeInterval(pTimer, pState->u.ChgInt.cNsCurInterval), VINF_SUCCESS);
216 }
217
218 if (iShot == pState->iActionShot)
219 RTR0TESTR0_CHECK_RC(pState->rc = RTTimerStop(pTimer), VINF_SUCCESS);
220}
221
222
223/**
224 * Callback which increments destroy the timer when it fires.
225 *
226 * @param pTimer The timer.
227 * @param iTick The current tick.
228 * @param pvUser The user argument.
229 */
230static DECLCALLBACK(void) tstRTR0TimerCallbackDestroyOnce(PRTTIMER pTimer, void *pvUser, uint64_t iTick)
231{
232 PTSTRTR0TIMERS1 pState = (PTSTRTR0TIMERS1)pvUser;
233 uint32_t iShot = ASMAtomicIncU32(&pState->cShots);
234
235 if (iShot <= RT_ELEMENTS(pState->aShotNsTSes))
236 pState->aShotNsTSes[iShot - 1] = RTTimeSystemNanoTS();
237 if (pState->fPeriodic)
238 RTR0TESTR0_CHECK_MSG(iShot == iTick, ("iShot=%u iTick=%u\n", iShot, iTick));
239 else
240 RTR0TESTR0_CHECK_MSG(iTick == 1, ("iShot=%u iTick=%u\n", iShot, iTick));
241
242 if (iShot == pState->iActionShot + 1)
243 RTR0TESTR0_CHECK_RC(pState->rc = RTTimerDestroy(pTimer), VINF_SUCCESS);
244}
245
246
247/**
248 * Callback which increments restarts a timer once.
249 *
250 * @param pTimer The timer.
251 * @param iTick The current tick.
252 * @param pvUser The user argument.
253 */
254static DECLCALLBACK(void) tstRTR0TimerCallbackRestartOnce(PRTTIMER pTimer, void *pvUser, uint64_t iTick)
255{
256 PTSTRTR0TIMERS1 pState = (PTSTRTR0TIMERS1)pvUser;
257 uint32_t iShot = ASMAtomicIncU32(&pState->cShots);
258
259 if (iShot <= RT_ELEMENTS(pState->aShotNsTSes))
260 pState->aShotNsTSes[iShot - 1] = RTTimeSystemNanoTS();
261 if (pState->fPeriodic)
262 RTR0TESTR0_CHECK_MSG(iShot == iTick, ("iShot=%u iTick=%u\n", iShot, iTick));
263 else
264 RTR0TESTR0_CHECK_MSG(iTick == 1, ("iShot=%u iTick=%u\n", iShot, iTick));
265
266 if (iShot == pState->iActionShot + 1)
267 RTR0TESTR0_CHECK_RC(pState->rc = RTTimerStart(pTimer, 10000000 /* 10ms */), VINF_SUCCESS);
268}
269
270
271/**
272 * Callback which increments a 32-bit counter.
273 *
274 * @param pTimer The timer.
275 * @param iTick The current tick.
276 * @param pvUser The user argument.
277 */
278static DECLCALLBACK(void) tstRTR0TimerCallbackU32Counter(PRTTIMER pTimer, void *pvUser, uint64_t iTick)
279{
280 PTSTRTR0TIMERS1 pState = (PTSTRTR0TIMERS1)pvUser;
281 uint32_t iShot = ASMAtomicIncU32(&pState->cShots);
282 NOREF(pTimer);
283
284 if (iShot <= RT_ELEMENTS(pState->aShotNsTSes))
285 pState->aShotNsTSes[iShot - 1] = RTTimeSystemNanoTS();
286 if (pState->fPeriodic)
287 RTR0TESTR0_CHECK_MSG(iShot == iTick, ("iShot=%u iTick=%u\n", iShot, iTick));
288 else
289 RTR0TESTR0_CHECK_MSG(iTick == 1, ("iShot=%u iTick=%u\n", iShot, iTick));
290}
291
292
293#ifdef SOME_UNUSED_FUNCTION
294/**
295 * Checks that the interval between two timer shots are within the specified
296 * range.
297 *
298 * @returns 0 if ok, 1 if bad.
299 * @param iShot The shot number (for bitching).
300 * @param uPrevTS The time stamp of the previous shot (ns).
301 * @param uThisTS The timer stamp of this shot (ns).
302 * @param uMin The minimum interval (ns).
303 * @param uMax The maximum interval (ns).
304 */
305static int tstRTR0TimerCheckShotInterval(uint32_t iShot, uint64_t uPrevTS, uint64_t uThisTS, uint32_t uMin, uint32_t uMax)
306{
307 uint64_t uDelta = uThisTS - uPrevTS;
308 RTR0TESTR0_CHECK_MSG_RET(uDelta >= uMin, ("iShot=%u uDelta=%lld uMin=%u\n", iShot, uDelta, uMin), 1);
309 RTR0TESTR0_CHECK_MSG_RET(uDelta <= uMax, ("iShot=%u uDelta=%lld uMax=%u\n", iShot, uDelta, uMax), 1);
310 return 0;
311}
312#endif
313
314
315/**
316 * Checks that the interval between timer shots are within a certain range.
317 *
318 * @returns Number of violations (i.e. 0 is ok).
319 * @param pState The state.
320 * @param uStartNsTS The start time stamp (ns).
321 * @param uMin The minimum interval (ns).
322 * @param uMax The maximum interval (ns).
323 */
324static int tstRTR0TimerCheckShotIntervals(PTSTRTR0TIMERS1 pState, uint64_t uStartNsTS, uint32_t uMin, uint32_t uMax)
325{
326 uint64_t uMaxDelta = 0;
327 uint64_t uMinDelta = UINT64_MAX;
328 uint32_t cBadShots = 0;
329 uint32_t cShots = pState->cShots;
330 uint64_t uPrevTS = uStartNsTS;
331 for (uint32_t iShot = 0; iShot < cShots; iShot++)
332 {
333 uint64_t uThisTS = pState->aShotNsTSes[iShot];
334 uint64_t uDelta = uThisTS - uPrevTS;
335 if (uDelta > uMaxDelta)
336 uMaxDelta = uDelta;
337 if (uDelta < uMinDelta)
338 uMinDelta = uDelta;
339 cBadShots += !(uDelta >= uMin && uDelta <= uMax);
340
341 RTR0TESTR0_CHECK_MSG(uDelta >= uMin, ("iShot=%u uDelta=%lld uMin=%u\n", iShot, uDelta, uMin));
342 RTR0TESTR0_CHECK_MSG(uDelta <= uMax, ("iShot=%u uDelta=%lld uMax=%u\n", iShot, uDelta, uMax));
343
344 uPrevTS = uThisTS;
345 }
346
347 RTR0TestR0Info("uMaxDelta=%llu uMinDelta=%llu\n", uMaxDelta, uMinDelta);
348 return cBadShots;
349}
350
351
352/**
353 * Service request callback function.
354 *
355 * @returns VBox status code.
356 * @param pSession The caller's session.
357 * @param u64Arg 64-bit integer argument.
358 * @param pReqHdr The request header. Input / Output. Optional.
359 */
360DECLEXPORT(int) TSTRTR0TimerSrvReqHandler(PSUPDRVSESSION pSession, uint32_t uOperation,
361 uint64_t u64Arg, PSUPR0SERVICEREQHDR pReqHdr)
362{
363 RTR0TESTR0_SRV_REQ_PROLOG_RET(pReqHdr);
364 NOREF(pSession);
365
366 /*
367 * Common parameter and state variables.
368 */
369 uint32_t const cNsSysHz = RTTimerGetSystemGranularity();
370 uint32_t const cNsMaxHighResHz = 10000; /** @todo need API for this */
371 TSTRTR0TIMERS1 State;
372 if ( cNsSysHz < UINT32_C(1000)
373 || cNsSysHz > UINT32_C(1000000000)
374 || cNsMaxHighResHz < UINT32_C(1)
375 || cNsMaxHighResHz > UINT32_C(1000000000))
376 {
377 RTR0TESTR0_CHECK_MSG(cNsSysHz > UINT32_C(1000) && cNsSysHz < UINT32_C(1000000000), ("%u", cNsSysHz));
378 RTR0TESTR0_CHECK_MSG(cNsMaxHighResHz > UINT32_C(1) && cNsMaxHighResHz < UINT32_C(1000000000), ("%u", cNsMaxHighResHz));
379 RTR0TESTR0_SRV_REQ_EPILOG(pReqHdr);
380 return VINF_SUCCESS;
381 }
382
383 /*
384 * The big switch.
385 */
386 switch (uOperation)
387 {
388 RTR0TESTR0_IMPLEMENT_SANITY_CASES();
389 RTR0TESTR0_IMPLEMENT_DEFAULT_CASE(uOperation);
390
391 case TSTRTR0TIMER_ONE_SHOT_BASIC:
392 case TSTRTR0TIMER_ONE_SHOT_BASIC_HIRES:
393 {
394 /* Create a one-shot timer and take one shot. */
395 PRTTIMER pTimer;
396 uint32_t fFlags = TSTRTR0TIMER_IS_HIRES(uOperation) ? RTTIMER_FLAGS_HIGH_RES : 0;
397 RTR0TESTR0_CHECK_RC_BREAK(RTTimerCreateEx(&pTimer, 0, fFlags, tstRTR0TimerCallbackU32Counter, &State),
398 VINF_SUCCESS);
399
400 do /* break loop */
401 {
402 RT_ZERO(State); ASMAtomicWriteU32(&State.cShots, State.cShots);
403 int rc = RTTimerStart(pTimer, 0);
404 if (rc == VERR_NOT_SUPPORTED)
405 {
406 RTR0TestR0Info("one-shot timer are not supported, skipping\n");
407 break;
408 }
409
410 RTR0TESTR0_CHECK_RC_BREAK(rc, VINF_SUCCESS);
411 for (uint32_t i = 0; i < 1000 && !ASMAtomicUoReadU32(&State.cShots); i++)
412 RTThreadSleep(5);
413 RTR0TESTR0_CHECK_MSG_BREAK(ASMAtomicUoReadU32(&State.cShots) == 1, ("cShots=%u\n", State.cShots));
414
415 /* check that it is restartable. */
416 RT_ZERO(State); ASMAtomicWriteU32(&State.cShots, State.cShots);
417 RTR0TESTR0_CHECK_RC_BREAK(RTTimerStart(pTimer, 0), VINF_SUCCESS);
418 for (uint32_t i = 0; i < 1000 && !ASMAtomicUoReadU32(&State.cShots); i++)
419 RTThreadSleep(5);
420 RTR0TESTR0_CHECK_MSG_BREAK(ASMAtomicUoReadU32(&State.cShots) == 1, ("cShots=%u\n", State.cShots));
421
422 /* check that it respects the timeout value and can be cancelled. */
423 RT_ZERO(State); ASMAtomicWriteU32(&State.cShots, State.cShots);
424 RTR0TESTR0_CHECK_RC(RTTimerStart(pTimer, 5*UINT64_C(1000000000)), VINF_SUCCESS);
425 RTR0TESTR0_CHECK_RC(RTTimerStop(pTimer), VINF_SUCCESS);
426 RTThreadSleep(1);
427 RTR0TESTR0_CHECK_MSG_BREAK(ASMAtomicUoReadU32(&State.cShots) == 0, ("cShots=%u\n", State.cShots));
428
429 /* Check some double starts and stops (shall not assert). */
430 RT_ZERO(State); ASMAtomicWriteU32(&State.cShots, State.cShots);
431 RTR0TESTR0_CHECK_RC(RTTimerStart(pTimer, 5*UINT64_C(1000000000)), VINF_SUCCESS);
432 RTR0TESTR0_CHECK_RC(RTTimerStart(pTimer, 0), VERR_TIMER_ACTIVE);
433 RTR0TESTR0_CHECK_RC(RTTimerStop(pTimer), VINF_SUCCESS);
434 RTR0TESTR0_CHECK_RC(RTTimerStop(pTimer), VERR_TIMER_SUSPENDED);
435 RTThreadSleep(1);
436 RTR0TESTR0_CHECK_MSG_BREAK(ASMAtomicUoReadU32(&State.cShots) == 0, ("cShots=%u\n", State.cShots));
437 } while (0);
438 RTR0TESTR0_CHECK_RC(RTTimerDestroy(pTimer), VINF_SUCCESS);
439 RTR0TESTR0_CHECK_RC(RTTimerDestroy(NULL), VINF_SUCCESS);
440 break;
441 }
442
443#if 1 /* might have to disable this for some host... */
444 case TSTRTR0TIMER_ONE_SHOT_RESTART:
445 case TSTRTR0TIMER_ONE_SHOT_RESTART_HIRES:
446 {
447 /* Create a one-shot timer and restart it in the callback handler. */
448 PRTTIMER pTimer;
449 uint32_t fFlags = TSTRTR0TIMER_IS_HIRES(uOperation) ? RTTIMER_FLAGS_HIGH_RES : 0;
450 for (uint32_t iTest = 0; iTest < 2; iTest++)
451 {
452 RTR0TESTR0_CHECK_RC_BREAK(RTTimerCreateEx(&pTimer, 0, fFlags, tstRTR0TimerCallbackRestartOnce, &State),
453 VINF_SUCCESS);
454
455 RT_ZERO(State);
456 State.iActionShot = 0;
457 ASMAtomicWriteU32(&State.cShots, State.cShots);
458 do /* break loop */
459 {
460 RTR0TESTR0_CHECK_RC_BREAK(RTTimerStart(pTimer, cNsSysHz * iTest), VINF_SUCCESS);
461 for (uint32_t i = 0; i < 1000 && ASMAtomicUoReadU32(&State.cShots) < 2; i++)
462 RTThreadSleep(5);
463 RTR0TESTR0_CHECK_MSG_BREAK(ASMAtomicUoReadU32(&State.cShots) == 2, ("cShots=%u\n", State.cShots));
464 } while (0);
465 RTR0TESTR0_CHECK_RC(RTTimerDestroy(pTimer), VINF_SUCCESS);
466 }
467 break;
468 }
469#endif
470
471#if 1 /* might have to disable this for some host... */
472 case TSTRTR0TIMER_ONE_SHOT_DESTROY:
473 case TSTRTR0TIMER_ONE_SHOT_DESTROY_HIRES:
474 {
475 /* Create a one-shot timer and destroy it in the callback handler. */
476 PRTTIMER pTimer;
477 uint32_t fFlags = TSTRTR0TIMER_IS_HIRES(uOperation) ? RTTIMER_FLAGS_HIGH_RES : 0;
478 for (uint32_t iTest = 0; iTest < 2; iTest++)
479 {
480 RTR0TESTR0_CHECK_RC_BREAK(RTTimerCreateEx(&pTimer, 0, fFlags, tstRTR0TimerCallbackDestroyOnce, &State),
481 VINF_SUCCESS);
482
483 RT_ZERO(State);
484 State.rc = VERR_IPE_UNINITIALIZED_STATUS;
485 State.iActionShot = 0;
486 ASMAtomicWriteU32(&State.cShots, State.cShots);
487 do /* break loop */
488 {
489 RTR0TESTR0_CHECK_RC_BREAK(RTTimerStart(pTimer, cNsSysHz * iTest), VINF_SUCCESS);
490 for (uint32_t i = 0; i < 1000 && (ASMAtomicUoReadU32(&State.cShots) < 1 || State.rc == VERR_IPE_UNINITIALIZED_STATUS); i++)
491 RTThreadSleep(5);
492 RTR0TESTR0_CHECK_MSG_BREAK(ASMAtomicReadU32(&State.cShots) == 1, ("cShots=%u\n", State.cShots));
493 RTR0TESTR0_CHECK_MSG_BREAK(State.rc == VINF_SUCCESS, ("rc=%Rrc\n", State.rc));
494 } while (0);
495 if (RT_FAILURE(State.rc))
496 RTR0TESTR0_CHECK_RC(RTTimerDestroy(pTimer), VINF_SUCCESS);
497 }
498 break;
499 }
500#endif
501
502 case TSTRTR0TIMER_ONE_SHOT_SPECIFIC:
503 case TSTRTR0TIMER_ONE_SHOT_SPECIFIC_HIRES:
504 {
505 PRTTIMER pTimer = NULL;
506 RTCPUSET OnlineSet;
507 RTMpGetOnlineSet(&OnlineSet);
508 for (uint32_t iCpu = 0; iCpu < RTCPUSET_MAX_CPUS; iCpu++)
509 if (RTCpuSetIsMemberByIndex(&OnlineSet, iCpu))
510 {
511 RT_ZERO(State);
512 State.iActionShot = 0;
513 State.rc = VINF_SUCCESS;
514 State.u.Specific.idCpu = RTMpCpuIdFromSetIndex(iCpu);
515 ASMAtomicWriteU32(&State.cShots, State.cShots);
516
517 uint32_t fFlags = TSTRTR0TIMER_IS_HIRES(uOperation) ? RTTIMER_FLAGS_HIGH_RES : 0;
518 fFlags |= RTTIMER_FLAGS_CPU(iCpu);
519 int rc = RTTimerCreateEx(&pTimer, 0, fFlags, tstRTR0TimerCallbackSpecific, &State);
520 if (rc == VERR_NOT_SUPPORTED)
521 {
522 RTR0TestR0Info("specific timer are not supported, skipping\n");
523 break;
524 }
525 RTR0TESTR0_CHECK_RC_BREAK(rc, VINF_SUCCESS);
526
527 for (uint32_t i = 0; i < 5 && !RTR0TestR0HaveErrors(); i++)
528 {
529 ASMAtomicWriteU32(&State.cShots, 0);
530 RTR0TESTR0_CHECK_RC_BREAK(RTTimerStart(pTimer, (i & 2 ? cNsSysHz : cNsSysHz / 2) * (i & 1)), VINF_SUCCESS);
531 uint64_t cNsElapsed = RTTimeSystemNanoTS();
532 for (uint32_t j = 0; j < 1000 && ASMAtomicUoReadU32(&State.cShots) < 1; j++)
533 RTThreadSleep(5);
534 cNsElapsed = RTTimeSystemNanoTS() - cNsElapsed;
535 RTR0TESTR0_CHECK_MSG_BREAK(ASMAtomicReadU32(&State.cShots) == 1,
536 ("cShots=%u iCpu=%u i=%u iCurCpu=%u cNsElapsed=%'llu\n",
537 State.cShots, iCpu, i, RTMpCpuIdToSetIndex(RTMpCpuId()), cNsElapsed ));
538 RTR0TESTR0_CHECK_MSG_BREAK(State.rc == VINF_SUCCESS, ("rc=%Rrc\n", State.rc));
539 RTR0TESTR0_CHECK_MSG_BREAK(!State.u.Specific.fFailed, ("iCpu=%u i=%u\n", iCpu, i));
540 }
541
542 RTR0TESTR0_CHECK_RC(RTTimerDestroy(pTimer), VINF_SUCCESS);
543 pTimer = NULL;
544 if (RTR0TestR0HaveErrors())
545 break;
546
547 RTMpGetOnlineSet(&OnlineSet);
548 }
549 RTR0TESTR0_CHECK_RC(RTTimerDestroy(pTimer), VINF_SUCCESS);
550 break;
551 }
552
553 case TSTRTR0TIMER_PERIODIC_BASIC:
554 case TSTRTR0TIMER_PERIODIC_BASIC_HIRES:
555 {
556 /* Create a periodic timer running at 10 HZ. */
557 uint32_t const u10HzAsNs = 100000000;
558 uint32_t const u10HzAsNsMin = u10HzAsNs - u10HzAsNs / 2;
559 uint32_t const u10HzAsNsMax = u10HzAsNs + u10HzAsNs / 2;
560 PRTTIMER pTimer;
561 uint32_t fFlags = TSTRTR0TIMER_IS_HIRES(uOperation) ? RTTIMER_FLAGS_HIGH_RES : 0;
562 RTR0TESTR0_CHECK_RC_BREAK(RTTimerCreateEx(&pTimer, u10HzAsNs, fFlags, tstRTR0TimerCallbackU32Counter, &State),
563 VINF_SUCCESS);
564
565 for (uint32_t iTest = 0; iTest < 2; iTest++)
566 {
567 RT_ZERO(State);
568 State.fPeriodic = true;
569 ASMAtomicWriteU32(&State.cShots, State.cShots);
570
571 uint64_t uStartNsTS = RTTimeSystemNanoTS();
572 RTR0TESTR0_CHECK_RC_BREAK(RTTimerStart(pTimer, u10HzAsNs), VINF_SUCCESS);
573 for (uint32_t i = 0; i < 1000 && ASMAtomicUoReadU32(&State.cShots) < 10; i++)
574 RTThreadSleep(10);
575 RTR0TESTR0_CHECK_RC_BREAK(RTTimerStop(pTimer), VINF_SUCCESS);
576 RTR0TESTR0_CHECK_MSG_BREAK(ASMAtomicUoReadU32(&State.cShots) == 10, ("cShots=%u\n", State.cShots));
577 if (tstRTR0TimerCheckShotIntervals(&State, uStartNsTS, u10HzAsNsMin, u10HzAsNsMax))
578 break;
579 }
580 RTR0TESTR0_CHECK_RC(RTTimerDestroy(pTimer), VINF_SUCCESS);
581 RTR0TESTR0_CHECK_RC(RTTimerDestroy(NULL), VINF_SUCCESS);
582 break;
583 }
584
585 case TSTRTR0TIMER_PERIODIC_CSSD_LOOPS:
586 case TSTRTR0TIMER_PERIODIC_CSSD_LOOPS_HIRES:
587 {
588 /* create, start, stop & destroy high res timers a number of times. */
589 uint32_t fFlags = TSTRTR0TIMER_IS_HIRES(uOperation) ? RTTIMER_FLAGS_HIGH_RES : 0;
590 for (uint32_t i = 0; i < 40; i++)
591 {
592 PRTTIMER pTimer;
593 RTR0TESTR0_CHECK_RC_BREAK(RTTimerCreateEx(&pTimer, cNsSysHz, fFlags, tstRTR0TimerCallbackU32Counter, &State),
594 VINF_SUCCESS);
595 for (uint32_t j = 0; j < 10; j++)
596 {
597 RT_ZERO(State);
598 State.fPeriodic = true;
599 ASMAtomicWriteU32(&State.cShots, State.cShots); /* ordered, necessary? */
600
601 RTR0TESTR0_CHECK_RC_BREAK(RTTimerStart(pTimer, i < 20 ? 0 : cNsSysHz), VINF_SUCCESS);
602 for (uint32_t k = 0; k < 1000 && ASMAtomicUoReadU32(&State.cShots) < 2; k++)
603 RTThreadSleep(1);
604 RTR0TESTR0_CHECK_RC_BREAK(RTTimerStop(pTimer), VINF_SUCCESS);
605 }
606 RTR0TESTR0_CHECK_RC(RTTimerDestroy(pTimer), VINF_SUCCESS);
607 }
608 break;
609 }
610
611 case TSTRTR0TIMER_PERIODIC_CHANGE_INTERVAL:
612 case TSTRTR0TIMER_PERIODIC_CHANGE_INTERVAL_HIRES:
613 {
614 /* Initialize the test parameters, using the u64Arg value for selecting variations. */
615 RT_ZERO(State);
616 State.cShots = 0;
617 State.rc = VERR_IPE_UNINITIALIZED_STATUS;
618 State.iActionShot = 42;
619 State.fPeriodic = true;
620 State.u.ChgInt.fDirection = !!(u64Arg & 1);
621 if (uOperation == TSTRTR0TIMER_PERIODIC_CHANGE_INTERVAL_HIRES)
622 {
623 State.u.ChgInt.cNsMaxInterval = RT_MAX(cNsMaxHighResHz * 10, 20000000); /* 10x / 20 ms */
624 State.u.ChgInt.cNsMinInterval = RT_MAX(cNsMaxHighResHz, 10000); /* min / 10 us */
625 }
626 else
627 {
628 State.u.ChgInt.cNsMaxInterval = cNsSysHz * 4;
629 State.u.ChgInt.cNsMinInterval = cNsSysHz;
630 }
631 State.u.ChgInt.cNsChangeStep = (State.u.ChgInt.cNsMaxInterval - State.u.ChgInt.cNsMinInterval) / 10;
632 State.u.ChgInt.cNsCurInterval = State.u.ChgInt.fDirection
633 ? State.u.ChgInt.cNsMaxInterval : State.u.ChgInt.cNsMinInterval;
634 State.u.ChgInt.cStepsBetween = u64Arg & 4 ? 1 : 3;
635 RTR0TESTR0_CHECK_MSG_BREAK(State.u.ChgInt.cNsMinInterval > 1000, ("%u\n", State.u.ChgInt.cNsMinInterval));
636 RTR0TESTR0_CHECK_MSG_BREAK(State.u.ChgInt.cNsMaxInterval > State.u.ChgInt.cNsMinInterval, ("max=%u min=%u\n", State.u.ChgInt.cNsMaxInterval, State.u.ChgInt.cNsMinInterval));
637 ASMAtomicWriteU32(&State.cShots, State.cShots);
638
639 /* create the timer and check if RTTimerChangeInterval is supported. */
640 PRTTIMER pTimer;
641 uint32_t fFlags = TSTRTR0TIMER_IS_HIRES(uOperation) ? RTTIMER_FLAGS_HIGH_RES : 0;
642 RTR0TESTR0_CHECK_RC_BREAK(RTTimerCreateEx(&pTimer, cNsSysHz, fFlags, tstRTR0TimerCallbackChangeInterval, &State),
643 VINF_SUCCESS);
644 int rc = RTTimerChangeInterval(pTimer, State.u.ChgInt.cNsMinInterval);
645 if (rc == VERR_NOT_SUPPORTED)
646 {
647 RTR0TestR0Info("RTTimerChangeInterval not supported, skipped");
648 RTR0TESTR0_CHECK_RC(RTTimerDestroy(pTimer), VINF_SUCCESS);
649 break;
650 }
651
652 /* do the test. */
653 RTR0TESTR0_CHECK_RC_BREAK(RTTimerStart(pTimer, u64Arg & 2 ? State.u.ChgInt.cNsCurInterval : 0), VINF_SUCCESS);
654 for (uint32_t k = 0;
655 k < 1000
656 && ASMAtomicReadU32(&State.cShots) <= State.iActionShot
657 && State.rc == VERR_IPE_UNINITIALIZED_STATUS;
658 k++)
659 RTThreadSleep(10);
660
661 rc = RTTimerStop(pTimer);
662 RTR0TESTR0_CHECK_MSG_BREAK(rc == VERR_TIMER_SUSPENDED || rc == VINF_SUCCESS, ("rc = %Rrc (RTTimerStop)\n", rc));
663 RTR0TESTR0_CHECK_RC(RTTimerDestroy(pTimer), VINF_SUCCESS);
664 break;
665 }
666
667 case TSTRTR0TIMER_PERIODIC_SPECIFIC:
668 case TSTRTR0TIMER_PERIODIC_SPECIFIC_HIRES:
669 {
670 PRTTIMER pTimer = NULL;
671 RTCPUSET OnlineSet;
672 RTMpGetOnlineSet(&OnlineSet);
673 for (uint32_t iCpu = 0; iCpu < RTCPUSET_MAX_CPUS; iCpu++)
674 if (RTCpuSetIsMemberByIndex(&OnlineSet, iCpu))
675 {
676 RT_ZERO(State);
677 State.iActionShot = 0;
678 State.rc = VINF_SUCCESS;
679 State.fPeriodic = true;
680 State.u.Specific.idCpu = RTMpCpuIdFromSetIndex(iCpu);
681 ASMAtomicWriteU32(&State.cShots, State.cShots);
682
683 uint32_t fFlags = TSTRTR0TIMER_IS_HIRES(uOperation) ? RTTIMER_FLAGS_HIGH_RES : 0;
684 fFlags |= RTTIMER_FLAGS_CPU(iCpu);
685 int rc = RTTimerCreateEx(&pTimer, cNsSysHz, fFlags, tstRTR0TimerCallbackSpecific, &State);
686 if (rc == VERR_NOT_SUPPORTED)
687 {
688 RTR0TestR0Info("specific timer are not supported, skipping\n");
689 break;
690 }
691 RTR0TESTR0_CHECK_RC_BREAK(rc, VINF_SUCCESS);
692
693 for (uint32_t i = 0; i < 3 && !RTR0TestR0HaveErrors(); i++)
694 {
695 ASMAtomicWriteU32(&State.cShots, 0);
696 RTR0TESTR0_CHECK_RC_BREAK(RTTimerStart(pTimer, (i & 2 ? cNsSysHz : cNsSysHz / 2) * (i & 1)), VINF_SUCCESS);
697 uint64_t cNsElapsed = RTTimeSystemNanoTS();
698 for (uint32_t j = 0; j < 1000 && ASMAtomicUoReadU32(&State.cShots) < 8; j++)
699 RTThreadSleep(5);
700 cNsElapsed = RTTimeSystemNanoTS() - cNsElapsed;
701 RTR0TESTR0_CHECK_RC_BREAK(RTTimerStop(pTimer), VINF_SUCCESS);
702 RTR0TESTR0_CHECK_MSG_BREAK(ASMAtomicReadU32(&State.cShots) > 5,
703 ("cShots=%u iCpu=%u i=%u iCurCpu=%u cNsElapsed=%'llu\n",
704 State.cShots, iCpu, i, RTMpCpuIdToSetIndex(RTMpCpuId()), cNsElapsed));
705 RTR0TESTR0_CHECK_MSG_BREAK(State.rc == VINF_SUCCESS, ("rc=%Rrc\n", State.rc));
706 RTR0TESTR0_CHECK_MSG_BREAK(!State.u.Specific.fFailed, ("iCpu=%u i=%u\n", iCpu, i));
707 }
708
709 RTR0TESTR0_CHECK_RC(RTTimerDestroy(pTimer), VINF_SUCCESS);
710 pTimer = NULL;
711 if (RTR0TestR0HaveErrors())
712 break;
713
714 RTMpGetOnlineSet(&OnlineSet);
715 }
716 RTR0TESTR0_CHECK_RC(RTTimerDestroy(pTimer), VINF_SUCCESS);
717 break;
718 }
719
720 case TSTRTR0TIMER_PERIODIC_OMNI:
721 case TSTRTR0TIMER_PERIODIC_OMNI_HIRES:
722 {
723 /* Create a periodic timer running at max host frequency, but no more than 1000 Hz. */
724 uint32_t cNsInterval = cNsSysHz;
725 while (cNsInterval < UINT32_C(1000000))
726 cNsInterval *= 2;
727 PTSTRTR0TIMEROMNI1 paStates = (PTSTRTR0TIMEROMNI1)RTMemAllocZ(sizeof(paStates[0]) * RTCPUSET_MAX_CPUS);
728 RTR0TESTR0_CHECK_MSG_BREAK(paStates, ("%d\n", RTCPUSET_MAX_CPUS));
729
730 PRTTIMER pTimer;
731 uint32_t fFlags = (TSTRTR0TIMER_IS_HIRES(uOperation) ? RTTIMER_FLAGS_HIGH_RES : 0)
732 | RTTIMER_FLAGS_CPU_ALL;
733 int rc = RTTimerCreateEx(&pTimer, cNsInterval, fFlags, tstRTR0TimerCallbackOmni, paStates);
734 if (rc == VERR_NOT_SUPPORTED)
735 {
736 RTR0TESTR0_SKIP_BREAK();
737 }
738 RTR0TESTR0_CHECK_RC_BREAK(rc, VINF_SUCCESS);
739
740 for (uint32_t iTest = 0; iTest < 3 && !RTR0TestR0HaveErrors(); iTest++)
741 {
742 /* reset the state */
743 for (uint32_t iCpu = 0; iCpu < RTCPUSET_MAX_CPUS; iCpu++)
744 {
745 paStates[iCpu].u64Start = 0;
746 paStates[iCpu].u64Last = 0;
747 ASMAtomicWriteU32(&paStates[iCpu].cTicks, 0);
748 }
749
750 /* run it for 1 second. */
751 RTCPUSET OnlineSet;
752 uint64_t uStartNsTS = RTTimeSystemNanoTS();
753 RTR0TESTR0_CHECK_RC_BREAK(RTTimerStart(pTimer, 0), VINF_SUCCESS);
754 RTMpGetOnlineSet(&OnlineSet);
755
756 for (uint32_t i = 0; i < 5000 && RTTimeSystemNanoTS() - uStartNsTS <= UINT32_C(1000000000); i++)
757 RTThreadSleep(2);
758
759 RTR0TESTR0_CHECK_RC_BREAK(RTTimerStop(pTimer), VINF_SUCCESS);
760 uint64_t cNsElapsedX = RTTimeNanoTS() - uStartNsTS;
761
762 /* Do a min/max on the start and stop times and calculate the test period. */
763 uint64_t u64MinStart = UINT64_MAX;
764 uint64_t u64MaxStop = 0;
765 for (uint32_t iCpu = 0; iCpu < RTCPUSET_MAX_CPUS; iCpu++)
766 {
767 if (paStates[iCpu].u64Start)
768 {
769 if (paStates[iCpu].u64Start < u64MinStart)
770 u64MinStart = paStates[iCpu].u64Start;
771 if (paStates[iCpu].u64Last > u64MaxStop)
772 u64MaxStop = paStates[iCpu].u64Last;
773 }
774 }
775 RTR0TESTR0_CHECK_MSG(u64MinStart < u64MaxStop, ("%llu, %llu", u64MinStart, u64MaxStop));
776 uint64_t cNsElapsed = u64MaxStop - u64MinStart;
777 RTR0TESTR0_CHECK_MSG(cNsElapsed <= cNsElapsedX + 100000, ("%llu, %llu", cNsElapsed, cNsElapsedX)); /* the fudge factor is time drift */
778 uint32_t cAvgTicks = cNsElapsed / cNsInterval + 1;
779
780 /* Check tick counts. ASSUMES no cpu on- or offlining.
781 This only catches really bad stuff. */
782 uint32_t cMinTicks = cAvgTicks - cAvgTicks / 10;
783 uint32_t cMaxTicks = cAvgTicks + cAvgTicks / 10 + 1;
784 for (uint32_t iCpu = 0; iCpu < RTCPUSET_MAX_CPUS; iCpu++)
785 if (paStates[iCpu].cTicks)
786 {
787 RTR0TESTR0_CHECK_MSG(RTCpuSetIsMemberByIndex(&OnlineSet, iCpu), ("%d\n", iCpu));
788 RTR0TESTR0_CHECK_MSG(paStates[iCpu].cTicks <= cMaxTicks && paStates[iCpu].cTicks >= cMinTicks,
789 ("min=%u, ticks=%u, avg=%u max=%u, iCpu=%u, interval=%'u, elapsed=%'llu/%'llu\n",
790 cMinTicks, paStates[iCpu].cTicks, cAvgTicks, cMaxTicks, iCpu,
791 cNsInterval, cNsElapsed, cNsElapsedX));
792 }
793 else
794 RTR0TESTR0_CHECK_MSG(!RTCpuSetIsMemberByIndex(&OnlineSet, iCpu), ("%d\n", iCpu));
795 }
796
797 RTR0TESTR0_CHECK_RC(RTTimerDestroy(pTimer), VINF_SUCCESS);
798 RTMemFree(paStates);
799 break;
800 }
801 }
802
803 RTR0TESTR0_SRV_REQ_EPILOG(pReqHdr);
804 /* The error indicator is the '!' in the message buffer. */
805 return VINF_SUCCESS;
806}
807
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