VirtualBox

source: vbox/trunk/src/VBox/Runtime/r0drv/solaris/timer-r0drv-solaris.c

Last change on this file was 98103, checked in by vboxsync, 17 months ago

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 21.9 KB
Line 
1/* $Id: timer-r0drv-solaris.c 98103 2023-01-17 14:15:46Z vboxsync $ */
2/** @file
3 * IPRT - Timer, Ring-0 Driver, Solaris.
4 */
5
6/*
7 * Copyright (C) 2006-2023 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * The contents of this file may alternatively be used under the terms
26 * of the Common Development and Distribution License Version 1.0
27 * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
28 * in the VirtualBox distribution, in which case the provisions of the
29 * CDDL are applicable instead of those of the GPL.
30 *
31 * You may elect to license modified versions of this file under the
32 * terms and conditions of either the GPL or the CDDL or both.
33 *
34 * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
35 */
36
37
38/*********************************************************************************************************************************
39* Header Files *
40*********************************************************************************************************************************/
41#include "the-solaris-kernel.h"
42#include "internal/iprt.h"
43#include <iprt/timer.h>
44
45#include <iprt/asm.h>
46#if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86)
47# include <iprt/asm-amd64-x86.h>
48#endif
49#include <iprt/assert.h>
50#include <iprt/err.h>
51#include <iprt/mem.h>
52#include <iprt/mp.h>
53#include <iprt/spinlock.h>
54#include <iprt/time.h>
55#include <iprt/thread.h>
56#include "internal/magics.h"
57
58
59/*********************************************************************************************************************************
60* Structures and Typedefs *
61*********************************************************************************************************************************/
62/**
63 * The internal representation of a Solaris timer handle.
64 */
65typedef struct RTTIMER
66{
67 /** Magic.
68 * This is RTTIMER_MAGIC, but changes to something else before the timer
69 * is destroyed to indicate clearly that thread should exit. */
70 uint32_t volatile u32Magic;
71 /** Reference counter. */
72 uint32_t volatile cRefs;
73 /** Flag indicating that the timer is suspended (hCyclicId should be
74 * CYCLIC_NONE). */
75 bool volatile fSuspended;
76 /** Flag indicating that the timer was suspended from the timer callback and
77 * therefore the hCyclicId may still be valid. */
78 bool volatile fSuspendedFromTimer;
79 /** Flag indicating that the timer interval was changed and that it requires
80 * manual expiration time programming for each callout. */
81 bool volatile fIntervalChanged;
82 /** Whether the timer must run on all CPUs or not. */
83 uint8_t fAllCpus;
84 /** Whether the timer must run on a specific CPU or not. */
85 uint8_t fSpecificCpu;
86 /** The CPU it must run on if fSpecificCpu is set. */
87 uint32_t iCpu;
88 /** The nano second interval for repeating timers. */
89 uint64_t volatile cNsInterval;
90 /** Cyclic timer Id. This is CYCLIC_NONE if no active timer.
91 * @remarks Please keep in mind that cyclic may call us back before the
92 * cyclic_add/cyclic_add_omni functions returns, so don't use this
93 * unguarded with cyclic_reprogram. */
94 cyclic_id_t hCyclicId;
95 /** The user callback. */
96 PFNRTTIMER pfnTimer;
97 /** The argument for the user callback. */
98 void *pvUser;
99 /** Union with timer type specific data. */
100 union
101 {
102 /** Single timer (fAllCpus == false). */
103 struct
104 {
105 /** Timer ticks. */
106 uint64_t u64Tick;
107 /** The next tick when fIntervalChanged is true, otherwise 0. */
108 uint64_t nsNextTick;
109 /** The (interrupt) thread currently active in the callback. */
110 kthread_t * volatile pActiveThread;
111 } Single;
112
113 /** Omni timer (fAllCpus == true). */
114 struct
115 {
116 /** Absolute timestamp of when the timer should fire first when starting up. */
117 uint64_t u64When;
118 /** Array of per CPU data (variable size). */
119 struct
120 {
121 /** Timer ticks (reinitialized when online'd). */
122 uint64_t u64Tick;
123 /** The (interrupt) thread currently active in the callback. */
124 kthread_t * volatile pActiveThread;
125 /** The next tick when fIntervalChanged is true, otherwise 0. */
126 uint64_t nsNextTick;
127 } aPerCpu[1];
128 } Omni;
129 } u;
130} RTTIMER;
131
132
133/*********************************************************************************************************************************
134* Defined Constants And Macros *
135*********************************************************************************************************************************/
136/** Validates that the timer is valid. */
137#define RTTIMER_ASSERT_VALID_RET(pTimer) \
138 do \
139 { \
140 AssertPtrReturn(pTimer, VERR_INVALID_HANDLE); \
141 AssertMsgReturn((pTimer)->u32Magic == RTTIMER_MAGIC, ("pTimer=%p u32Magic=%x expected %x\n", (pTimer), (pTimer)->u32Magic, RTTIMER_MAGIC), \
142 VERR_INVALID_HANDLE); \
143 } while (0)
144
145
146/*********************************************************************************************************************************
147* Internal Functions *
148*********************************************************************************************************************************/
149static void rtTimerSolSingleCallbackWrapper(void *pvArg);
150static void rtTimerSolStopIt(PRTTIMER pTimer);
151
152
153/**
154 * Retains a reference to the timer.
155 *
156 * @returns New reference counter value.
157 * @param pTimer The timer.
158 */
159DECLINLINE(uint32_t) rtTimerSolRetain(PRTTIMER pTimer)
160{
161 return ASMAtomicIncU32(&pTimer->cRefs);
162}
163
164
165/**
166 * Destroys the timer when the reference counter has reached zero.
167 *
168 * @returns 0 (new references counter value).
169 * @param pTimer The timer.
170 */
171static uint32_t rtTimeSolReleaseCleanup(PRTTIMER pTimer)
172{
173 Assert(pTimer->hCyclicId == CYCLIC_NONE);
174 ASMAtomicWriteU32(&pTimer->u32Magic, ~RTTIMER_MAGIC);
175 RTMemFree(pTimer);
176 return 0;
177}
178
179
180/**
181 * Releases a reference to the timer.
182 *
183 * @returns New reference counter value.
184 * @param pTimer The timer.
185 */
186DECLINLINE(uint32_t) rtTimerSolRelease(PRTTIMER pTimer)
187{
188 uint32_t cRefs = ASMAtomicDecU32(&pTimer->cRefs);
189 if (!cRefs)
190 return rtTimeSolReleaseCleanup(pTimer);
191 return cRefs;
192}
193
194
195/**
196 * Callback wrapper for single-CPU timers.
197 *
198 * @param pvArg Opaque pointer to the timer.
199 *
200 * @remarks This will be executed in interrupt context but only at the specified
201 * level i.e. CY_LOCK_LEVEL in our case. We -CANNOT- call into the
202 * cyclic subsystem here, neither should pfnTimer().
203 */
204static void rtTimerSolSingleCallbackWrapper(void *pvArg)
205{
206 PRTTIMER pTimer = (PRTTIMER)pvArg;
207 AssertPtrReturnVoid(pTimer);
208 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
209 Assert(!pTimer->fAllCpus);
210
211 /* Make sure one-shots do not fire another time. */
212 Assert( !pTimer->fSuspended
213 || pTimer->cNsInterval != 0);
214
215 if (!pTimer->fSuspendedFromTimer)
216 {
217 /* Make sure we are firing on the right CPU. */
218 Assert( !pTimer->fSpecificCpu
219 || pTimer->iCpu == RTMpCpuId());
220
221 /* For one-shot, we may allow the callback to restart them. */
222 if (pTimer->cNsInterval == 0)
223 pTimer->fSuspendedFromTimer = true;
224
225 /*
226 * Perform the callout.
227 */
228 pTimer->u.Single.pActiveThread = curthread;
229
230 uint64_t u64Tick = ++pTimer->u.Single.u64Tick;
231 pTimer->pfnTimer(pTimer, pTimer->pvUser, u64Tick);
232
233 pTimer->u.Single.pActiveThread = NULL;
234
235 if (RT_LIKELY(!pTimer->fSuspendedFromTimer))
236 {
237 if ( !pTimer->fIntervalChanged
238 || RT_UNLIKELY(pTimer->hCyclicId == CYCLIC_NONE))
239 return;
240
241 /*
242 * The interval was changed, we need to set the expiration time
243 * ourselves before returning. This comes at a slight cost,
244 * which is why we don't do it all the time.
245 */
246 if (pTimer->u.Single.nsNextTick)
247 pTimer->u.Single.nsNextTick += ASMAtomicUoReadU64(&pTimer->cNsInterval);
248 else
249 pTimer->u.Single.nsNextTick = RTTimeSystemNanoTS() + ASMAtomicUoReadU64(&pTimer->cNsInterval);
250 cyclic_reprogram(pTimer->hCyclicId, pTimer->u.Single.nsNextTick);
251 return;
252 }
253
254 /*
255 * The timer has been suspended, set expiration time to infinitiy.
256 */
257 }
258 if (RT_LIKELY(pTimer->hCyclicId != CYCLIC_NONE))
259 cyclic_reprogram(pTimer->hCyclicId, CY_INFINITY);
260}
261
262
263/**
264 * Callback wrapper for Omni-CPU timers.
265 *
266 * @param pvArg Opaque pointer to the timer.
267 *
268 * @remarks This will be executed in interrupt context but only at the specified
269 * level i.e. CY_LOCK_LEVEL in our case. We -CANNOT- call into the
270 * cyclic subsystem here, neither should pfnTimer().
271 */
272static void rtTimerSolOmniCallbackWrapper(void *pvArg)
273{
274 PRTTIMER pTimer = (PRTTIMER)pvArg;
275 AssertPtrReturnVoid(pTimer);
276 Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
277 Assert(pTimer->fAllCpus);
278
279 if (!pTimer->fSuspendedFromTimer)
280 {
281 /*
282 * Perform the callout.
283 */
284 uint32_t const iCpu = CPU->cpu_id;
285
286 pTimer->u.Omni.aPerCpu[iCpu].pActiveThread = curthread;
287 uint64_t u64Tick = ++pTimer->u.Omni.aPerCpu[iCpu].u64Tick;
288
289 pTimer->pfnTimer(pTimer, pTimer->pvUser, u64Tick);
290
291 pTimer->u.Omni.aPerCpu[iCpu].pActiveThread = NULL;
292
293 if (RT_LIKELY(!pTimer->fSuspendedFromTimer))
294 {
295 if ( !pTimer->fIntervalChanged
296 || RT_UNLIKELY(pTimer->hCyclicId == CYCLIC_NONE))
297 return;
298
299 /*
300 * The interval was changed, we need to set the expiration time
301 * ourselves before returning. This comes at a slight cost,
302 * which is why we don't do it all the time.
303 *
304 * Note! The cyclic_reprogram call only affects the omni cyclic
305 * component for this CPU.
306 */
307 if (pTimer->u.Omni.aPerCpu[iCpu].nsNextTick)
308 pTimer->u.Omni.aPerCpu[iCpu].nsNextTick += ASMAtomicUoReadU64(&pTimer->cNsInterval);
309 else
310 pTimer->u.Omni.aPerCpu[iCpu].nsNextTick = RTTimeSystemNanoTS() + ASMAtomicUoReadU64(&pTimer->cNsInterval);
311 cyclic_reprogram(pTimer->hCyclicId, pTimer->u.Omni.aPerCpu[iCpu].nsNextTick);
312 return;
313 }
314
315 /*
316 * The timer has been suspended, set expiration time to infinitiy.
317 */
318 }
319 if (RT_LIKELY(pTimer->hCyclicId != CYCLIC_NONE))
320 cyclic_reprogram(pTimer->hCyclicId, CY_INFINITY);
321}
322
323
324/**
325 * Omni-CPU cyclic online event. This is called before the omni cycle begins to
326 * fire on the specified CPU.
327 *
328 * @param pvArg Opaque pointer to the timer.
329 * @param pCpu Pointer to the CPU on which it will fire.
330 * @param pCyclicHandler Pointer to a cyclic handler to add to the CPU
331 * specified in @a pCpu.
332 * @param pCyclicTime Pointer to the cyclic time and interval object.
333 *
334 * @remarks We -CANNOT- call back into the cyclic subsystem here, we can however
335 * block (sleep).
336 */
337static void rtTimerSolOmniCpuOnline(void *pvArg, cpu_t *pCpu, cyc_handler_t *pCyclicHandler, cyc_time_t *pCyclicTime)
338{
339 PRTTIMER pTimer = (PRTTIMER)pvArg;
340 AssertPtrReturnVoid(pTimer);
341 AssertPtrReturnVoid(pCpu);
342 AssertPtrReturnVoid(pCyclicHandler);
343 AssertPtrReturnVoid(pCyclicTime);
344 uint32_t const iCpu = pCpu->cpu_id; /* Note! CPU is not necessarily the same as pCpu. */
345
346 pTimer->u.Omni.aPerCpu[iCpu].u64Tick = 0;
347 pTimer->u.Omni.aPerCpu[iCpu].nsNextTick = 0;
348
349 pCyclicHandler->cyh_func = (cyc_func_t)rtTimerSolOmniCallbackWrapper;
350 pCyclicHandler->cyh_arg = pTimer;
351 pCyclicHandler->cyh_level = CY_LOCK_LEVEL;
352
353 uint64_t u64Now = RTTimeSystemNanoTS();
354 if (pTimer->u.Omni.u64When < u64Now)
355 pCyclicTime->cyt_when = u64Now + pTimer->cNsInterval / 2;
356 else
357 pCyclicTime->cyt_when = pTimer->u.Omni.u64When;
358
359 pCyclicTime->cyt_interval = pTimer->cNsInterval;
360}
361
362
363RTDECL(int) RTTimerCreateEx(PRTTIMER *ppTimer, uint64_t u64NanoInterval, uint32_t fFlags, PFNRTTIMER pfnTimer, void *pvUser)
364{
365 RT_ASSERT_PREEMPTIBLE();
366 *ppTimer = NULL;
367
368 /*
369 * Validate flags.
370 */
371 if (!RTTIMER_FLAGS_ARE_VALID(fFlags))
372 return VERR_INVALID_PARAMETER;
373
374 if ( (fFlags & RTTIMER_FLAGS_CPU_SPECIFIC)
375 && (fFlags & RTTIMER_FLAGS_CPU_ALL) != RTTIMER_FLAGS_CPU_ALL
376 && !RTMpIsCpuPossible(RTMpCpuIdFromSetIndex(fFlags & RTTIMER_FLAGS_CPU_MASK)))
377 return VERR_CPU_NOT_FOUND;
378
379 /* One-shot omni timers are not supported by the cyclic system. */
380 if ( (fFlags & RTTIMER_FLAGS_CPU_ALL) == RTTIMER_FLAGS_CPU_ALL
381 && u64NanoInterval == 0)
382 return VERR_NOT_SUPPORTED;
383
384 /*
385 * Allocate and initialize the timer handle. The omni variant has a
386 * variable sized array of ticks counts, thus the size calculation.
387 */
388 PRTTIMER pTimer = (PRTTIMER)RTMemAllocZ( (fFlags & RTTIMER_FLAGS_CPU_ALL) == RTTIMER_FLAGS_CPU_ALL
389 ? RT_UOFFSETOF_DYN(RTTIMER, u.Omni.aPerCpu[RTMpGetCount()])
390 : sizeof(RTTIMER));
391 if (!pTimer)
392 return VERR_NO_MEMORY;
393
394 pTimer->u32Magic = RTTIMER_MAGIC;
395 pTimer->cRefs = 1;
396 pTimer->fSuspended = true;
397 pTimer->fSuspendedFromTimer = false;
398 pTimer->fIntervalChanged = false;
399 if ((fFlags & RTTIMER_FLAGS_CPU_ALL) == RTTIMER_FLAGS_CPU_ALL)
400 {
401 pTimer->fAllCpus = true;
402 pTimer->fSpecificCpu = false;
403 pTimer->iCpu = UINT32_MAX;
404 }
405 else if (fFlags & RTTIMER_FLAGS_CPU_SPECIFIC)
406 {
407 pTimer->fAllCpus = false;
408 pTimer->fSpecificCpu = true;
409 pTimer->iCpu = fFlags & RTTIMER_FLAGS_CPU_MASK; /* ASSUMES: index == cpuid */
410 }
411 else
412 {
413 pTimer->fAllCpus = false;
414 pTimer->fSpecificCpu = false;
415 pTimer->iCpu = UINT32_MAX;
416 }
417 pTimer->cNsInterval = u64NanoInterval;
418 pTimer->pfnTimer = pfnTimer;
419 pTimer->pvUser = pvUser;
420 pTimer->hCyclicId = CYCLIC_NONE;
421
422 *ppTimer = pTimer;
423 return VINF_SUCCESS;
424}
425
426
427/**
428 * Checks if the calling thread is currently executing the timer proceduce for
429 * the given timer.
430 *
431 * @returns true if it is, false if it isn't.
432 * @param pTimer The timer in question.
433 */
434DECLINLINE(bool) rtTimerSolIsCallingFromTimerProc(PRTTIMER pTimer)
435{
436 kthread_t *pCurThread = curthread;
437 AssertReturn(pCurThread, false); /* serious paranoia */
438
439 if (!pTimer->fAllCpus)
440 return pTimer->u.Single.pActiveThread == pCurThread;
441 return pTimer->u.Omni.aPerCpu[CPU->cpu_id].pActiveThread == pCurThread;
442}
443
444
445RTDECL(int) RTTimerDestroy(PRTTIMER pTimer)
446{
447 if (pTimer == NULL)
448 return VINF_SUCCESS;
449 RTTIMER_ASSERT_VALID_RET(pTimer);
450 RT_ASSERT_INTS_ON();
451
452 /*
453 * It is not possible to destroy a timer from it's callback function.
454 * Cyclic makes that impossible (or at least extremely risky).
455 */
456 AssertReturn(!rtTimerSolIsCallingFromTimerProc(pTimer), VERR_INVALID_CONTEXT);
457
458 /*
459 * Invalidate the handle, make sure it's stopped and free the associated resources.
460 */
461 ASMAtomicWriteU32(&pTimer->u32Magic, ~RTTIMER_MAGIC);
462
463 if ( !pTimer->fSuspended
464 || pTimer->hCyclicId != CYCLIC_NONE) /* 2nd check shouldn't happen */
465 rtTimerSolStopIt(pTimer);
466
467 rtTimerSolRelease(pTimer);
468 return VINF_SUCCESS;
469}
470
471
472RTDECL(int) RTTimerStart(PRTTIMER pTimer, uint64_t u64First)
473{
474 RTTIMER_ASSERT_VALID_RET(pTimer);
475 RT_ASSERT_INTS_ON();
476
477 /*
478 * It's not possible to restart a one-shot time from it's callback function,
479 * at least not at the moment.
480 */
481 AssertReturn(!rtTimerSolIsCallingFromTimerProc(pTimer), VERR_INVALID_CONTEXT);
482
483 mutex_enter(&cpu_lock);
484
485 /*
486 * Make sure it's not active already. If it was suspended from a timer
487 * callback function, we need to do some cleanup work here before we can
488 * restart the timer.
489 */
490 if (!pTimer->fSuspended)
491 {
492 if (!pTimer->fSuspendedFromTimer)
493 {
494 mutex_exit(&cpu_lock);
495 return VERR_TIMER_ACTIVE;
496 }
497 cyclic_remove(pTimer->hCyclicId);
498 pTimer->hCyclicId = CYCLIC_NONE;
499 }
500
501 pTimer->fSuspended = false;
502 pTimer->fSuspendedFromTimer = false;
503 pTimer->fIntervalChanged = false;
504 if (pTimer->fAllCpus)
505 {
506 /*
507 * Setup omni (all CPU) timer. The Omni-CPU online event will fire
508 * and from there we setup periodic timers per CPU.
509 */
510 pTimer->u.Omni.u64When = RTTimeSystemNanoTS() + (u64First ? u64First : pTimer->cNsInterval);
511
512 cyc_omni_handler_t HandlerOmni;
513 HandlerOmni.cyo_online = rtTimerSolOmniCpuOnline;
514 HandlerOmni.cyo_offline = NULL;
515 HandlerOmni.cyo_arg = pTimer;
516
517 pTimer->hCyclicId = cyclic_add_omni(&HandlerOmni);
518 }
519 else
520 {
521 cyc_handler_t Handler;
522 cyc_time_t FireTime;
523
524 /*
525 * Setup a single CPU timer. If a specific CPU was requested, it
526 * must be online or the timer cannot start.
527 */
528 if ( pTimer->fSpecificCpu
529 && !RTMpIsCpuOnline(pTimer->iCpu)) /* ASSUMES: index == cpuid */
530 {
531 pTimer->fSuspended = true;
532
533 mutex_exit(&cpu_lock);
534 return VERR_CPU_OFFLINE;
535 }
536
537 Handler.cyh_func = (cyc_func_t)rtTimerSolSingleCallbackWrapper;
538 Handler.cyh_arg = pTimer;
539 Handler.cyh_level = CY_LOCK_LEVEL;
540
541 /*
542 * Use a large interval (1 hour) so that we don't get a timer-callback between
543 * cyclic_add() and cyclic_bind(). Program the correct interval once cyclic_bind() is done.
544 * See @bugref{7691#c20}.
545 */
546 if (!pTimer->fSpecificCpu)
547 FireTime.cyt_when = RTTimeSystemNanoTS() + u64First;
548 else
549 FireTime.cyt_when = RTTimeSystemNanoTS() + u64First + RT_NS_1HOUR;
550 FireTime.cyt_interval = pTimer->cNsInterval != 0
551 ? pTimer->cNsInterval
552 : CY_INFINITY /* Special value, see cyclic_fire(). */;
553 pTimer->u.Single.u64Tick = 0;
554 pTimer->u.Single.nsNextTick = 0;
555
556 pTimer->hCyclicId = cyclic_add(&Handler, &FireTime);
557 if (pTimer->fSpecificCpu)
558 {
559 cyclic_bind(pTimer->hCyclicId, cpu[pTimer->iCpu], NULL /* cpupart */);
560 cyclic_reprogram(pTimer->hCyclicId, RTTimeSystemNanoTS() + u64First);
561 }
562 }
563
564 mutex_exit(&cpu_lock);
565 return VINF_SUCCESS;
566}
567
568
569/**
570 * Worker common for RTTimerStop and RTTimerDestroy.
571 *
572 * @param pTimer The timer to stop.
573 */
574static void rtTimerSolStopIt(PRTTIMER pTimer)
575{
576 mutex_enter(&cpu_lock);
577
578 pTimer->fSuspended = true;
579 if (pTimer->hCyclicId != CYCLIC_NONE)
580 {
581 cyclic_remove(pTimer->hCyclicId);
582 pTimer->hCyclicId = CYCLIC_NONE;
583 }
584 pTimer->fSuspendedFromTimer = false;
585
586 mutex_exit(&cpu_lock);
587}
588
589
590RTDECL(int) RTTimerStop(PRTTIMER pTimer)
591{
592 RTTIMER_ASSERT_VALID_RET(pTimer);
593 RT_ASSERT_INTS_ON();
594
595 if (pTimer->fSuspended)
596 return VERR_TIMER_SUSPENDED;
597
598 /* Trying the cpu_lock stuff and calling cyclic_remove may deadlock
599 the system, so just mark the timer as suspened and deal with it in
600 the callback wrapper function above. */
601 if (rtTimerSolIsCallingFromTimerProc(pTimer))
602 pTimer->fSuspendedFromTimer = true;
603 else
604 rtTimerSolStopIt(pTimer);
605
606 return VINF_SUCCESS;
607}
608
609
610RTDECL(int) RTTimerChangeInterval(PRTTIMER pTimer, uint64_t u64NanoInterval)
611{
612 /*
613 * Validate.
614 */
615 RTTIMER_ASSERT_VALID_RET(pTimer);
616 AssertReturn(u64NanoInterval > 0, VERR_INVALID_PARAMETER);
617 AssertReturn(u64NanoInterval < UINT64_MAX / 8, VERR_INVALID_PARAMETER);
618 AssertReturn(pTimer->cNsInterval, VERR_INVALID_STATE);
619
620 if (pTimer->fSuspended || pTimer->fSuspendedFromTimer)
621 pTimer->cNsInterval = u64NanoInterval;
622 else
623 {
624 ASMAtomicWriteU64(&pTimer->cNsInterval, u64NanoInterval);
625 ASMAtomicWriteBool(&pTimer->fIntervalChanged, true);
626
627 if ( !pTimer->fAllCpus
628 && !pTimer->u.Single.nsNextTick
629 && pTimer->hCyclicId != CYCLIC_NONE
630 && rtTimerSolIsCallingFromTimerProc(pTimer))
631 pTimer->u.Single.nsNextTick = RTTimeSystemNanoTS();
632 }
633
634 return VINF_SUCCESS;
635}
636
637
638RTDECL(uint32_t) RTTimerGetSystemGranularity(void)
639{
640 return nsec_per_tick;
641}
642
643
644RTDECL(int) RTTimerRequestSystemGranularity(uint32_t u32Request, uint32_t *pu32Granted)
645{
646 return VERR_NOT_SUPPORTED;
647}
648
649
650RTDECL(int) RTTimerReleaseSystemGranularity(uint32_t u32Granted)
651{
652 return VERR_NOT_SUPPORTED;
653}
654
655
656RTDECL(bool) RTTimerCanDoHighResolution(void)
657{
658 return true;
659}
660
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use