VirtualBox

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

Last change on this file since 48358 was 48165, checked in by vboxsync, 11 years ago

r0drv/solaris/timer: Fix specific periodic timers, one-shot any-cpu timers.
Fixed R0 timer testcase to not do unsupported and potentially dangerous tests on Solaris.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 35.5 KB
Line 
1/* $Id: tstRTR0Timer.cpp 48165 2013-08-29 17:16:42Z 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 int rc = RTTimerCreateEx(&pTimer, 0, fFlags, tstRTR0TimerCallbackU32Counter, &State);
398 if (rc == VERR_NOT_SUPPORTED)
399 {
400 RTR0TestR0Info("one-shot timer are not supported, skipping\n");
401 break;
402 }
403 RTR0TESTR0_CHECK_RC_BREAK(rc, VINF_SUCCESS);
404
405 do /* break loop */
406 {
407 RT_ZERO(State); ASMAtomicWriteU32(&State.cShots, State.cShots);
408 RTR0TESTR0_CHECK_RC_BREAK(RTTimerStart(pTimer, 0), VINF_SUCCESS);
409 for (uint32_t i = 0; i < 1000 && !ASMAtomicUoReadU32(&State.cShots); i++)
410 RTThreadSleep(5);
411 RTR0TESTR0_CHECK_MSG_BREAK(ASMAtomicUoReadU32(&State.cShots) == 1, ("cShots=%u\n", State.cShots));
412
413 /* check that it is restartable. */
414 RT_ZERO(State); ASMAtomicWriteU32(&State.cShots, State.cShots);
415 RTR0TESTR0_CHECK_RC_BREAK(RTTimerStart(pTimer, 0), VINF_SUCCESS);
416 for (uint32_t i = 0; i < 1000 && !ASMAtomicUoReadU32(&State.cShots); i++)
417 RTThreadSleep(5);
418 RTR0TESTR0_CHECK_MSG_BREAK(ASMAtomicUoReadU32(&State.cShots) == 1, ("cShots=%u\n", State.cShots));
419
420 /* check that it respects the timeout value and can be cancelled. */
421 RT_ZERO(State); ASMAtomicWriteU32(&State.cShots, State.cShots);
422 RTR0TESTR0_CHECK_RC(RTTimerStart(pTimer, 5*UINT64_C(1000000000)), VINF_SUCCESS);
423 RTR0TESTR0_CHECK_RC(RTTimerStop(pTimer), VINF_SUCCESS);
424 RTThreadSleep(1);
425 RTR0TESTR0_CHECK_MSG_BREAK(ASMAtomicUoReadU32(&State.cShots) == 0, ("cShots=%u\n", State.cShots));
426
427 /* Check some double starts and stops (shall not assert). */
428 RT_ZERO(State); ASMAtomicWriteU32(&State.cShots, State.cShots);
429 RTR0TESTR0_CHECK_RC(RTTimerStart(pTimer, 5*UINT64_C(1000000000)), VINF_SUCCESS);
430 RTR0TESTR0_CHECK_RC(RTTimerStart(pTimer, 0), VERR_TIMER_ACTIVE);
431 RTR0TESTR0_CHECK_RC(RTTimerStop(pTimer), VINF_SUCCESS);
432 RTR0TESTR0_CHECK_RC(RTTimerStop(pTimer), VERR_TIMER_SUSPENDED);
433 RTThreadSleep(1);
434 RTR0TESTR0_CHECK_MSG_BREAK(ASMAtomicUoReadU32(&State.cShots) == 0, ("cShots=%u\n", State.cShots));
435 } while (0);
436 RTR0TESTR0_CHECK_RC(RTTimerDestroy(pTimer), VINF_SUCCESS);
437 RTR0TESTR0_CHECK_RC(RTTimerDestroy(NULL), VINF_SUCCESS);
438 break;
439 }
440
441#if 1 /* might have to disable this for some host... */
442 case TSTRTR0TIMER_ONE_SHOT_RESTART:
443 case TSTRTR0TIMER_ONE_SHOT_RESTART_HIRES:
444 {
445 /* Create a one-shot timer and restart it in the callback handler. */
446 PRTTIMER pTimer;
447 uint32_t fFlags = TSTRTR0TIMER_IS_HIRES(uOperation) ? RTTIMER_FLAGS_HIGH_RES : 0;
448 for (uint32_t iTest = 0; iTest < 2; iTest++)
449 {
450 int rc = RTTimerCreateEx(&pTimer, 0, fFlags, tstRTR0TimerCallbackRestartOnce, &State);
451 if (rc == VERR_NOT_SUPPORTED)
452 {
453 RTR0TestR0Info("one-shot timer are not supported, skipping\n");
454 break;
455 }
456 RTR0TESTR0_CHECK_RC_BREAK(rc, VINF_SUCCESS);
457
458 RT_ZERO(State);
459 State.iActionShot = 0;
460 ASMAtomicWriteU32(&State.cShots, State.cShots);
461 do /* break loop */
462 {
463 RTR0TESTR0_CHECK_RC_BREAK(RTTimerStart(pTimer, cNsSysHz * iTest), VINF_SUCCESS);
464 for (uint32_t i = 0; i < 1000 && ASMAtomicUoReadU32(&State.cShots) < 2; i++)
465 RTThreadSleep(5);
466 RTR0TESTR0_CHECK_MSG_BREAK(ASMAtomicUoReadU32(&State.cShots) == 2, ("cShots=%u\n", State.cShots));
467 } while (0);
468 RTR0TESTR0_CHECK_RC(RTTimerDestroy(pTimer), VINF_SUCCESS);
469 }
470 break;
471 }
472#endif
473
474#if 1 /* might have to disable this for some host... */
475 case TSTRTR0TIMER_ONE_SHOT_DESTROY:
476 case TSTRTR0TIMER_ONE_SHOT_DESTROY_HIRES:
477 {
478 /* Create a one-shot timer and destroy it in the callback handler. */
479 PRTTIMER pTimer;
480 uint32_t fFlags = TSTRTR0TIMER_IS_HIRES(uOperation) ? RTTIMER_FLAGS_HIGH_RES : 0;
481 for (uint32_t iTest = 0; iTest < 2; iTest++)
482 {
483 int rc = RTTimerCreateEx(&pTimer, 0, fFlags, tstRTR0TimerCallbackDestroyOnce, &State);
484 if (rc == VERR_NOT_SUPPORTED)
485 {
486 RTR0TestR0Info("one-shot timer are not supported, skipping\n");
487 break;
488 }
489 RTR0TESTR0_CHECK_RC_BREAK(rc, VINF_SUCCESS);
490
491 RT_ZERO(State);
492 State.rc = VERR_IPE_UNINITIALIZED_STATUS;
493 State.iActionShot = 0;
494 ASMAtomicWriteU32(&State.cShots, State.cShots);
495 do /* break loop */
496 {
497 RTR0TESTR0_CHECK_RC_BREAK(RTTimerStart(pTimer, cNsSysHz * iTest), VINF_SUCCESS);
498 for (uint32_t i = 0; i < 1000 && (ASMAtomicUoReadU32(&State.cShots) < 1 || State.rc == VERR_IPE_UNINITIALIZED_STATUS); i++)
499 RTThreadSleep(5);
500 RTR0TESTR0_CHECK_MSG_BREAK(ASMAtomicReadU32(&State.cShots) == 1, ("cShots=%u\n", State.cShots));
501 RTR0TESTR0_CHECK_MSG_BREAK(State.rc == VINF_SUCCESS, ("rc=%Rrc\n", State.rc));
502 } while (0);
503 if (RT_FAILURE(State.rc))
504 RTR0TESTR0_CHECK_RC(RTTimerDestroy(pTimer), VINF_SUCCESS);
505 }
506 break;
507 }
508#endif
509
510 case TSTRTR0TIMER_ONE_SHOT_SPECIFIC:
511 case TSTRTR0TIMER_ONE_SHOT_SPECIFIC_HIRES:
512 {
513 PRTTIMER pTimer = NULL;
514 RTCPUSET OnlineSet;
515 RTMpGetOnlineSet(&OnlineSet);
516 for (uint32_t iCpu = 0; iCpu < RTCPUSET_MAX_CPUS; iCpu++)
517 if (RTCpuSetIsMemberByIndex(&OnlineSet, iCpu))
518 {
519 RT_ZERO(State);
520 State.iActionShot = 0;
521 State.rc = VINF_SUCCESS;
522 State.u.Specific.idCpu = RTMpCpuIdFromSetIndex(iCpu);
523 ASMAtomicWriteU32(&State.cShots, State.cShots);
524
525 uint32_t fFlags = TSTRTR0TIMER_IS_HIRES(uOperation) ? RTTIMER_FLAGS_HIGH_RES : 0;
526 fFlags |= RTTIMER_FLAGS_CPU(iCpu);
527 int rc = RTTimerCreateEx(&pTimer, 0, fFlags, tstRTR0TimerCallbackSpecific, &State);
528 if (rc == VERR_NOT_SUPPORTED)
529 {
530 RTR0TestR0Info("one-shot specific timer are not supported, skipping\n");
531 break;
532 }
533 RTR0TESTR0_CHECK_RC_BREAK(rc, VINF_SUCCESS);
534
535 for (uint32_t i = 0; i < 5 && !RTR0TestR0HaveErrors(); i++)
536 {
537 ASMAtomicWriteU32(&State.cShots, 0);
538 RTR0TESTR0_CHECK_RC_BREAK(RTTimerStart(pTimer, (i & 2 ? cNsSysHz : cNsSysHz / 2) * (i & 1)), VINF_SUCCESS);
539 uint64_t cNsElapsed = RTTimeSystemNanoTS();
540 for (uint32_t j = 0; j < 1000 && ASMAtomicUoReadU32(&State.cShots) < 1; j++)
541 RTThreadSleep(5);
542 cNsElapsed = RTTimeSystemNanoTS() - cNsElapsed;
543 RTR0TESTR0_CHECK_MSG_BREAK(ASMAtomicReadU32(&State.cShots) == 1,
544 ("cShots=%u iCpu=%u i=%u iCurCpu=%u cNsElapsed=%'llu\n",
545 State.cShots, iCpu, i, RTMpCpuIdToSetIndex(RTMpCpuId()), cNsElapsed ));
546 RTR0TESTR0_CHECK_MSG_BREAK(State.rc == VINF_SUCCESS, ("rc=%Rrc\n", State.rc));
547 RTR0TESTR0_CHECK_MSG_BREAK(!State.u.Specific.fFailed, ("iCpu=%u i=%u\n", iCpu, i));
548 }
549
550 RTR0TESTR0_CHECK_RC(RTTimerDestroy(pTimer), VINF_SUCCESS);
551 pTimer = NULL;
552 if (RTR0TestR0HaveErrors())
553 break;
554
555 RTMpGetOnlineSet(&OnlineSet);
556 }
557 RTR0TESTR0_CHECK_RC(RTTimerDestroy(pTimer), VINF_SUCCESS);
558 break;
559 }
560
561 case TSTRTR0TIMER_PERIODIC_BASIC:
562 case TSTRTR0TIMER_PERIODIC_BASIC_HIRES:
563 {
564 /* Create a periodic timer running at 10 HZ. */
565 uint32_t const u10HzAsNs = 100000000;
566 uint32_t const u10HzAsNsMin = u10HzAsNs - u10HzAsNs / 2;
567 uint32_t const u10HzAsNsMax = u10HzAsNs + u10HzAsNs / 2;
568 PRTTIMER pTimer;
569 uint32_t fFlags = TSTRTR0TIMER_IS_HIRES(uOperation) ? RTTIMER_FLAGS_HIGH_RES : 0;
570 RTR0TESTR0_CHECK_RC_BREAK(RTTimerCreateEx(&pTimer, u10HzAsNs, fFlags, tstRTR0TimerCallbackU32Counter, &State),
571 VINF_SUCCESS);
572
573 for (uint32_t iTest = 0; iTest < 2; iTest++)
574 {
575 RT_ZERO(State);
576 State.fPeriodic = true;
577 ASMAtomicWriteU32(&State.cShots, State.cShots);
578
579 uint64_t uStartNsTS = RTTimeSystemNanoTS();
580 RTR0TESTR0_CHECK_RC_BREAK(RTTimerStart(pTimer, u10HzAsNs), VINF_SUCCESS);
581 for (uint32_t i = 0; i < 1000 && ASMAtomicUoReadU32(&State.cShots) < 10; i++)
582 RTThreadSleep(10);
583 RTR0TESTR0_CHECK_RC_BREAK(RTTimerStop(pTimer), VINF_SUCCESS);
584 RTR0TESTR0_CHECK_MSG_BREAK(ASMAtomicUoReadU32(&State.cShots) == 10, ("cShots=%u\n", State.cShots));
585 if (tstRTR0TimerCheckShotIntervals(&State, uStartNsTS, u10HzAsNsMin, u10HzAsNsMax))
586 break;
587 }
588 RTR0TESTR0_CHECK_RC(RTTimerDestroy(pTimer), VINF_SUCCESS);
589 RTR0TESTR0_CHECK_RC(RTTimerDestroy(NULL), VINF_SUCCESS);
590 break;
591 }
592
593 case TSTRTR0TIMER_PERIODIC_CSSD_LOOPS:
594 case TSTRTR0TIMER_PERIODIC_CSSD_LOOPS_HIRES:
595 {
596 /* create, start, stop & destroy high res timers a number of times. */
597 uint32_t fFlags = TSTRTR0TIMER_IS_HIRES(uOperation) ? RTTIMER_FLAGS_HIGH_RES : 0;
598 for (uint32_t i = 0; i < 40; i++)
599 {
600 PRTTIMER pTimer;
601 RTR0TESTR0_CHECK_RC_BREAK(RTTimerCreateEx(&pTimer, cNsSysHz, fFlags, tstRTR0TimerCallbackU32Counter, &State),
602 VINF_SUCCESS);
603 for (uint32_t j = 0; j < 10; j++)
604 {
605 RT_ZERO(State);
606 State.fPeriodic = true;
607 ASMAtomicWriteU32(&State.cShots, State.cShots); /* ordered, necessary? */
608
609 RTR0TESTR0_CHECK_RC_BREAK(RTTimerStart(pTimer, i < 20 ? 0 : cNsSysHz), VINF_SUCCESS);
610 for (uint32_t k = 0; k < 1000 && ASMAtomicUoReadU32(&State.cShots) < 2; k++)
611 RTThreadSleep(1);
612 RTR0TESTR0_CHECK_RC_BREAK(RTTimerStop(pTimer), VINF_SUCCESS);
613 }
614 RTR0TESTR0_CHECK_RC(RTTimerDestroy(pTimer), VINF_SUCCESS);
615 }
616 break;
617 }
618
619 case TSTRTR0TIMER_PERIODIC_CHANGE_INTERVAL:
620 case TSTRTR0TIMER_PERIODIC_CHANGE_INTERVAL_HIRES:
621 {
622 /* Initialize the test parameters, using the u64Arg value for selecting variations. */
623 RT_ZERO(State);
624 State.cShots = 0;
625 State.rc = VERR_IPE_UNINITIALIZED_STATUS;
626 State.iActionShot = 42;
627 State.fPeriodic = true;
628 State.u.ChgInt.fDirection = !!(u64Arg & 1);
629 if (uOperation == TSTRTR0TIMER_PERIODIC_CHANGE_INTERVAL_HIRES)
630 {
631 State.u.ChgInt.cNsMaxInterval = RT_MAX(cNsMaxHighResHz * 10, 20000000); /* 10x / 20 ms */
632 State.u.ChgInt.cNsMinInterval = RT_MAX(cNsMaxHighResHz, 10000); /* min / 10 us */
633 }
634 else
635 {
636 State.u.ChgInt.cNsMaxInterval = cNsSysHz * 4;
637 State.u.ChgInt.cNsMinInterval = cNsSysHz;
638 }
639 State.u.ChgInt.cNsChangeStep = (State.u.ChgInt.cNsMaxInterval - State.u.ChgInt.cNsMinInterval) / 10;
640 State.u.ChgInt.cNsCurInterval = State.u.ChgInt.fDirection
641 ? State.u.ChgInt.cNsMaxInterval : State.u.ChgInt.cNsMinInterval;
642 State.u.ChgInt.cStepsBetween = u64Arg & 4 ? 1 : 3;
643 RTR0TESTR0_CHECK_MSG_BREAK(State.u.ChgInt.cNsMinInterval > 1000, ("%u\n", State.u.ChgInt.cNsMinInterval));
644 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));
645 ASMAtomicWriteU32(&State.cShots, State.cShots);
646
647 /* create the timer and check if RTTimerChangeInterval is supported. */
648 PRTTIMER pTimer;
649 uint32_t fFlags = TSTRTR0TIMER_IS_HIRES(uOperation) ? RTTIMER_FLAGS_HIGH_RES : 0;
650 RTR0TESTR0_CHECK_RC_BREAK(RTTimerCreateEx(&pTimer, cNsSysHz, fFlags, tstRTR0TimerCallbackChangeInterval, &State),
651 VINF_SUCCESS);
652 int rc = RTTimerChangeInterval(pTimer, State.u.ChgInt.cNsMinInterval);
653 if (rc == VERR_NOT_SUPPORTED)
654 {
655 RTR0TestR0Info("RTTimerChangeInterval not supported, skipped");
656 RTR0TESTR0_CHECK_RC(RTTimerDestroy(pTimer), VINF_SUCCESS);
657 break;
658 }
659
660 /* do the test. */
661 RTR0TESTR0_CHECK_RC_BREAK(RTTimerStart(pTimer, u64Arg & 2 ? State.u.ChgInt.cNsCurInterval : 0), VINF_SUCCESS);
662 for (uint32_t k = 0;
663 k < 1000
664 && ASMAtomicReadU32(&State.cShots) <= State.iActionShot
665 && State.rc == VERR_IPE_UNINITIALIZED_STATUS;
666 k++)
667 RTThreadSleep(10);
668
669 rc = RTTimerStop(pTimer);
670 RTR0TESTR0_CHECK_MSG_BREAK(rc == VERR_TIMER_SUSPENDED || rc == VINF_SUCCESS, ("rc = %Rrc (RTTimerStop)\n", rc));
671 RTR0TESTR0_CHECK_RC(RTTimerDestroy(pTimer), VINF_SUCCESS);
672 break;
673 }
674
675 case TSTRTR0TIMER_PERIODIC_SPECIFIC:
676 case TSTRTR0TIMER_PERIODIC_SPECIFIC_HIRES:
677 {
678 PRTTIMER pTimer = NULL;
679 RTCPUSET OnlineSet;
680 RTMpGetOnlineSet(&OnlineSet);
681 for (uint32_t iCpu = 0; iCpu < RTCPUSET_MAX_CPUS; iCpu++)
682 if (RTCpuSetIsMemberByIndex(&OnlineSet, iCpu))
683 {
684 RT_ZERO(State);
685 State.iActionShot = 0;
686 State.rc = VINF_SUCCESS;
687 State.fPeriodic = true;
688 State.u.Specific.idCpu = RTMpCpuIdFromSetIndex(iCpu);
689 ASMAtomicWriteU32(&State.cShots, State.cShots);
690
691 uint32_t fFlags = TSTRTR0TIMER_IS_HIRES(uOperation) ? RTTIMER_FLAGS_HIGH_RES : 0;
692 fFlags |= RTTIMER_FLAGS_CPU(iCpu);
693 int rc = RTTimerCreateEx(&pTimer, cNsSysHz, fFlags, tstRTR0TimerCallbackSpecific, &State);
694 if (rc == VERR_NOT_SUPPORTED)
695 {
696 RTR0TestR0Info("specific timer are not supported, skipping\n");
697 break;
698 }
699 RTR0TESTR0_CHECK_RC_BREAK(rc, VINF_SUCCESS);
700
701 for (uint32_t i = 0; i < 3 && !RTR0TestR0HaveErrors(); i++)
702 {
703 ASMAtomicWriteU32(&State.cShots, 0);
704 RTR0TESTR0_CHECK_RC_BREAK(RTTimerStart(pTimer, (i & 2 ? cNsSysHz : cNsSysHz / 2) * (i & 1)), VINF_SUCCESS);
705 uint64_t cNsElapsed = RTTimeSystemNanoTS();
706 for (uint32_t j = 0; j < 1000 && ASMAtomicUoReadU32(&State.cShots) < 8; j++)
707 RTThreadSleep(5);
708 cNsElapsed = RTTimeSystemNanoTS() - cNsElapsed;
709 RTR0TESTR0_CHECK_RC_BREAK(RTTimerStop(pTimer), VINF_SUCCESS);
710 RTR0TESTR0_CHECK_MSG_BREAK(ASMAtomicReadU32(&State.cShots) > 5,
711 ("cShots=%u iCpu=%u i=%u iCurCpu=%u cNsElapsed=%'llu\n",
712 State.cShots, iCpu, i, RTMpCpuIdToSetIndex(RTMpCpuId()), cNsElapsed));
713 RTR0TESTR0_CHECK_MSG_BREAK(State.rc == VINF_SUCCESS, ("rc=%Rrc\n", State.rc));
714 RTR0TESTR0_CHECK_MSG_BREAK(!State.u.Specific.fFailed, ("iCpu=%u i=%u\n", iCpu, i));
715 }
716
717 RTR0TESTR0_CHECK_RC(RTTimerDestroy(pTimer), VINF_SUCCESS);
718 pTimer = NULL;
719 if (RTR0TestR0HaveErrors())
720 break;
721
722 RTMpGetOnlineSet(&OnlineSet);
723 }
724 RTR0TESTR0_CHECK_RC(RTTimerDestroy(pTimer), VINF_SUCCESS);
725 break;
726 }
727
728 case TSTRTR0TIMER_PERIODIC_OMNI:
729 case TSTRTR0TIMER_PERIODIC_OMNI_HIRES:
730 {
731 /* Create a periodic timer running at max host frequency, but no more than 1000 Hz. */
732 uint32_t cNsInterval = cNsSysHz;
733 while (cNsInterval < UINT32_C(1000000))
734 cNsInterval *= 2;
735 PTSTRTR0TIMEROMNI1 paStates = (PTSTRTR0TIMEROMNI1)RTMemAllocZ(sizeof(paStates[0]) * RTCPUSET_MAX_CPUS);
736 RTR0TESTR0_CHECK_MSG_BREAK(paStates, ("%d\n", RTCPUSET_MAX_CPUS));
737
738 PRTTIMER pTimer;
739 uint32_t fFlags = (TSTRTR0TIMER_IS_HIRES(uOperation) ? RTTIMER_FLAGS_HIGH_RES : 0)
740 | RTTIMER_FLAGS_CPU_ALL;
741 int rc = RTTimerCreateEx(&pTimer, cNsInterval, fFlags, tstRTR0TimerCallbackOmni, paStates);
742 if (rc == VERR_NOT_SUPPORTED)
743 {
744 RTR0TESTR0_SKIP_BREAK();
745 }
746 RTR0TESTR0_CHECK_RC_BREAK(rc, VINF_SUCCESS);
747
748 for (uint32_t iTest = 0; iTest < 3 && !RTR0TestR0HaveErrors(); iTest++)
749 {
750 /* reset the state */
751 for (uint32_t iCpu = 0; iCpu < RTCPUSET_MAX_CPUS; iCpu++)
752 {
753 paStates[iCpu].u64Start = 0;
754 paStates[iCpu].u64Last = 0;
755 ASMAtomicWriteU32(&paStates[iCpu].cTicks, 0);
756 }
757
758 /* run it for 1 second. */
759 RTCPUSET OnlineSet;
760 uint64_t uStartNsTS = RTTimeSystemNanoTS();
761 RTR0TESTR0_CHECK_RC_BREAK(RTTimerStart(pTimer, 0), VINF_SUCCESS);
762 RTMpGetOnlineSet(&OnlineSet);
763
764 for (uint32_t i = 0; i < 5000 && RTTimeSystemNanoTS() - uStartNsTS <= UINT32_C(1000000000); i++)
765 RTThreadSleep(2);
766
767 RTR0TESTR0_CHECK_RC_BREAK(RTTimerStop(pTimer), VINF_SUCCESS);
768 uint64_t cNsElapsedX = RTTimeNanoTS() - uStartNsTS;
769
770 /* Do a min/max on the start and stop times and calculate the test period. */
771 uint64_t u64MinStart = UINT64_MAX;
772 uint64_t u64MaxStop = 0;
773 for (uint32_t iCpu = 0; iCpu < RTCPUSET_MAX_CPUS; iCpu++)
774 {
775 if (paStates[iCpu].u64Start)
776 {
777 if (paStates[iCpu].u64Start < u64MinStart)
778 u64MinStart = paStates[iCpu].u64Start;
779 if (paStates[iCpu].u64Last > u64MaxStop)
780 u64MaxStop = paStates[iCpu].u64Last;
781 }
782 }
783 RTR0TESTR0_CHECK_MSG(u64MinStart < u64MaxStop, ("%llu, %llu", u64MinStart, u64MaxStop));
784 uint64_t cNsElapsed = u64MaxStop - u64MinStart;
785 RTR0TESTR0_CHECK_MSG(cNsElapsed <= cNsElapsedX + 100000, ("%llu, %llu", cNsElapsed, cNsElapsedX)); /* the fudge factor is time drift */
786 uint32_t cAvgTicks = cNsElapsed / cNsInterval + 1;
787
788 /* Check tick counts. ASSUMES no cpu on- or offlining.
789 This only catches really bad stuff. */
790 uint32_t cMinTicks = cAvgTicks - cAvgTicks / 10;
791 uint32_t cMaxTicks = cAvgTicks + cAvgTicks / 10 + 1;
792 for (uint32_t iCpu = 0; iCpu < RTCPUSET_MAX_CPUS; iCpu++)
793 if (paStates[iCpu].cTicks)
794 {
795 RTR0TESTR0_CHECK_MSG(RTCpuSetIsMemberByIndex(&OnlineSet, iCpu), ("%d\n", iCpu));
796 RTR0TESTR0_CHECK_MSG(paStates[iCpu].cTicks <= cMaxTicks && paStates[iCpu].cTicks >= cMinTicks,
797 ("min=%u, ticks=%u, avg=%u max=%u, iCpu=%u, interval=%'u, elapsed=%'llu/%'llu\n",
798 cMinTicks, paStates[iCpu].cTicks, cAvgTicks, cMaxTicks, iCpu,
799 cNsInterval, cNsElapsed, cNsElapsedX));
800 }
801 else
802 RTR0TESTR0_CHECK_MSG(!RTCpuSetIsMemberByIndex(&OnlineSet, iCpu), ("%d\n", iCpu));
803 }
804
805 RTR0TESTR0_CHECK_RC(RTTimerDestroy(pTimer), VINF_SUCCESS);
806 RTMemFree(paStates);
807 break;
808 }
809 }
810
811 RTR0TESTR0_SRV_REQ_EPILOG(pReqHdr);
812 /* The error indicator is the '!' in the message buffer. */
813 return VINF_SUCCESS;
814}
815
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