timer-r0drv-solaris.c revision 6988e736149e8800875f9fbb001a6018926d6562
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync/** $Id$ */
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync/** @file
45565249f149f7562fc6ee85be7ca3a3706e32e6vboxsync * innotek Portable Runtime - Timer, Ring-0 Driver, Solaris.
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync */
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync/*
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync * Copyright (C) 2006-2007 innotek GmbH
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync *
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync * available from http://www.virtualbox.org. This file is free software;
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync * you can redistribute it and/or modify it under the terms of the GNU
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync * General Public License as published by the Free Software Foundation,
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync * in version 2 as it comes in the "COPYING" file of the VirtualBox OSE
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync * distribution. VirtualBox OSE is distributed in the hope that it will
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync * be useful, but WITHOUT ANY WARRANTY of any kind.
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync */
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync/*******************************************************************************
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync* Header Files *
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync*******************************************************************************/
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync#include "the-solaris-kernel.h"
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync#include <iprt/timer.h>
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync#include <iprt/time.h>
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync#include <iprt/spinlock.h>
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync#include <iprt/err.h>
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync#include <iprt/asm.h>
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync#include <iprt/assert.h>
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync#include <iprt/alloc.h>
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync#include "internal/magics.h"
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync
45565249f149f7562fc6ee85be7ca3a3706e32e6vboxsync
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync/*******************************************************************************
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync* Structures and Typedefs *
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync*******************************************************************************/
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync/**
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync * The internal representation of a Solaris timer handle.
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync */
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsynctypedef struct RTTIMER
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync{
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync /** Magic.
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync * This is RTTIMER_MAGIC, but changes to something else before the timer
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync * is destroyed to indicate clearly that thread should exit. */
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync uint32_t volatile u32Magic;
3393c62e395aa8388303d99f765a219efc289158vboxsync /** Flag indicating the the timer is suspended. */
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync uint8_t volatile fSuspended;
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync /** Whether the timer must run on a specific CPU or not. */
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync uint8_t fSpecificCpu;
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync /** The CPU it must run on if fSpecificCpu is set. */
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync uint8_t iCpu;
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync /** The Solaris cyclic structure. */
cea5568645ca17479265436cfd5ba010ddd106d9vboxsync cyc_handler_t CyclicInfo;
45565249f149f7562fc6ee85be7ca3a3706e32e6vboxsync /** The Solaris cyclic handle. */
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync cyclic_id_t CyclicID;
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync /** Callback. */
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync PFNRTTIMER pfnTimer;
cea5568645ca17479265436cfd5ba010ddd106d9vboxsync /** User argument. */
cea5568645ca17479265436cfd5ba010ddd106d9vboxsync void *pvUser;
cea5568645ca17479265436cfd5ba010ddd106d9vboxsync /** The timer interval. 0 for one-shot timer */
cea5568645ca17479265436cfd5ba010ddd106d9vboxsync uint64_t u64NanoInterval;
cea5568645ca17479265436cfd5ba010ddd106d9vboxsync} RTTIMER;
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync/*******************************************************************************
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync* Internal Functions *
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync*******************************************************************************/
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsyncstatic void rtTimerSolarisCallback(void *pvTimer);
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsyncstatic void rtTimerSolarisStop(PRTTIMER pTimer);
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsyncRTDECL(int) RTTimerCreateEx(PRTTIMER *ppTimer, uint64_t u64NanoInterval, unsigned fFlags, PFNRTTIMER pfnTimer, void *pvUser)
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync{
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync *ppTimer = NULL;
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync /*
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync * Validate flags.
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync */
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync if (!RTTIMER_FLAGS_IS_VALID(fFlags))
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync return VERR_INVALID_PARAMETER;
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync if ( (fFlags & RTTIMER_FLAGS_CPU_SPECIFIC)
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync /** @todo implement && (fFlags & RTTIMER_FLAGS_CPU_ALL) != RTTIMER_FLAGS_CPU_ALL*/)
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync return VERR_NOT_SUPPORTED;
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync /*
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync * Allocate and initialize the timer handle.
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync */
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync PRTTIMER pTimer = (PRTTIMER)RTMemAlloc(sizeof(*pTimer));
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync if (!pTimer)
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync return VERR_NO_MEMORY;
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync pTimer->u32Magic = RTTIMER_MAGIC;
cea5568645ca17479265436cfd5ba010ddd106d9vboxsync pTimer->fSuspended = true;
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync pTimer->fSpecificCpu = !!(fFlags & RTTIMER_FLAGS_CPU_SPECIFIC);
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync pTimer->iCpu = fFlags & RTTIMER_FLAGS_CPU_MASK;
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync pTimer->CyclicInfo.cyh_func = rtTimerSolarisCallback;
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync pTimer->CyclicInfo.cyh_level = CY_LOCK_LEVEL;
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync pTimer->CyclicInfo.cyh_arg = pTimer;
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync pTimer->CyclicID = CYCLIC_NONE;
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync pTimer->u64NanoInterval = u64NanoInterval;
8d7d0a641afd3eb2aacf2b3ba428e6d8894a6a5fvboxsync pTimer->pfnTimer = pfnTimer;
8d7d0a641afd3eb2aacf2b3ba428e6d8894a6a5fvboxsync pTimer->pvUser = pvUser;
8d7d0a641afd3eb2aacf2b3ba428e6d8894a6a5fvboxsync
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync *ppTimer = pTimer;
8d7d0a641afd3eb2aacf2b3ba428e6d8894a6a5fvboxsync return VINF_SUCCESS;
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync}
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync/**
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync * Validates the timer handle.
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync *
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync * @returns true if valid, false if invalid.
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync * @param pTimer The handle.
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync */
84eeabfd29e718854e00e795879dab6ce61469e5vboxsyncDECLINLINE(bool) rtTimerIsValid(PRTTIMER pTimer)
a93da6c0946d71f517dc6d64a633704cb99068b8vboxsync{
a93da6c0946d71f517dc6d64a633704cb99068b8vboxsync AssertReturn(VALID_PTR(pTimer), false);
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync AssertReturn(pTimer->u32Magic == RTTIMER_MAGIC, false);
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync return true;
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync}
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsyncRTDECL(int) RTTimerDestroy(PRTTIMER pTimer)
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync{
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync if (pTimer == NULL)
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync return VINF_SUCCESS;
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync if (!rtTimerIsValid(pTimer))
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync return VERR_INVALID_HANDLE;
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync /*
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync * Free the associated resources.
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync */
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync pTimer->u32Magic++;
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync rtTimerSolarisStop(pTimer);
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync RTMemFree(pTimer);
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync return VINF_SUCCESS;
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync}
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsyncRTDECL(int) RTTimerStart(PRTTIMER pTimer, uint64_t u64First)
cf0b951d0e7a93540b3931ca506ed97c1dc300ccvboxsync{
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync cyc_time_t timerSpec;
cf0b951d0e7a93540b3931ca506ed97c1dc300ccvboxsync
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync if (!rtTimerIsValid(pTimer))
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync return VERR_INVALID_HANDLE;
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync if (!pTimer->fSuspended)
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync return VERR_TIMER_ACTIVE;
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync /*
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync * Calc when it should start fireing.
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync */
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync u64First += RTTimeNanoTS();
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync pTimer->fSuspended = false;
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync timerSpec.cyt_when = u64First;
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync timerSpec.cyt_interval = pTimer->u64NanoInterval == 0 ? u64First : pTimer->u64NanoInterval;
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync rtTimerSolarisStop(pTimer); /** @todo r=bird: can't happen. */
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync pTimer->CyclicID = cyclic_add(&pTimer->CyclicInfo, &timerSpec);
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync return VINF_SUCCESS;
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync}
a93da6c0946d71f517dc6d64a633704cb99068b8vboxsync
b47847090b3c99e4fdf905536053595e75845265vboxsync
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsyncRTDECL(int) RTTimerStop(PRTTIMER pTimer)
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync{
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync if (!rtTimerIsValid(pTimer))
4b30f6c72b07654509606857da385afcc09aaae3vboxsync return VERR_INVALID_HANDLE;
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync if (pTimer->fSuspended)
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync return VERR_TIMER_SUSPENDED;
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync /*
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync * Suspend the timer.
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync */
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync pTimer->fSuspended = true;
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync rtTimerSolarisStop(pTimer);
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync return VINF_SUCCESS;
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync}
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync
84eeabfd29e718854e00e795879dab6ce61469e5vboxsyncstatic void rtTimerSolarisCallback(void *pvTimer)
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync{
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync PRTTIMER pTimer = (PRTTIMER)pvTimer;
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync /* If this is a one shot timer, call pfnTimer and suspend
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync * as Solaris does not support 0 interval timers implictly
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync */
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync if (!pTimer->u64NanoInterval)
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync {
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync pTimer->fSuspended = true;
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync rtTimerSolarisStop(pTimer);
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync }
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync
4b30f6c72b07654509606857da385afcc09aaae3vboxsync /* Callback user defined callback function */
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync pTimer->pfnTimer(pTimer, pTimer->pvUser);
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync}
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsyncstatic void rtTimerSolarisStop(PRTTIMER pTimer)
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync{
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync /* Important we check for invalid cyclic object */
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync if (pTimer->CyclicID != CYCLIC_NONE)
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync {
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync cyclic_remove(pTimer->CyclicID);
a93da6c0946d71f517dc6d64a633704cb99068b8vboxsync pTimer->CyclicID = CYCLIC_NONE;
b47847090b3c99e4fdf905536053595e75845265vboxsync }
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync}
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsyncRTDECL(uint32_t) RTTimerGetSystemGranularity(void)
4fe68a6b363f8944c4305b845a95580cd547937fvboxsync{
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync return nsec_per_tick;
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync}
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync
4b30f6c72b07654509606857da385afcc09aaae3vboxsyncRTDECL(int) RTTimerRequestSystemGranularity(uint32_t u32Request, uint32_t *pu32Granted)
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync{
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync return VERR_NOT_SUPPORTED;
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync}
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsyncRTDECL(int) RTTimerReleaseSystemGranularity(uint32_t u32Granted)
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync{
bb73206f5ad484c56a70984ee9897e9ffee18b8bvboxsync return VERR_NOT_SUPPORTED;
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync}
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync
84eeabfd29e718854e00e795879dab6ce61469e5vboxsync