timer-r0drv-os2.cpp revision 590bfe12ce22cd3716448fbb9f4dc51664bfe5e2
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync/* $Id$ */
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync/** @file
5b281ba489ca18f0380d7efc7a5108b606cce449vboxsync * IPRT - Memory Allocation, Ring-0 Driver, OS/2.
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync */
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync/*
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync * Copyright (c) 2007 knut st. osmundsen <bird-src-spam@anduin.net>
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync *
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync * Permission is hereby granted, free of charge, to any person
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync * obtaining a copy of this software and associated documentation
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync * files (the "Software"), to deal in the Software without
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync * restriction, including without limitation the rights to use,
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync * copy, modify, merge, publish, distribute, sublicense, and/or sell
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync * copies of the Software, and to permit persons to whom the
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync * Software is furnished to do so, subject to the following
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync * conditions:
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync *
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync * The above copyright notice and this permission notice shall be
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync * included in all copies or substantial portions of the Software.
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync *
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync * OTHER DEALINGS IN THE SOFTWARE.
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync */
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync/*******************************************************************************
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync* Header Files *
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync*******************************************************************************/
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync#include "the-os2-kernel.h"
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync#include <iprt/timer.h>
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync#include <iprt/time.h>
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync#include <iprt/spinlock.h>
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync#include <iprt/err.h>
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync#include <iprt/asm.h>
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync#include <iprt/assert.h>
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync#include <iprt/alloc.h>
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync
881b5ff6bc55e1fb0f4ef42f9782ccec79c0a138vboxsync#include "internal/magics.h"
881b5ff6bc55e1fb0f4ef42f9782ccec79c0a138vboxsync
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync/*******************************************************************************
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync* Structures and Typedefs *
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync*******************************************************************************/
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync/**
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync * The internal representation of an OS/2 timer handle.
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync */
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsynctypedef struct RTTIMER
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync{
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync /** Magic.
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync * This is RTTIMER_MAGIC, but changes to something else before the timer
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync * is destroyed to indicate clearly that thread should exit. */
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync uint32_t volatile u32Magic;
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync /** The next timer in the timer list. */
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync PRTTIMER pNext;
9621896680fea9b2078823e8ef2e64cec5bf2da0vboxsync /** Flag indicating the timer is suspended. */
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync uint8_t volatile fSuspended;
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync /** Cleared at the start of timer processing, set when calling pfnTimer.
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync * If any timer changes occures while doing the callback this will be used to resume the cycle. */
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync bool fDone;
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync /** Callback. */
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync PFNRTTIMER pfnTimer;
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync /** User argument. */
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync void *pvUser;
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync /** The timer interval. 0 if one-shot. */
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync uint64_t u64NanoInterval;
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync /** The start of the current run.
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync * This is used to calculate when the timer ought to fire the next time. */
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync uint64_t volatile u64StartTS;
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync /** The start of the current run.
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync * This is used to calculate when the timer ought to fire the next time. */
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync uint64_t volatile u64NextTS;
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync /** The current tick number (since u64StartTS). */
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync uint64_t volatile iTick;
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync} RTTIMER;
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync/*******************************************************************************
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync* Global Variables *
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync*******************************************************************************/
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync/** Spinlock protecting the timers. */
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsyncstatic RTSPINLOCK g_Spinlock = NIL_RTSPINLOCK;
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync/** The timer head. */
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsyncstatic PRTTIMER volatile g_pTimerHead = NULL;
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync/** The number of active timers. */
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsyncstatic uint32_t volatile g_cActiveTimers = 0;
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync/** The number of active timers. */
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsyncstatic uint32_t volatile g_cTimers = 0;
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync/** The change number.
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync * This is used to detect list changes during the timer callback loop. */
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsyncstatic uint32_t volatile g_u32ChangeNo;
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync/*******************************************************************************
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync* Internal Functions *
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync*******************************************************************************/
590bfe12ce22cd3716448fbb9f4dc51664bfe5e2vboxsyncRT_C_DECLS_BEGIN
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsyncDECLASM(void) rtTimerOs2Tick(void);
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsyncDECLASM(int) rtTimerOs2Arm(void);
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsyncDECLASM(int) rtTimerOs2Dearm(void);
590bfe12ce22cd3716448fbb9f4dc51664bfe5e2vboxsyncRT_C_DECLS_END
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsyncRTDECL(int) RTTimerCreateEx(PRTTIMER *ppTimer, uint64_t u64NanoInterval, unsigned fFlags, PFNRTTIMER pfnTimer, void *pvUser)
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync{
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync *ppTimer = NULL;
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync
3f1eb07aba9eee6394f3084c956149ee9a27df09vboxsync /*
3f1eb07aba9eee6394f3084c956149ee9a27df09vboxsync * We don't support the fancy MP features.
3f1eb07aba9eee6394f3084c956149ee9a27df09vboxsync */
3f1eb07aba9eee6394f3084c956149ee9a27df09vboxsync if (fFlags & RTTIMER_FLAGS_CPU_SPECIFIC)
3f1eb07aba9eee6394f3084c956149ee9a27df09vboxsync return VERR_NOT_SUPPORTED;
3f1eb07aba9eee6394f3084c956149ee9a27df09vboxsync
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync /*
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync * Lazy initialize the spinlock.
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync */
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync if (g_Spinlock == NIL_RTSPINLOCK)
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync {
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync RTSPINLOCK Spinlock;
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync int rc = RTSpinlockCreate(&Spinlock);
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync AssertRCReturn(rc, rc);
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync //bool fRc;
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync //ASMAtomicCmpXchgSize(&g_Spinlock, Spinlock, NIL_RTSPINLOCK, fRc);
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync //if (!fRc)
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync if (!ASMAtomicCmpXchgPtr((void * volatile *)&g_Spinlock, Spinlock, NIL_RTSPINLOCK))
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync RTSpinlockDestroy(Spinlock);
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync }
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync /*
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync * Allocate and initialize the timer handle.
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync */
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync PRTTIMER pTimer = (PRTTIMER)RTMemAlloc(sizeof(*pTimer));
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync if (!pTimer)
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync return VERR_NO_MEMORY;
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync pTimer->u32Magic = RTTIMER_MAGIC;
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync pTimer->pNext = NULL;
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync pTimer->fSuspended = true;
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync pTimer->pfnTimer = pfnTimer;
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync pTimer->pvUser = pvUser;
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync pTimer->u64NanoInterval = u64NanoInterval;
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync pTimer->u64StartTS = 0;
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync /*
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync * Insert the timer into the list (LIFO atm).
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync */
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync RTSpinlockAcquireNoInts(g_Spinlock, &Tmp);
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync g_u32ChangeNo++;
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync pTimer->pNext = g_pTimerHead;
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync g_pTimerHead = pTimer;
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync g_cTimers++;
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync RTSpinlockReleaseNoInts(g_Spinlock, &Tmp);
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync *ppTimer = pTimer;
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync return VINF_SUCCESS;
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync}
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync/**
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync * Validates the timer handle.
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync *
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync * @returns true if valid, false if invalid.
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync * @param pTimer The handle.
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync */
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsyncDECLINLINE(bool) rtTimerIsValid(PRTTIMER pTimer)
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync{
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync AssertReturn(VALID_PTR(pTimer), false);
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync AssertReturn(pTimer->u32Magic == RTTIMER_MAGIC, false);
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync return true;
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync}
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsyncRTDECL(int) RTTimerDestroy(PRTTIMER pTimer)
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync{
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync /* It's ok to pass NULL pointer. */
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync if (pTimer == /*NIL_RTTIMER*/ NULL)
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync return VINF_SUCCESS;
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync if (!rtTimerIsValid(pTimer))
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync return VERR_INVALID_HANDLE;
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync /*
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync * Remove it from the list.
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync */
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync RTSpinlockAcquireNoInts(g_Spinlock, &Tmp);
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync g_u32ChangeNo++;
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync if (g_pTimerHead == pTimer)
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync g_pTimerHead = pTimer->pNext;
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync else
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync {
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync PRTTIMER pPrev = g_pTimerHead;
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync while (pPrev->pNext != pTimer)
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync {
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync pPrev = pPrev->pNext;
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync if (RT_UNLIKELY(!pPrev))
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync {
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync RTSpinlockReleaseNoInts(g_Spinlock, &Tmp);
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync return VERR_INVALID_HANDLE;
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync }
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync }
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync pPrev->pNext = pTimer->pNext;
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync }
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync Assert(g_cTimers > 0);
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync g_cTimers--;
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync if (!pTimer->fSuspended)
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync {
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync Assert(g_cActiveTimers > 0);
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync g_cActiveTimers--;
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync if (!g_cActiveTimers)
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync rtTimerOs2Dearm();
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync }
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync RTSpinlockReleaseNoInts(g_Spinlock, &Tmp);
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync /*
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync * Free the associated resources.
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync */
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync pTimer->u32Magic++;
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync RTMemFree(pTimer);
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync return VINF_SUCCESS;
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync}
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsyncRTDECL(int) RTTimerStart(PRTTIMER pTimer, uint64_t u64First)
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync{
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync if (!rtTimerIsValid(pTimer))
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync return VERR_INVALID_HANDLE;
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync if (!pTimer->fSuspended)
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync return VERR_TIMER_ACTIVE;
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync /*
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync * Calc when it should start fireing and give the thread a kick so it get going.
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync */
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync u64First += RTTimeNanoTS();
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync RTSpinlockAcquireNoInts(g_Spinlock, &Tmp);
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync g_u32ChangeNo++;
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync if (!g_cActiveTimers)
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync {
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync int rc = rtTimerOs2Arm();
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync if (RT_FAILURE(rc))
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync {
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync RTSpinlockReleaseNoInts(g_Spinlock, &Tmp);
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync return rc;
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync }
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync }
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync g_cActiveTimers++;
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync pTimer->fSuspended = false;
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync pTimer->fDone = true; /* next tick, not current! */
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync pTimer->iTick = 0;
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync pTimer->u64StartTS = u64First;
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync pTimer->u64NextTS = u64First;
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync RTSpinlockReleaseNoInts(g_Spinlock, &Tmp);
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync return VINF_SUCCESS;
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync}
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsyncRTDECL(int) RTTimerStop(PRTTIMER pTimer)
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync{
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync if (!rtTimerIsValid(pTimer))
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync return VERR_INVALID_HANDLE;
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync if (pTimer->fSuspended)
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync return VERR_TIMER_SUSPENDED;
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync /*
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync * Suspend the timer.
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync */
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync RTSpinlockAcquireNoInts(g_Spinlock, &Tmp);
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync g_u32ChangeNo++;
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync pTimer->fSuspended = true;
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync Assert(g_cActiveTimers > 0);
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync g_cActiveTimers--;
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync if (!g_cActiveTimers)
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync rtTimerOs2Dearm();
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync RTSpinlockReleaseNoInts(g_Spinlock, &Tmp);
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync return VINF_SUCCESS;
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync}
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsyncDECLASM(void) rtTimerOs2Tick(void)
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync{
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync /*
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync * Query the current time and then take the lock.
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync */
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync const uint64_t u64NanoTS = RTTimeNanoTS();
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync RTSpinlockAcquireNoInts(g_Spinlock, &Tmp);
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync /*
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync * Clear the fDone flag.
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync */
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync PRTTIMER pTimer;
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync for (pTimer = g_pTimerHead; pTimer; pTimer = pTimer->pNext)
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync pTimer->fDone = false;
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync /*
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync * Walk the timer list and do the callbacks for any active timer.
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync */
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync uint32_t u32CurChangeNo = g_u32ChangeNo;
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync pTimer = g_pTimerHead;
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync while (pTimer)
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync {
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync PRTTIMER pNext = pTimer->pNext;
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync if ( !pTimer->fSuspended
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync && !pTimer->fDone
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync && pTimer->u64NextTS <= u64NanoTS)
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync {
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync pTimer->fDone = true;
0f77dc54d7ec617480988ccdfcd080f480e79698vboxsync pTimer->iTick++;
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync /* calculate the next timeout */
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync if (!pTimer->u64NanoInterval)
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync pTimer->fSuspended = true;
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync else
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync {
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync pTimer->u64NextTS = pTimer->u64StartTS + pTimer->iTick * pTimer->u64NanoInterval;
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync if (pTimer->u64NextTS < u64NanoTS)
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync pTimer->u64NextTS = u64NanoTS + RTTimerGetSystemGranularity() / 2;
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync }
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync /* do the callout */
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync PFNRTTIMER pfnTimer = pTimer->pfnTimer;
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync void *pvUser = pTimer->pvUser;
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync RTSpinlockReleaseNoInts(g_Spinlock, &Tmp);
0f77dc54d7ec617480988ccdfcd080f480e79698vboxsync pfnTimer(pTimer, pvUser, pTimer->iTick);
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync RTSpinlockAcquireNoInts(g_Spinlock, &Tmp);
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync /* check if anything changed. */
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync if (u32CurChangeNo != g_u32ChangeNo)
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync {
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync u32CurChangeNo = g_u32ChangeNo;
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync pNext = g_pTimerHead;
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync }
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync }
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync /* next */
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync pTimer = pNext;
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync }
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync RTSpinlockReleaseNoInts(g_Spinlock, &Tmp);
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync}
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsyncRTDECL(uint32_t) RTTimerGetSystemGranularity(void)
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync{
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync return 32000000; /* 32ms */
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync}
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsyncRTDECL(int) RTTimerRequestSystemGranularity(uint32_t u32Request, uint32_t *pu32Granted)
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync{
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync return VERR_NOT_SUPPORTED;
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync}
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsyncRTDECL(int) RTTimerReleaseSystemGranularity(uint32_t u32Granted)
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync{
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync return VERR_NOT_SUPPORTED;
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync}
d1c5a03c19683c719b94496bb998fde2f2e5e622vboxsync