8c2194fa35a37e70b7d7023451818c12f1914d47vboxsync/* $Id$ */
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync/** @file
5b281ba489ca18f0380d7efc7a5108b606cce449vboxsync * IPRT - Timers, Generic.
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync */
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync/*
1be6c03d6e9f1ef801ff29b318baa5d42f1bfc2evboxsync * Copyright (C) 2006-2012 Oracle Corporation
c98fb3e16fcd571a790eab772c0c66173d225205vboxsync *
c98fb3e16fcd571a790eab772c0c66173d225205vboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
c98fb3e16fcd571a790eab772c0c66173d225205vboxsync * available from http://www.virtualbox.org. This file is free software;
c98fb3e16fcd571a790eab772c0c66173d225205vboxsync * you can redistribute it and/or modify it under the terms of the GNU
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * General Public License (GPL) as published by the Free Software
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync *
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * The contents of this file may alternatively be used under the terms
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * of the Common Development and Distribution License Version 1.0
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * VirtualBox OSE distribution, in which case the provisions of the
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * CDDL are applicable instead of those of the GPL.
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync *
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * You may elect to license modified versions of this file under the
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * terms and conditions of either the GPL or the CDDL or both.
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync */
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync/*******************************************************************************
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync* Header Files *
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync*******************************************************************************/
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync#include <iprt/timer.h>
aa4bcf0a4b2db3ac352b56a291d49cb8d4b66d32vboxsync#include "internal/iprt.h"
aa4bcf0a4b2db3ac352b56a291d49cb8d4b66d32vboxsync
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync#include <iprt/thread.h>
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync#include <iprt/err.h>
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync#include <iprt/assert.h>
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync#include <iprt/alloc.h>
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync#include <iprt/asm.h>
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync#include <iprt/semaphore.h>
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync#include <iprt/time.h>
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync#include <iprt/log.h>
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync#include "internal/magics.h"
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync/*******************************************************************************
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync* Structures and Typedefs *
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync*******************************************************************************/
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync/**
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync * The internal representation of a timer handle.
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync */
cacc4e75dbbff469c10a505168208f064c6c385cvboxsynctypedef struct RTTIMER
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync{
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync /** Magic.
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync * This is RTTIMER_MAGIC, but changes to something else before the timer
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync * is destroyed to indicate clearly that thread should exit. */
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync uint32_t volatile u32Magic;
9621896680fea9b2078823e8ef2e64cec5bf2da0vboxsync /** Flag indicating the timer is suspended. */
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync uint8_t volatile fSuspended;
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync /** Flag indicating that the timer has been destroyed. */
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync uint8_t volatile fDestroyed;
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync /** Callback. */
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync PFNRTTIMER pfnTimer;
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync /** User argument. */
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync void *pvUser;
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync /** The timer thread. */
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync RTTHREAD Thread;
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync /** Event semaphore on which the thread is blocked. */
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync RTSEMEVENT Event;
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync /** The timer interval. 0 if one-shot. */
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync uint64_t u64NanoInterval;
d428342802b081b076970ddb499d215b79f087ccvboxsync /** The start of the current run (ns).
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync * This is used to calculate when the timer ought to fire the next time. */
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync uint64_t volatile u64StartTS;
d428342802b081b076970ddb499d215b79f087ccvboxsync /** The start of the current run (ns).
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync * This is used to calculate when the timer ought to fire the next time. */
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync uint64_t volatile u64NextTS;
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync /** The current tick number (since u64StartTS). */
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync uint64_t volatile iTick;
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync} RTTIMER;
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync/*******************************************************************************
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync* Internal Functions *
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync*******************************************************************************/
cacc4e75dbbff469c10a505168208f064c6c385cvboxsyncstatic DECLCALLBACK(int) rtTimerThread(RTTHREAD Thread, void *pvUser);
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsyncRTDECL(int) RTTimerCreateEx(PRTTIMER *ppTimer, uint64_t u64NanoInterval, uint32_t fFlags, PFNRTTIMER pfnTimer, void *pvUser)
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync{
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync *ppTimer = NULL;
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync
3f1eb07aba9eee6394f3084c956149ee9a27df09vboxsync /*
3f1eb07aba9eee6394f3084c956149ee9a27df09vboxsync * We don't support the fancy MP features.
3f1eb07aba9eee6394f3084c956149ee9a27df09vboxsync */
3f1eb07aba9eee6394f3084c956149ee9a27df09vboxsync if (fFlags & RTTIMER_FLAGS_CPU_SPECIFIC)
3f1eb07aba9eee6394f3084c956149ee9a27df09vboxsync return VERR_NOT_SUPPORTED;
3f1eb07aba9eee6394f3084c956149ee9a27df09vboxsync
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync /*
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync * Allocate and initialize the timer handle.
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync */
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync PRTTIMER pTimer = (PRTTIMER)RTMemAlloc(sizeof(*pTimer));
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync if (!pTimer)
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync return VERR_NO_MEMORY;
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync pTimer->u32Magic = RTTIMER_MAGIC;
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync pTimer->fSuspended = true;
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync pTimer->fDestroyed = false;
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync pTimer->pfnTimer = pfnTimer;
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync pTimer->pvUser = pvUser;
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync pTimer->Thread = NIL_RTTHREAD;
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync pTimer->Event = NIL_RTSEMEVENT;
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync pTimer->u64NanoInterval = u64NanoInterval;
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync pTimer->u64StartTS = 0;
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync int rc = RTSemEventCreate(&pTimer->Event);
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync if (RT_SUCCESS(rc))
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync {
31c721c11fd84ae16ea50a404dab9455ca3e48fdvboxsync rc = RTThreadCreate(&pTimer->Thread, rtTimerThread, pTimer, 0, RTTHREADTYPE_TIMER, RTTHREADFLAGS_WAITABLE, "Timer");
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync if (RT_SUCCESS(rc))
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync {
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync *ppTimer = pTimer;
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync return VINF_SUCCESS;
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync }
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync pTimer->u32Magic = 0;
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync RTSemEventDestroy(pTimer->Event);
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync pTimer->Event = NIL_RTSEMEVENT;
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync }
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync RTMemFree(pTimer);
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync return rc;
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync}
aa4bcf0a4b2db3ac352b56a291d49cb8d4b66d32vboxsyncRT_EXPORT_SYMBOL(RTTimerCreateEx);
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync/**
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync * Validates the timer handle.
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync *
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync * @returns true if valid, false if invalid.
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync * @param pTimer The handle.
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync */
cacc4e75dbbff469c10a505168208f064c6c385cvboxsyncDECLINLINE(bool) rtTimerIsValid(PRTTIMER pTimer)
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync{
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync AssertReturn(VALID_PTR(pTimer), false);
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync AssertReturn(pTimer->u32Magic == RTTIMER_MAGIC, false);
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync AssertReturn(!pTimer->fDestroyed, false);
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync return true;
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync}
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync
cacc4e75dbbff469c10a505168208f064c6c385cvboxsyncRTDECL(int) RTTimerDestroy(PRTTIMER pTimer)
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync{
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync /* It's ok to pass NULL pointer. */
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync if (pTimer == /*NIL_RTTIMER*/ NULL)
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync return VINF_SUCCESS;
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync if (!rtTimerIsValid(pTimer))
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync return VERR_INVALID_HANDLE;
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync /*
1be6c03d6e9f1ef801ff29b318baa5d42f1bfc2evboxsync * If the timer is active, we stop and destruct it in one go, to avoid
1be6c03d6e9f1ef801ff29b318baa5d42f1bfc2evboxsync * unnecessary waiting for the next tick. If it's suspended we can safely
1be6c03d6e9f1ef801ff29b318baa5d42f1bfc2evboxsync * set the destroy flag and signal it.
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync */
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync RTTHREAD Thread = pTimer->Thread;
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync if (!pTimer->fSuspended)
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync ASMAtomicXchgU8(&pTimer->fSuspended, true);
1be6c03d6e9f1ef801ff29b318baa5d42f1bfc2evboxsync ASMAtomicXchgU8(&pTimer->fDestroyed, true);
1be6c03d6e9f1ef801ff29b318baa5d42f1bfc2evboxsync int rc = RTSemEventSignal(pTimer->Event);
1be6c03d6e9f1ef801ff29b318baa5d42f1bfc2evboxsync if (rc == VERR_ALREADY_POSTED)
1be6c03d6e9f1ef801ff29b318baa5d42f1bfc2evboxsync rc = VINF_SUCCESS;
1be6c03d6e9f1ef801ff29b318baa5d42f1bfc2evboxsync AssertRC(rc);
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync RTThreadWait(Thread, 250, NULL);
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync return VINF_SUCCESS;
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync}
aa4bcf0a4b2db3ac352b56a291d49cb8d4b66d32vboxsyncRT_EXPORT_SYMBOL(RTTimerDestroy);
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync
cacc4e75dbbff469c10a505168208f064c6c385cvboxsyncRTDECL(int) RTTimerStart(PRTTIMER pTimer, uint64_t u64First)
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync{
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync if (!rtTimerIsValid(pTimer))
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync return VERR_INVALID_HANDLE;
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync if (!pTimer->fSuspended)
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync return VERR_TIMER_ACTIVE;
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync /*
ad27e1d5e48ca41245120c331cc88b50464813cevboxsync * Calc when it should start firing and give the thread a kick so it get going.
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync */
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync u64First += RTTimeNanoTS();
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync ASMAtomicXchgU64(&pTimer->iTick, 0);
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync ASMAtomicXchgU64(&pTimer->u64StartTS, u64First);
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync ASMAtomicXchgU64(&pTimer->u64NextTS, u64First);
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync ASMAtomicXchgU8(&pTimer->fSuspended, false);
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync int rc = RTSemEventSignal(pTimer->Event);
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync if (rc == VERR_ALREADY_POSTED)
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync rc = VINF_SUCCESS;
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync AssertRC(rc);
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync return rc;
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync}
aa4bcf0a4b2db3ac352b56a291d49cb8d4b66d32vboxsyncRT_EXPORT_SYMBOL(RTTimerStart);
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync
cacc4e75dbbff469c10a505168208f064c6c385cvboxsyncRTDECL(int) RTTimerStop(PRTTIMER pTimer)
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync{
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync if (!rtTimerIsValid(pTimer))
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync return VERR_INVALID_HANDLE;
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync if (pTimer->fSuspended)
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync return VERR_TIMER_SUSPENDED;
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync /*
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync * Mark it as suspended and kick the thread.
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync */
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync ASMAtomicXchgU8(&pTimer->fSuspended, true);
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync int rc = RTSemEventSignal(pTimer->Event);
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync if (rc == VERR_ALREADY_POSTED)
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync rc = VINF_SUCCESS;
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync AssertRC(rc);
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync return rc;
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync}
aa4bcf0a4b2db3ac352b56a291d49cb8d4b66d32vboxsyncRT_EXPORT_SYMBOL(RTTimerStop);
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsyncRTDECL(int) RTTimerChangeInterval(PRTTIMER pTimer, uint64_t u64NanoInterval)
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsync{
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsync if (!rtTimerIsValid(pTimer))
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsync return VERR_INVALID_HANDLE;
4e47bb772df0d04d1ded3e06354de547d52e2d06vboxsync NOREF(u64NanoInterval);
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsync return VERR_NOT_SUPPORTED;
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsync}
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsyncRT_EXPORT_SYMBOL(RTTimerChangeInterval);
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsync
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsync
4e47bb772df0d04d1ded3e06354de547d52e2d06vboxsyncstatic DECLCALLBACK(int) rtTimerThread(RTTHREAD hThreadSelf, void *pvUser)
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync{
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync PRTTIMER pTimer = (PRTTIMER)pvUser;
4e47bb772df0d04d1ded3e06354de547d52e2d06vboxsync NOREF(hThreadSelf);
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync /*
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync * The loop.
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync */
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync while (!pTimer->fDestroyed)
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync {
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync if (pTimer->fSuspended)
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync {
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync int rc = RTSemEventWait(pTimer->Event, RT_INDEFINITE_WAIT);
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync if (RT_FAILURE(rc) && rc != VERR_INTERRUPTED)
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync {
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync AssertRC(rc);
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync RTThreadSleep(1000); /* Don't cause trouble! */
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync }
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync }
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync else
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync {
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync const uint64_t u64NanoTS = RTTimeNanoTS();
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync if (u64NanoTS >= pTimer->u64NextTS)
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync {
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync pTimer->iTick++;
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync /* one shot? */
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync if (!pTimer->u64NanoInterval)
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync ASMAtomicXchgU8(&pTimer->fSuspended, true);
11bc79171b92d5853ebfa8b47a6db79a85347df3vboxsync pTimer->pfnTimer(pTimer, pTimer->pvUser, pTimer->iTick);
11bc79171b92d5853ebfa8b47a6db79a85347df3vboxsync
11bc79171b92d5853ebfa8b47a6db79a85347df3vboxsync /* status changed? */
11bc79171b92d5853ebfa8b47a6db79a85347df3vboxsync if (pTimer->fSuspended || pTimer->fDestroyed)
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync continue;
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync /* calc the next time we should fire. */
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync pTimer->u64NextTS = pTimer->u64StartTS + pTimer->iTick * pTimer->u64NanoInterval;
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync if (pTimer->u64NextTS < u64NanoTS)
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync#ifdef IN_RING3 /* In ring-3 we'll catch up lost ticks immediately. */
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync pTimer->u64NextTS = u64NanoTS + 1;
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync#else
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync pTimer->u64NextTS = u64NanoTS + RTTimerGetSystemGranularity() / 2;
d428342802b081b076970ddb499d215b79f087ccvboxsync#endif
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync }
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync /* block. */
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync uint64_t cNanoSeconds = pTimer->u64NextTS - u64NanoTS;
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync#ifdef IN_RING3 /* In ring-3 we'll catch up lost ticks immediately. */
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync if (cNanoSeconds > 10)
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync#endif
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync {
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync int rc = RTSemEventWait(pTimer->Event, cNanoSeconds < 1000000 ? 1 : cNanoSeconds / 1000000);
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync if (RT_FAILURE(rc) && rc != VERR_INTERRUPTED && rc != VERR_TIMEOUT)
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync {
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync AssertRC(rc);
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync RTThreadSleep(1000); /* Don't cause trouble! */
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync }
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync }
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync }
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync }
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync /*
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync * Release the timer resources.
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync */
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync ASMAtomicIncU32(&pTimer->u32Magic); /* make the handle invalid. */
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync int rc = RTSemEventDestroy(pTimer->Event); AssertRC(rc);
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync pTimer->Event = NIL_RTSEMEVENT;
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync pTimer->Thread = NIL_RTTHREAD;
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync RTMemFree(pTimer);
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync return VINF_SUCCESS;
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync}
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync
cacc4e75dbbff469c10a505168208f064c6c385cvboxsyncRTDECL(uint32_t) RTTimerGetSystemGranularity(void)
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync{
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync return 10000000; /* 10ms */
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync}
aa4bcf0a4b2db3ac352b56a291d49cb8d4b66d32vboxsyncRT_EXPORT_SYMBOL(RTTimerGetSystemGranularity);
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync
cacc4e75dbbff469c10a505168208f064c6c385cvboxsyncRTDECL(int) RTTimerRequestSystemGranularity(uint32_t u32Request, uint32_t *pu32Granted)
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync{
4e47bb772df0d04d1ded3e06354de547d52e2d06vboxsync NOREF(u32Request); NOREF(pu32Granted);
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync return VERR_NOT_SUPPORTED;
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync}
aa4bcf0a4b2db3ac352b56a291d49cb8d4b66d32vboxsyncRT_EXPORT_SYMBOL(RTTimerRequestSystemGranularity);
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync
cacc4e75dbbff469c10a505168208f064c6c385cvboxsyncRTDECL(int) RTTimerReleaseSystemGranularity(uint32_t u32Granted)
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync{
4e47bb772df0d04d1ded3e06354de547d52e2d06vboxsync NOREF(u32Granted);
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync return VERR_NOT_SUPPORTED;
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync}
aa4bcf0a4b2db3ac352b56a291d49cb8d4b66d32vboxsyncRT_EXPORT_SYMBOL(RTTimerReleaseSystemGranularity);
cacc4e75dbbff469c10a505168208f064c6c385cvboxsync
0dfc79e0666da4c8853deda18a14ebf5819d0d78vboxsync
0dfc79e0666da4c8853deda18a14ebf5819d0d78vboxsyncRTDECL(bool) RTTimerCanDoHighResolution(void)
0dfc79e0666da4c8853deda18a14ebf5819d0d78vboxsync{
0dfc79e0666da4c8853deda18a14ebf5819d0d78vboxsync return false;
0dfc79e0666da4c8853deda18a14ebf5819d0d78vboxsync}
0dfc79e0666da4c8853deda18a14ebf5819d0d78vboxsyncRT_EXPORT_SYMBOL(RTTimerCanDoHighResolution);