VirtualBox

Changeset 32572 in vbox


Ignore:
Timestamp:
Sep 16, 2010 4:18:12 PM (15 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
65965
Message:

VMM,SUPDrv,IPRT: More changes for related to the priodic preemption timer. (still disabled)

Location:
trunk
Files:
1 added
20 edited

Legend:

Unmodified
Added
Removed
  • trunk/include/iprt/mp.h

    r28800 r32572  
    7373 * Gets the max CPU identifier (inclusive).
    7474 *
    75  * Inteded for brute force enumerations, but use with
     75 * Intended for brute force enumerations, but use with
    7676 * care as it may be expensive.
    7777 *
     
    8080RTDECL(RTCPUID) RTMpGetMaxCpuId(void);
    8181
     82/**
     83 * Gets the size of a CPU array that is indexed by CPU set index.
     84 *
     85 * This takes both online, offline and hot-plugged cpus into account.
     86 *
     87 * @returns Number of elements.
     88 *
     89 * @remarks Use RTMpCpuIdToSetIndex to convert a RTCPUID into an array index.
     90 */
     91RTDECL(uint32_t) RTMpGetArraySize(void);
    8292
    8393/**
     
    102112 * possibly be hotplugged later.
    103113 *
    104  * @return The count.
     114 * @returns The count.
     115 * @remarks Don't use this for CPU array sizing, use RTMpGetArraySize instead.
    105116 */
    106117RTDECL(RTCPUID) RTMpGetCount(void);
  • trunk/include/iprt/timer.h

    r32504 r32572  
    9393 *                              on every timer tick.
    9494 * @param   pvUser              User argument for the callback.
    95  * @see     RTTimerDestroy, RTTimerStop
     95 * @see     RTTimerCreateEx, RTTimerStart, RTTimerStop, RTTimerChangeInterval,
     96 *          RTTimerDestroy, RTTimerGetSystemGranularity
    9697 */
    9798RTDECL(int) RTTimerCreate(PRTTIMER *ppTimer, unsigned uMilliesInterval, PFNRTTIMER pfnTimer, void *pvUser);
     
    102103 * @returns iprt status code.
    103104 * @retval  VERR_NOT_SUPPORTED if an unsupported flag was specfied.
     105 * @retval  VERR_CPU_NOT_FOUND if the specified CPU
    104106 *
    105107 * @param   ppTimer             Where to store the timer handle.
     
    111113 *                              on every timer tick.
    112114 * @param   pvUser              User argument for the callback.
    113  * @see     RTTimerStart, RTTimerStop, RTTimerDestroy, RTTimerGetSystemGranularity
    114  */
    115 RTDECL(int) RTTimerCreateEx(PRTTIMER *ppTimer, uint64_t u64NanoInterval, unsigned fFlags, PFNRTTIMER pfnTimer, void *pvUser);
     115 * @see     RTTimerStart, RTTimerStop, RTTimerChangeInterval, RTTimerDestroy,
     116 *          RTTimerGetSystemGranularity, RTTimerCanDoHighResolution
     117 */
     118RTDECL(int) RTTimerCreateEx(PRTTIMER *ppTimer, uint64_t u64NanoInterval, uint32_t fFlags, PFNRTTIMER pfnTimer, void *pvUser);
    116119
    117120/** @name RTTimerCreateEx flags
    118121 * @{ */
    119122/** Any CPU is fine. (Must be 0.) */
    120 #define RTTIMER_FLAGS_CPU_ANY        0
     123#define RTTIMER_FLAGS_CPU_ANY       UINT32_C(0)
    121124/** One specific CPU */
    122 #define RTTIMER_FLAGS_CPU_SPECIFIC   RT_BIT(8)
     125#define RTTIMER_FLAGS_CPU_SPECIFIC  RT_BIT(8)
    123126/** Omni timer, run on all online CPUs.
    124127 * @remarks The timer callback isn't necessarily running at the time same time on each CPU. */
    125 #define RTTIMER_FLAGS_CPU_ALL        ( RTTIMER_FLAGS_CPU_MASK | RTTIMER_FLAGS_CPU_SPECIFIC )
     128#define RTTIMER_FLAGS_CPU_ALL       ( RTTIMER_FLAGS_CPU_MASK | RTTIMER_FLAGS_CPU_SPECIFIC )
    126129/** CPU mask. */
    127 #define RTTIMER_FLAGS_CPU_MASK       0xff
    128 /** Convert a CPU number (0-based) to RTTimerCreateEx flags.
    129  * This will automatically OR in the RTTIMER_FLAG_CPU_SPECIFIC flag. */
    130 #define RTTIMER_FLAGS_CPU(iCpu)      ( (iCpu) | RTTIMER_FLAG_CPU_SPECIFIC )
     130#define RTTIMER_FLAGS_CPU_MASK      UINT32_C(0xff)
     131/** Desire a high resolution timer that works with RTTimerChangeInterval and
     132 * isn't subject to RTTimerGetSystemGranularity rounding.
     133 * @remarks This is quietly ignored if the feature isn't supported. */
     134#define RTTIMER_FLAGS_HIGH_RES      RT_BIT(9)
     135/** Convert a CPU set index (0-based) to RTTimerCreateEx flags.
     136 * This will automatically OR in the RTTIMER_FLAGS_CPU_SPECIFIC flag. */
     137#define RTTIMER_FLAGS_CPU(iCpu)     ( (iCpu) | RTTIMER_FLAGS_CPU_SPECIFIC )
    131138/** Macro that validates the flags. */
    132 #define RTTIMER_FLAGS_ARE_VALID(fFlags) ( !((fFlags) & ~((fFlags) & RTTIMER_FLAGS_CPU_SPECIFIC ? 0x1ffU : 0x100U)) )
     139#define RTTIMER_FLAGS_ARE_VALID(fFlags) \
     140    ( !((fFlags) & ~((fFlags) & RTTIMER_FLAGS_CPU_SPECIFIC ? UINT32_C(0x3ff) : UINT32_C(0x300))) )
    133141/** @} */
    134142
     
    147155 * @retval  VERR_INVALID_HANDLE if pTimer isn't valid.
    148156 * @retval  VERR_TIMER_ACTIVE if the timer isn't suspended.
     157 * @retval  VERR_CPU_OFFLINE if the CPU the timer was created to run on is not
     158 *          online (this include the case where it's not present in the
     159 *          system).
    149160 *
    150161 * @param   pTimer      The timer to activate.
    151162 * @param   u64First    The RTTimeSystemNanoTS() for when the timer should start
    152  *                      firing (relative). If 0 is specified, the timer will fire ASAP.
     163 *                      firing (relative).  If 0 is specified, the timer will
     164 *                      fire ASAP.
     165 * @remarks When RTTimerCanDoHighResolution returns true, this API is
     166 *          callable with preemption disabled in ring-0.
    153167 * @see     RTTimerStop
    154168 */
     
    161175 * @retval  VERR_INVALID_HANDLE if pTimer isn't valid.
    162176 * @retval  VERR_TIMER_SUSPENDED if the timer isn't active.
    163  * @retval  VERR_NOT_SUPPORTED if the IPRT implementation doesn't support stopping a timer.
     177 * @retval  VERR_NOT_SUPPORTED if the IPRT implementation doesn't support
     178 *          stopping a timer.
    164179 *
    165180 * @param   pTimer  The timer to suspend.
     181 * @remarks Can be called from the timer callback function to stop it.
    166182 * @see     RTTimerStart
    167183 */
    168184RTDECL(int) RTTimerStop(PRTTIMER pTimer);
    169185
     186/**
     187 * Changes the interval of a periodic timer.
     188 *
     189 * If the timer is active, it is implementation dependent whether the change
     190 * takes place immediately or after the next tick.  To get defined behavior,
     191 * stop the timer before calling this API.
     192 *
     193 * @returns IPRT status code.
     194 * @retval  VERR_INVALID_HANDLE if pTimer isn't valid.
     195 * @retval  VERR_NOT_SUPPORTED if not supported.
     196 *
     197 * @param   pTimer              The timer to activate.
     198 * @param   u64NanoInterval     The interval between timer ticks specified in
     199 *                              nanoseconds.  This is rounded to the fit the
     200 *                              system timer granularity.
     201 * @remarks Callable from the timer callback.  Callable with preemption
     202 *          disabled in ring-0.
     203 */
     204RTDECL(int) RTTimerChangeInterval(PRTTIMER pTimer, uint64_t u64NanoInterval);
    170205
    171206/**
     
    225260 *
    226261 * @returns true if supported, false it not.
     262 *
     263 * @remarks Returning true also means RTTimerChangeInterval must be implemented
     264 *          and RTTimerStart be callable with preemption disabled.
    227265 */
    228266RTDECL(bool) RTTimerCanDoHighResolution(void);
  • trunk/src/VBox/HostDrivers/Support/SUPDrv.c

    r32504 r32572  
    276276    { "RTTimerStart",                           (void *)RTTimerStart },
    277277    { "RTTimerStop",                            (void *)RTTimerStop },
     278    { "RTTimerChangeInterval",                  (void *)RTTimerChangeInterval },
    278279    { "RTTimerGetSystemGranularity",            (void *)RTTimerGetSystemGranularity },
    279280    { "RTTimerRequestSystemGranularity",        (void *)RTTimerRequestSystemGranularity },
     
    285286    { "RTMpCpuIdFromSetIndex",                  (void *)RTMpCpuIdFromSetIndex },
    286287    { "RTMpCpuIdToSetIndex",                    (void *)RTMpCpuIdToSetIndex },
     288    { "RTMpGetArraySize",                       (void *)RTMpGetArraySize },
    287289    { "RTMpIsCpuPossible",                      (void *)RTMpIsCpuPossible },
    288290    { "RTMpGetCount",                           (void *)RTMpGetCount },
     
    49044906     * ever increasing. We don't bother taking TSC rollover into account.
    49054907     */
    4906     RTCPUSET    CpuSet;
    4907     int         iLastCpu = RTCpuLastIndex(RTMpGetSet(&CpuSet));
     4908    int         iEndCpu = RTMpGetArraySize();
    49084909    int         iCpu;
    49094910    int         cLoops = 8;
     
    49164917    while (cLoops-- > 0)
    49174918    {
    4918         for (iCpu = 0; iCpu <= iLastCpu; iCpu++)
     4919        for (iCpu = 0; iCpu < iEndCpu; iCpu++)
    49194920        {
    49204921            uint64_t CurTsc;
     
    49524953
    49534954        /* broke out of the loop. */
    4954         if (iCpu <= iLastCpu)
     4955        if (iCpu < iEndCpu)
    49554956            break;
    49564957    }
    49574958
    49584959    *poffMin = offMin; /* Almost RTMpOnSpecific profiling. */
    4959     Log(("supdrvDetermineAsyncTsc: returns %d; iLastCpu=%d rc=%d offMin=%llx offMax=%llx\n",
    4960          fAsync, iLastCpu, rc, offMin, offMax));
     4960    Log(("supdrvDetermineAsyncTsc: returns %d; iEndCpu=%d rc=%d offMin=%llx offMax=%llx\n",
     4961         fAsync, iEndCpu, rc, offMin, offMax));
    49614962#if !defined(RT_OS_SOLARIS) && !defined(RT_OS_OS2) && !defined(RT_OS_WINDOWS)
    49624963    OSDBGPRINT(("vboxdrv: fAsync=%d offMin=%#lx offMax=%#lx\n", fAsync, (long)offMin, (long)offMax));
  • trunk/src/VBox/HostDrivers/Support/SUPDrvIOC.h

    r32504 r32572  
    193193 *          - Nothing.
    194194 */
    195 #define SUPDRV_IOC_VERSION                              0x00150002
     195#define SUPDRV_IOC_VERSION                              0x00150003
    196196
    197197/** SUP_IOCTL_COOKIE. */
  • trunk/src/VBox/HostDrivers/Support/SUPLib.cpp

    r32504 r32572  
    269269        CookieReq.u.In.u32ReqVersion = SUPDRV_IOC_VERSION;
    270270        const uint32_t uMinVersion = (SUPDRV_IOC_VERSION & 0xffff0000) == 0x00150000
    271                                    ?  0x00150002
     271                                   ?  0x00150003
    272272                                   : SUPDRV_IOC_VERSION & 0xffff0000;
    273273        CookieReq.u.In.u32MinVersion = uMinVersion;
     
    424424        { "RTR0MemObjMapKernel",                    0xefef001b },
    425425        { "RTR0MemObjMapKernelEx",                  0xefef001c },
     426        { "RTMpGetArraySize",                       0xefef001c },
    426427        { "RTProcSelf",                             0xefef001d },
    427428        { "RTR0ProcHandleSelf",                     0xefef001e },
     
    459460        { "RTTimerStart",                           0xefef003a },
    460461        { "RTTimerStop",                            0xefef003a },
     462        { "RTTimerChangeInterval",                  0xefef003a },
    461463        { "RTTimerGetSystemGranularity",            0xefef003a },
    462464        { "RTTimerRequestSystemGranularity",        0xefef003a },
  • trunk/src/VBox/HostDrivers/Support/SUPR0.def

    r32507 r32572  
    138138    RTTimerStart
    139139    RTTimerStop
     140    RTTimerChangeInterval
    140141    RTTimerGetSystemGranularity
    141142    RTTimerRequestSystemGranularity
     
    143144    RTTimerCanDoHighResolution
    144145
     146    RTMpCpuId
     147    RTMpCpuIdToSetIndex
     148    RTMpGetArraySize
     149    RTMpGetCount
     150    RTMpIsCpuOnline
     151    RTMpIsCpuWorkPending
    145152    RTMpOnAll
    146153    RTMpOnOthers
    147154    RTMpOnSpecific
    148155    RTMpPokeCpu
    149     RTMpIsCpuOnline
    150     RTMpGetCount
    151     RTMpCpuIdToSetIndex
    152     RTMpCpuId
    153     RTMpIsCpuWorkPending
    154156    RTPowerNotificationRegister
    155157    RTPowerNotificationDeregister
  • trunk/src/VBox/HostDrivers/Support/freebsd/Makefile

    r31842 r32572  
    125125        RTLogWriteStdErr-stub-generic.c \
    126126        RTLogWriteUser-generic.c \
     127        RTMpGetArraySize-generic.c \
    127128        RTRandAdvCreateSystemFaster-generic.c \
    128129        RTRandAdvCreateSystemTruer-generic.c \
  • trunk/src/VBox/HostDrivers/Support/freebsd/files_vboxdrv

    r31847 r32572  
    150150    ${PATH_ROOT}/src/VBox/Runtime/generic/uuid-generic.cpp=>generic/uuid-generic.c \
    151151    ${PATH_ROOT}/src/VBox/Runtime/generic/RTTimerCreate-generic.cpp=>generic/RTTimerCreate-generic.c \
     152    ${PATH_ROOT}/src/VBox/Runtime/generic/RTMpGetArraySize-generic.cpp=>generic/RTMpGetArraySize-generic.c \
    152153    ${PATH_ROOT}/src/VBox/Runtime/generic/timer-generic.cpp=>generic/timer-generic.c \
    153154    ${PATH_ROOT}/src/VBox/Runtime/generic/mppresent-generic.cpp=>generic/mppresent-generic.c \
  • trunk/src/VBox/HostDrivers/Support/linux/Makefile

    r32537 r32572  
    130130        generic/RTLogWriteStdOut-stub-generic.o \
    131131        generic/RTLogWriteUser-generic.o \
     132        generic/RTMpGetArraySize-generic.o \
    132133        generic/RTTimerCreate-generic.o \
    133134        generic/uuid-generic.o \
  • trunk/src/VBox/HostDrivers/Support/linux/files_vboxdrv

    r32504 r32572  
    128128    ${PATH_ROOT}/src/VBox/Runtime/generic/RTLogWriteStdOut-stub-generic.cpp=>generic/RTLogWriteStdOut-stub-generic.c \
    129129    ${PATH_ROOT}/src/VBox/Runtime/generic/RTLogWriteUser-generic.cpp=>generic/RTLogWriteUser-generic.c \
     130    ${PATH_ROOT}/src/VBox/Runtime/generic/RTMpGetArraySize-generic.cpp=>generic/RTMpGetArraySize-generic.c \
    130131    ${PATH_ROOT}/src/VBox/Runtime/generic/RTTimerCreate-generic.cpp=>generic/RTTimerCreate-generic.c \
    131132    ${PATH_ROOT}/src/VBox/Runtime/generic/uuid-generic.cpp=>generic/uuid-generic.c \
  • trunk/src/VBox/Runtime/Makefile.kmk

    r32529 r32572  
    13901390        generic/RTLogWriteStdErr-stub-generic.cpp \
    13911391        generic/RTLogWriteUser-generic.cpp \
     1392        generic/RTMpGetArraySize-generic.cpp \
    13921393        generic/RTRandAdvCreateSystemFaster-generic.cpp \
    13931394        generic/uuid-generic.cpp \
  • trunk/src/VBox/Runtime/generic/timer-generic.cpp

    r32504 r32572  
    8787
    8888
    89 RTDECL(int) RTTimerCreateEx(PRTTIMER *ppTimer, uint64_t u64NanoInterval, unsigned fFlags, PFNRTTIMER pfnTimer, void *pvUser)
     89RTDECL(int) RTTimerCreateEx(PRTTIMER *ppTimer, uint64_t u64NanoInterval, uint32_t fFlags, PFNRTTIMER pfnTimer, void *pvUser)
    9090{
    9191    *ppTimer = NULL;
     
    225225}
    226226RT_EXPORT_SYMBOL(RTTimerStop);
     227
     228
     229RTDECL(int) RTTimerChangeInterval(PRTTIMER pTimer, uint64_t u64NanoInterval)
     230{
     231    if (!rtTimerIsValid(pTimer))
     232        return VERR_INVALID_HANDLE;
     233    return VERR_NOT_SUPPORTED;
     234}
     235RT_EXPORT_SYMBOL(RTTimerChangeInterval);
    227236
    228237
  • trunk/src/VBox/Runtime/r0drv/freebsd/timer-r0drv-freebsd.c

    r32504 r32572  
    9090
    9191
    92 RTDECL(int) RTTimerCreateEx(PRTTIMER *ppTimer, uint64_t u64NanoInterval, unsigned fFlags, PFNRTTIMER pfnTimer, void *pvUser)
     92RTDECL(int) RTTimerCreateEx(PRTTIMER *ppTimer, uint64_t u64NanoInterval, uint32_t fFlags, PFNRTTIMER pfnTimer, void *pvUser)
    9393{
    9494    *ppTimer = NULL;
     
    102102        &&  (fFlags & RTTIMER_FLAGS_CPU_ALL) != RTTIMER_FLAGS_CPU_ALL
    103103        &&  (fFlags & RTTIMER_FLAGS_CPU_MASK) > mp_maxid)
    104         return VERR_INVALID_PARAMETER;
     104        return VERR_CPU_NOT_FOUND;
    105105
    106106    /*
     
    166166    if (!pTimer->fSuspended)
    167167        return VERR_TIMER_ACTIVE;
     168    if (   pTimer->fSpecificCpu
     169        && !RTMpIsCpuOnline(pTimer->idCpu))
     170        return VERR_CPU_OFFLINE;
    168171
    169172    /*
     
    199202
    200203    return VINF_SUCCESS;
     204}
     205
     206
     207RTDECL(int) RTTimerChangeInterval(PRTTIMER pTimer, uint64_t u64NanoInterval)
     208{
     209    if (!rtTimerIsValid(pTimer))
     210        return VERR_INVALID_HANDLE;
     211    return VERR_NOT_SUPPORTED;
    201212}
    202213
  • trunk/src/VBox/Runtime/r0drv/linux/timer-r0drv-linux.c

    r32504 r32572  
    55
    66/*
    7  * Copyright (C) 2006-2008 Oracle Corporation
     7 * Copyright (C) 2006-2010 Oracle Corporation
    88 *
    99 * This file is part of VirtualBox Open Source Edition (OSE), as
     
    4444#include "internal/magics.h"
    4545
    46 /* We use the API of Linux 2.6.28+ (hrtimer_add_expires_ns()) */
    47 #if !defined(RT_USE_LINUX_HRTIMER) \
    48     && LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 28) \
     46/** @def RTTIMER_LINUX_HAVE_HRTIMER
     47 * Whether the kernel support high resolution timers (Linux kernel versions
     48 * 2.6.28 and later (hrtimer_add_expires_ns()). */
     49#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 28)
     50# define RTTIMER_LINUX_HAVE_HRTIMER
     51#endif
     52
     53/** @def RTTIMER_LINUX_ONLY_HRTIMER
     54 * Whether to use high resolution timers for everything or not.  Implies
     55 * RTTIMER_LINUX_WITH_HRTIMER. */
     56#if !defined(RTTIMER_LINUX_ONLY_HRTIMER) \
     57    && defined(RTTIMER_LINUX_HAVE_HRTIMER) \
    4958    && 0 /* currently disabled */
    50 # define RT_USE_LINUX_HRTIMER
     59# define RTTIMER_LINUX_ONLY_HRTIMER
    5160#endif
    5261
    5362/* This check must match the ktime usage in rtTimeGetSystemNanoTS() / time-r0drv-linux.c. */
    54 #if defined(RT_USE_LINUX_HRTIMER) \
    55  && LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 28)
    56 # error "RT_USE_LINUX_HRTIMER requires 2.6.28 or later, sorry."
     63#if defined(RTTIMER_LINUX_ONLY_HRTIMER) \
     64 && !defined(RTTIMER_LINUX_HAVE_HRTIMER)
     65# error "RTTIMER_LINUX_ONLY_HRTIMER requires 2.6.28 or later, sorry."
     66#endif
     67
     68/** @def RTTIMER_LINUX_WITH_HRTIMER
     69 * Whether to use high resolution timers.  */
     70#if !defined(RTTIMER_LINUX_WITH_HRTIMER) \
     71    && defined(RTTIMER_LINUX_HAVE_HRTIMER)
     72# define RTTIMER_LINUX_WITH_HRTIMER
    5773#endif
    5874
     
    96112typedef struct RTTIMERLNXSUBTIMER
    97113{
    98     /** The linux timer structure. */
    99 #ifdef RT_USE_LINUX_HRTIMER
    100     struct hrtimer          LnxTimer;
    101 #else
    102     struct timer_list       LnxTimer;
    103     /** The start of the current run (ns).
    104      * This is used to calculate when the timer ought to fire the next time. */
    105     uint64_t                u64StartTS;
    106     /** The start of the current run (ns).
    107      * This is used to calculate when the timer ought to fire the next time. */
    108     uint64_t                u64NextTS;
    109 #endif
    110     /** The current tick number (since u64StartTS). */
     114    /** Timer specific data.  */
     115    union
     116    {
     117#if defined(RTTIMER_LINUX_WITH_HRTIMER)
     118        /** High resolution timer. */
     119        struct
     120        {
     121            /** The linux timer structure. */
     122            struct hrtimer          LnxTimer;
     123        } Hr;
     124#endif
     125#ifndef RTTIMER_LINUX_ONLY_HRTIMER
     126        /** Standard timer. */
     127        struct
     128        {
     129            /** The linux timer structure. */
     130            struct timer_list       LnxTimer;
     131            /** The start of the current run (ns).
     132             * This is used to calculate when the timer ought to fire the next time. */
     133            uint64_t                u64StartTS;
     134            /** The start of the current run (ns).
     135             * This is used to calculate when the timer ought to fire the next time. */
     136            uint64_t                u64NextTS;
     137            /** The u64NextTS in jiffies. */
     138            unsigned long           ulNextJiffies;
     139        } Std;
     140#endif
     141    } u;
     142    /** The current tick number (since u.Std.u64StartTS). */
    111143    uint64_t                iTick;
    112144    /** Pointer to the parent timer. */
    113145    PRTTIMER                pParent;
    114 #ifndef RT_USE_LINUX_HRTIMER
    115     /** The u64NextTS in jiffies. */
    116     unsigned long           ulNextJiffies;
    117 #endif
    118146    /** The current sub-timer state. */
    119147    RTTIMERLNXSTATE volatile enmState;
     
    121149/** Pointer to a linux sub-timer. */
    122150typedef RTTIMERLNXSUBTIMER *PRTTIMERLNXSUBTIMER;
    123 AssertCompileMemberOffset(RTTIMERLNXSUBTIMER, LnxTimer, 0);
    124151
    125152
     
    144171    bool                    fAllCpus;
    145172#endif /* else: All -> specific on non-SMP kernels */
    146     /** The CPU it must run on if fSpecificCpu is set. */
     173    /** Whether it is a high resolution timer or a standard one. */
     174    bool                    fHighRes;
     175    /** The id of the CPU it must run on if fSpecificCpu is set. */
    147176    RTCPUID                 idCpu;
    148177    /** The number of CPUs this timer should run on. */
     
    153182    void                   *pvUser;
    154183    /** The timer interval. 0 if one-shot. */
    155     uint64_t                u64NanoInterval;
    156 #ifndef RT_USE_LINUX_HRTIMER
     184    uint64_t volatile       u64NanoInterval;
     185#ifndef RTTIMER_LINUX_ONLY_HRTIMER
    157186    /** This is set to the number of jiffies between ticks if the interval is
    158187     * an exact number of jiffies. */
     
    210239}
    211240
    212 
    213 #ifdef RT_USE_LINUX_HRTIMER
     241#ifdef RTTIMER_LINUX_WITH_HRTIMER
     242
    214243/**
    215244 * Converts a nano second time stamp to ktime_t.
     
    239268}
    240269
    241 #else /* ! RT_USE_LINUX_HRTIMER */
    242 
     270#endif /* RTTIMER_LINUX_WITH_HRTIMER */
     271
     272#ifndef RTTIMER_LINUX_ONLY_HRTIMER
    243273/**
    244274 * Converts a nano second interval to jiffies.
     
    258288    return (cNanoSecs + (TICK_NSEC-1)) / TICK_NSEC;
    259289}
    260 #endif /* ! RT_USE_LINUX_HRTIMER */
     290#endif /* !RTTIMER_LINUX_ONLY_HRTIMER */
    261291
    262292
     
    269299 * @param   fPinned     true = timer pinned to a specific CPU,
    270300 *                      false = timer can migrate between CPUs
    271  */
    272 static void rtTimerLnxStartSubTimer(PRTTIMERLNXSUBTIMER pSubTimer, uint64_t u64Now, uint64_t u64First, bool fPinned)
     301 * @param   fHighRes    Whether the user requested a high resolution timer or not.
     302 */
     303static void rtTimerLnxStartSubTimer(PRTTIMERLNXSUBTIMER pSubTimer, uint64_t u64Now, uint64_t u64First,
     304                                    bool fPinned, bool fHighRes)
    273305{
    274306    /*
     
    276308     */
    277309    uint64_t u64NextTS = u64Now + u64First;
    278 #ifndef RT_USE_LINUX_HRTIMER
    279     pSubTimer->u64StartTS = u64NextTS;
    280     pSubTimer->u64NextTS = u64NextTS;
     310#ifndef RTTIMER_LINUX_ONLY_HRTIMER
     311    if (fHighRes)
     312    {
     313        pSubTimer->u.Std.u64StartTS = u64NextTS;
     314        pSubTimer->u.Std.u64NextTS  = u64NextTS;
     315    }
    281316#endif
    282317
    283318    pSubTimer->iTick = 0;
    284319
    285 #ifdef RT_USE_LINUX_HRTIMER
    286     hrtimer_start(&pSubTimer->LnxTimer, rtTimerLnxNanoToKt(u64NextTS),
    287                   fPinned ? HRTIMER_MODE_ABS_PINNED : HRTIMER_MODE_ABS);
    288 #else
     320#ifdef RTTIMER_LINUX_WITH_HRTIMER
     321# ifndef RTTIMER_LINUX_ONLY_HRTIMER
     322    if (fHighRes)
     323# endif
     324        hrtimer_start(&pSubTimer->u.Hr.LnxTimer, rtTimerLnxNanoToKt(u64NextTS),
     325                      fPinned ? HRTIMER_MODE_ABS_PINNED : HRTIMER_MODE_ABS);
     326# ifndef RTTIMER_LINUX_ONLY_HRTIMER
     327    else
     328# endif
     329#endif
     330#ifndef RTTIMER_LINUX_ONLY_HRTIMER
    289331    {
    290332        unsigned long cJiffies = !u64First ? 0 : rtTimerLnxNanoToJiffies(u64First);
    291         pSubTimer->ulNextJiffies = jiffies + cJiffies;
     333        pSubTimer->u.Std.ulNextJiffies = jiffies + cJiffies;
    292334# ifdef CONFIG_SMP
    293335        if (fPinned)
    294             mod_timer_pinned(&pSubTimer->LnxTimer, pSubTimer->ulNextJiffies);
     336            mod_timer_pinned(&pSubTimer->u.Std.LnxTimer, pSubTimer->u.Std.ulNextJiffies);
    295337        else
    296338# endif
    297             mod_timer(&pSubTimer->LnxTimer, pSubTimer->ulNextJiffies);
     339            mod_timer(&pSubTimer->u.Std.LnxTimer, pSubTimer->u.Std.ulNextJiffies);
    298340    }
    299341#endif
     
    310352static void rtTimerLnxStopSubTimer(PRTTIMERLNXSUBTIMER pSubTimer)
    311353{
    312 #ifdef RT_USE_LINUX_HRTIMER
    313     hrtimer_cancel(&pSubTimer->LnxTimer);
    314 #else
    315     if (timer_pending(&pSubTimer->LnxTimer))
    316         del_timer_sync(&pSubTimer->LnxTimer);
     354#ifdef RTTIMER_LINUX_WITH_HRTIMER
     355# ifndef RTTIMER_LINUX_ONLY_HRTIMER
     356    if (pSubTimer->pParent->fHighRes)
     357# endif
     358        hrtimer_cancel(&pSubTimer->u.Hr.LnxTimer);
     359# ifndef RTTIMER_LINUX_ONLY_HRTIMER
     360    else
     361# endif
     362#endif
     363# ifndef RTTIMER_LINUX_ONLY_HRTIMER
     364    {
     365        if (timer_pending(&pSubTimer->u.Std.LnxTimer))
     366            del_timer_sync(&pSubTimer->u.Std.LnxTimer);
     367    }
    317368#endif
    318369
     
    321372
    322373
    323 #ifdef RT_USE_LINUX_HRTIMER
    324 /**
    325  * Timer callback function.
    326  * @returns HRTIMER_NORESTART or HRTIMER_RESTART depending on whether it's a one-shot or interval timer.
     374#ifdef RTTIMER_LINUX_WITH_HRTIMER
     375/**
     376 * Timer callback function for high resolution timers.
     377 *
     378 * @returns HRTIMER_NORESTART or HRTIMER_RESTART depending on whether it's a
     379 *          one-shot or interval timer.
    327380 * @param   pHrTimer    Pointer to the sub-timer structure.
    328381 */
    329 static enum hrtimer_restart rtTimerLinuxCallback(struct hrtimer *pHrTimer)
    330 #else
    331 /**
    332  * Timer callback function.
    333  * @param   ulUser      Address of the sub-timer structure.
    334  */
    335 static void rtTimerLinuxCallback(unsigned long ulUser)
    336 #endif
    337 {
    338 #ifdef RT_USE_LINUX_HRTIMER
    339     enum hrtimer_restart rc;
    340     PRTTIMERLNXSUBTIMER pSubTimer = (PRTTIMERLNXSUBTIMER)pHrTimer;
    341 #else
    342     PRTTIMERLNXSUBTIMER pSubTimer = (PRTTIMERLNXSUBTIMER)ulUser;
    343 #endif
    344     PRTTIMER pTimer = pSubTimer->pParent;
     382static enum hrtimer_restart rtTimerLinuxHrCallback(struct hrtimer *pHrTimer)
     383{
     384    PRTTIMERLNXSUBTIMER     pSubTimer = RT_FROM_MEMBER(pHrTimer, RTTIMERLNXSUBTIMER, u.Hr.LnxTimer);
     385    PRTTIMER                pTimer    = pSubTimer->pParent;
     386    enum hrtimer_restart    rc;
    345387
    346388    /*
     
    359401    {
    360402        rtTimerLnxCmpXchgState(&pSubTimer->enmState, RTTIMERLNXSTATE_STOPPED, RTTIMERLNXSTATE_ACTIVE);
    361 # ifdef RT_USE_LINUX_HRTIMER
    362403        rc = HRTIMER_NORESTART;
    363 # endif
    364404    }
    365405    else if (!pTimer->u64NanoInterval)
     
    371411            ASMAtomicWriteBool(&pTimer->fSuspended, true);
    372412        rtTimerLnxCmpXchgState(&pSubTimer->enmState, RTTIMERLNXSTATE_STOPPED, RTTIMERLNXSTATE_ACTIVE);
    373 #ifdef RT_USE_LINUX_HRTIMER
    374413        rc = HRTIMER_NORESTART;
    375 #else
    376         /* detached before we're called, nothing to do for this case. */
    377 #endif
    378 
    379414        pTimer->pfnTimer(pTimer, pTimer->pvUser, ++pSubTimer->iTick);
    380415    }
    381416    else
    382417    {
     418        /*
     419         * Run the timer.  Update the timer after calling the method.
     420         */
    383421        const uint64_t iTick = ++pSubTimer->iTick;
    384 
    385 #ifdef RT_USE_LINUX_HRTIMER
    386         hrtimer_add_expires_ns(&pSubTimer->LnxTimer, pTimer->u64NanoInterval);
    387         rc = HRTIMER_RESTART;
    388 #else
    389         const uint64_t u64NanoTS = RTTimeNanoTS();
    390 
     422        pTimer->pfnTimer(pTimer, pTimer->pvUser, iTick);
     423
     424        /** @todo Check reference counting wrt. RTTimerDestroy from the
     425         *        callback? */
     426        if (   pSubTimer->enmState == RTTIMERLNXSTATE_ACTIVE
     427            || pSubTimer->enmState == RTTIMERLNXSTATE_MP_STARTING)
     428        {
     429            hrtimer_add_expires_ns(&pSubTimer->u.Hr.LnxTimer, ASMAtomicReadU64(&pTimer->u64NanoInterval));
     430            rc = HRTIMER_RESTART;
     431        }
     432        else
     433            rc = HRTIMER_NORESTART;
     434    }
     435
     436    return rc;
     437}
     438#endif /* RTTIMER_LINUX_ONLY_HRTIMER */
     439
     440
     441#ifndef RTTIMER_LINUX_ONLY_HRTIMER
     442/**
     443 * Timer callback function for standard timers.
     444 *
     445 * @param   ulUser      Address of the sub-timer structure.
     446 */
     447static void rtTimerLinuxStdCallback(unsigned long ulUser)
     448{
     449    PRTTIMERLNXSUBTIMER pSubTimer = (PRTTIMERLNXSUBTIMER)ulUser;
     450    PRTTIMER            pTimer    = pSubTimer->pParent;
     451
     452    /*
     453     * Don't call the handler if the timer has been suspended.
     454     * Also, when running on all CPUS, make sure we don't call out twice
     455     * on a CPU because of timer migration.
     456     *
     457     * For the specific cpu case, we're just ignoring timer migration for now... (bad)
     458     */
     459    if (    ASMAtomicUoReadBool(&pTimer->fSuspended)
     460#ifdef CONFIG_SMP
     461        ||  (   pTimer->fAllCpus
     462             && (RTCPUID)(pSubTimer - &pTimer->aSubTimers[0]) != RTMpCpuId())
     463#endif
     464       )
     465        rtTimerLnxCmpXchgState(&pSubTimer->enmState, RTTIMERLNXSTATE_STOPPED, RTTIMERLNXSTATE_ACTIVE);
     466    else if (!pTimer->u64NanoInterval)
     467    {
     468        /*
     469         * One shot timer, stop it before dispatching it.
     470         */
     471        if (pTimer->cCpus == 1)
     472            ASMAtomicWriteBool(&pTimer->fSuspended, true);
     473        rtTimerLnxCmpXchgState(&pSubTimer->enmState, RTTIMERLNXSTATE_STOPPED, RTTIMERLNXSTATE_ACTIVE);
     474        pTimer->pfnTimer(pTimer, pTimer->pvUser, ++pSubTimer->iTick);
     475    }
     476    else
     477    {
    391478        /*
    392479         * Interval timer, calculate the next timeout and re-arm it.
    393480         *
    394          * The first time around, we'll re-adjust the u64StartTS to
     481         * The first time around, we'll re-adjust the u.Std.u64StartTS to
    395482         * try prevent some jittering if we were started at a bad time.
    396483         * This may of course backfire with highres timers...
     484         *
     485         * Note! u64NanoInterval won't change for standard timers.
    397486         */
     487        const uint64_t iTick            = ++pSubTimer->iTick;
     488        const uint64_t u64NanoInterval  = pTimer->u64NanoInterval;
     489        const uint64_t u64NanoTS        = RTTimeNanoTS();
     490
    398491        if (RT_UNLIKELY(iTick == 1))
    399492        {
    400             pSubTimer->u64StartTS = pSubTimer->u64NextTS = u64NanoTS;
    401             pSubTimer->ulNextJiffies = jiffies;
     493            pSubTimer->u.Std.u64StartTS    = u64NanoTS;
     494            pSubTimer->u.Std.u64NextTS     = u64NanoTS;
     495            pSubTimer->u.Std.ulNextJiffies = jiffies;
    402496        }
    403497
    404         pSubTimer->u64NextTS += pTimer->u64NanoInterval;
     498        pSubTimer->u.Std.u64NextTS += u64NanoInterval;
    405499        if (pTimer->cJiffies)
    406500        {
    407             pSubTimer->ulNextJiffies += pTimer->cJiffies;
     501            pSubTimer->u.Std.ulNextJiffies += pTimer->cJiffies;
    408502            /* Prevent overflows when the jiffies counter wraps around.
    409503             * Special thanks to Ken Preslan for helping debugging! */
    410             while (time_before(pSubTimer->ulNextJiffies, jiffies))
     504            while (time_before(pSubTimer->u.Std.ulNextJiffies, jiffies))
    411505            {
    412                 pSubTimer->ulNextJiffies += pTimer->cJiffies;
    413                 pSubTimer->u64NextTS += pTimer->u64NanoInterval;
     506                pSubTimer->u.Std.ulNextJiffies += pTimer->cJiffies;
     507                pSubTimer->u.Std.u64NextTS += u64NanoInterval;
    414508            }
    415509        }
    416510        else
    417511        {
    418             while (pSubTimer->u64NextTS < u64NanoTS)
    419                 pSubTimer->u64NextTS += pTimer->u64NanoInterval;
    420             pSubTimer->ulNextJiffies = jiffies + rtTimerLnxNanoToJiffies(pSubTimer->u64NextTS - u64NanoTS);
     512            while (pSubTimer->u.Std.u64NextTS < u64NanoTS)
     513                pSubTimer->u.Std.u64NextTS += u64NanoInterval;
     514            pSubTimer->u.Std.ulNextJiffies = jiffies + rtTimerLnxNanoToJiffies(pSubTimer->u.Std.u64NextTS - u64NanoTS);
    421515        }
    422516
    423517# ifdef CONFIG_SMP
    424518        if (pTimer->fSpecificCpu || pTimer->fAllCpus)
    425             mod_timer_pinned(&pSubTimer->LnxTimer, pSubTimer->ulNextJiffies);
     519            mod_timer_pinned(&pSubTimer->u.Std.LnxTimer, pSubTimer->u.Std.ulNextJiffies);
    426520        else
    427521# endif
    428             mod_timer(&pSubTimer->LnxTimer, pSubTimer->ulNextJiffies);
    429 #endif
     522            mod_timer(&pSubTimer->u.Std.LnxTimer, pSubTimer->u.Std.ulNextJiffies);
    430523
    431524        /*
     
    434527        pTimer->pfnTimer(pTimer, pTimer->pvUser, iTick);
    435528    }
    436 
    437 #ifdef RT_USE_LINUX_HRTIMER
    438     return rc;
    439 #endif
    440 }
     529}
     530#endif /* !RTTIMER_LINUX_ONLY_HRTIMER */
     531
    441532
    442533
     
    455546    PRTTIMER pTimer = (PRTTIMER)pvUser1;
    456547    Assert(idCpu < pTimer->cCpus);
    457     rtTimerLnxStartSubTimer(&pTimer->aSubTimers[idCpu], pArgs->u64Now, pArgs->u64First, true /*fPinned*/);
     548    rtTimerLnxStartSubTimer(&pTimer->aSubTimers[idCpu], pArgs->u64Now, pArgs->u64First, true /*fPinned*/, pTimer->fHighRes);
    458549}
    459550
     
    607698            PRTTIMERLNXSUBTIMER pSubTimer = &pTimer->aSubTimers[idCpu];
    608699            if (rtTimerLnxCmpXchgState(&pSubTimer->enmState, RTTIMERLNXSTATE_MP_STARTING, RTTIMERLNXSTATE_STOPPED))
    609                 rtTimerLnxStartSubTimer(pSubTimer, pArgs->u64Now, pArgs->u64First, true /*fPinned*/);
     700                rtTimerLnxStartSubTimer(pSubTimer, pArgs->u64Now, pArgs->u64First, true /*fPinned*/, pTimer->fHighRes);
    610701        }
    611702
     
    660751
    661752                    if (RTMpCpuId() == idCpu)
    662                         rtTimerLnxStartSubTimer(pSubTimer, Args.u64Now, Args.u64First, true /*fPinned*/);
     753                        rtTimerLnxStartSubTimer(pSubTimer, Args.u64Now, Args.u64First, true /*fPinned*/, pTimer->fHighRes);
    663754                    else
    664755                    {
     
    708799    PRTTIMERLINUXSTARTONCPUARGS pArgs = (PRTTIMERLINUXSTARTONCPUARGS)pvUser2;
    709800    PRTTIMER pTimer = (PRTTIMER)pvUser1;
    710     rtTimerLnxStartSubTimer(&pTimer->aSubTimers[0], pArgs->u64Now, pArgs->u64First, true /*fPinned*/);
     801    rtTimerLnxStartSubTimer(&pTimer->aSubTimers[0], pArgs->u64Now, pArgs->u64First, true /*fPinned*/, pTimer->fHighRes);
    711802}
    712803
     
    742833    ASMAtomicWriteBool(&pTimer->fSuspended, false);
    743834    if (!pTimer->fSpecificCpu)
    744         rtTimerLnxStartSubTimer(&pTimer->aSubTimers[0], Args.u64Now, Args.u64First, false /*fPinned*/);
     835    {
     836        rtTimerLnxStartSubTimer(&pTimer->aSubTimers[0], Args.u64Now, Args.u64First, false /*fPinned*/, pTimer->fHighRes);
     837    }
    745838    else
    746839    {
     
    792885
    793886
     887RTDECL(int) RTTimerChangeInterval(PRTTIMER pTimer, uint64_t u64NanoInterval)
     888{
     889    int rc = VINF_SUCCESS;
     890
     891    /*
     892     * Validate.
     893     */
     894    AssertPtrReturn(pTimer, VERR_INVALID_HANDLE);
     895    AssertReturn(pTimer->u32Magic == RTTIMER_MAGIC, VERR_INVALID_HANDLE);
     896    AssertReturn(u64NanoInterval, VERR_INVALID_PARAMETER);
     897
     898    /*
     899     * Make the change.
     900     */
     901#ifdef RTTIMER_LINUX_WITH_HRTIMER
     902# ifndef RTTIMER_LINUX_ONLY_HRTIMER
     903    if (pTimer->fHighRes)
     904# endif
     905        ASMAtomicWriteU64(&pTimer->u64NanoInterval, u64NanoInterval);
     906# ifndef RTTIMER_LINUX_ONLY_HRTIMER
     907    else
     908# endif
     909#endif
     910#ifndef RTTIMER_LINUX_ONLY_HRTIMER
     911        rc = VERR_NOT_SUPPORTED; /** @todo Implement this if needed. */
     912#endif
     913
     914    return rc;
     915}
     916RT_EXPORT_SYMBOL(RTTimerChangeInterval);
     917
     918
    794919RTDECL(int) RTTimerDestroy(PRTTIMER pTimer)
    795920{
     
    836961
    837962
    838 RTDECL(int) RTTimerCreateEx(PRTTIMER *ppTimer, uint64_t u64NanoInterval, unsigned fFlags, PFNRTTIMER pfnTimer, void *pvUser)
    839 {
    840     PRTTIMER pTimer;
    841     RTCPUID  iCpu;
    842     unsigned cCpus;
     963RTDECL(int) RTTimerCreateEx(PRTTIMER *ppTimer, uint64_t u64NanoInterval, uint32_t fFlags, PFNRTTIMER pfnTimer, void *pvUser)
     964{
     965    PRTTIMER    pTimer;
     966    RTCPUID     iCpu;
     967    unsigned    cCpus;
    843968
    844969    *ppTimer = NULL;
     
    851976    if (    (fFlags & RTTIMER_FLAGS_CPU_SPECIFIC)
    852977        &&  (fFlags & RTTIMER_FLAGS_CPU_ALL) != RTTIMER_FLAGS_CPU_ALL
    853         &&  !RTMpIsCpuOnline(fFlags & RTTIMER_FLAGS_CPU_MASK))
    854         return (fFlags & RTTIMER_FLAGS_CPU_MASK) > RTMpGetMaxCpuId()
    855              ? VERR_CPU_NOT_FOUND
    856              : VERR_CPU_OFFLINE;
     978        &&  !RTMpIsCpuPossible(RTMpCpuIdFromSetIndex(fFlags & RTTIMER_FLAGS_CPU_MASK)))
     979        return VERR_CPU_NOT_FOUND;
    857980
    858981    /*
     
    8791002    pTimer->hSpinlock = NIL_RTSPINLOCK;
    8801003    pTimer->fSuspended = true;
     1004    pTimer->fHighRes = !!(fFlags & RTTIMER_FLAGS_HIGH_RES);
    8811005#ifdef CONFIG_SMP
    8821006    pTimer->fSpecificCpu = (fFlags & RTTIMER_FLAGS_CPU_SPECIFIC) && (fFlags & RTTIMER_FLAGS_CPU_ALL) != RTTIMER_FLAGS_CPU_ALL;
    8831007    pTimer->fAllCpus = (fFlags & RTTIMER_FLAGS_CPU_ALL) == RTTIMER_FLAGS_CPU_ALL;
    884     pTimer->idCpu = fFlags & RTTIMER_FLAGS_CPU_MASK;
     1008    pTimer->idCpu = pTimer->fSpecificCpu ? RTMpCpuIdFromSetIndex(fFlags & RTTIMER_FLAGS_CPU_MASK) : NIL_RTCPUID;
    8851009#else
    8861010    pTimer->fSpecificCpu = !!(fFlags & RTTIMER_FLAGS_CPU_SPECIFIC);
     
    8911015    pTimer->pvUser = pvUser;
    8921016    pTimer->u64NanoInterval = u64NanoInterval;
    893 #ifndef RT_USE_LINUX_HRTIMER
     1017#ifndef RTTIMER_LINUX_ONLY_HRTIMER
    8941018    pTimer->cJiffies = u64NanoInterval / RTTimerGetSystemGranularity();
    8951019    if (pTimer->cJiffies * RTTimerGetSystemGranularity() != u64NanoInterval)
     
    8991023    for (iCpu = 0; iCpu < cCpus; iCpu++)
    9001024    {
    901 #ifdef RT_USE_LINUX_HRTIMER
    902         hrtimer_init(&pTimer->aSubTimers[iCpu].LnxTimer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS);
    903         pTimer->aSubTimers[iCpu].LnxTimer.function = rtTimerLinuxCallback;
    904 #else
    905         init_timer(&pTimer->aSubTimers[iCpu].LnxTimer);
    906         pTimer->aSubTimers[iCpu].LnxTimer.data     = (unsigned long)&pTimer->aSubTimers[iCpu];
    907         pTimer->aSubTimers[iCpu].LnxTimer.function = rtTimerLinuxCallback;
    908         pTimer->aSubTimers[iCpu].LnxTimer.expires  = jiffies;
    909         pTimer->aSubTimers[iCpu].u64StartTS = 0;
    910         pTimer->aSubTimers[iCpu].u64NextTS = 0;
     1025#ifdef RTTIMER_LINUX_WITH_HRTIMER
     1026# ifndef RTTIMER_LINUX_ONLY_HRTIMER
     1027        if (pTimer->fHighRes)
     1028# endif
     1029        {
     1030            hrtimer_init(&pTimer->aSubTimers[iCpu].u.Hr.LnxTimer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS);
     1031            pTimer->aSubTimers[iCpu].u.Hr.LnxTimer.function = rtTimerLinuxHrCallback;
     1032        }
     1033# ifndef RTTIMER_LINUX_ONLY_HRTIMER
     1034        else
     1035# endif
     1036#endif
     1037#ifndef RTTIMER_LINUX_ONLY_HRTIMER
     1038        {
     1039            init_timer(&pTimer->aSubTimers[iCpu].u.Std.LnxTimer);
     1040            pTimer->aSubTimers[iCpu].u.Std.LnxTimer.data     = (unsigned long)&pTimer->aSubTimers[iCpu];
     1041            pTimer->aSubTimers[iCpu].u.Std.LnxTimer.function = rtTimerLinuxStdCallback;
     1042            pTimer->aSubTimers[iCpu].u.Std.LnxTimer.expires  = jiffies;
     1043            pTimer->aSubTimers[iCpu].u.Std.u64StartTS = 0;
     1044            pTimer->aSubTimers[iCpu].u.Std.u64NextTS = 0;
     1045        }
    9111046#endif
    9121047        pTimer->aSubTimers[iCpu].iTick = 0;
     
    9451080RTDECL(uint32_t) RTTimerGetSystemGranularity(void)
    9461081{
    947 #ifdef RT_USE_LINUX_HRTIMER
     1082#ifdef RTTIMER_LINUX_ONLY_HRTIMER
     1083    /** @todo Not sure if this is what we want or not... Add new API for
     1084     *        querying the resolution of the high res timers? */
    9481085    struct timespec Ts;
    9491086    int rc = hrtimer_get_res(CLOCK_MONOTONIC, &Ts);
     
    9751112RTDECL(bool) RTTimerCanDoHighResolution(void)
    9761113{
    977 #ifdef RT_USE_LINUX_HRTIMER
     1114#ifdef RTTIMER_LINUX_WITH_HRTIMER
    9781115    return true;
    9791116#else
  • trunk/src/VBox/Runtime/r0drv/nt/timer-r0drv-nt.cpp

    r32504 r32572  
    218218    if (!ASMAtomicUoReadBool(&pTimer->fSuspended))
    219219        return VERR_TIMER_ACTIVE;
     220    if (   pTimer->fSpecificCpu
     221        && !RTMpIsCpuOnline(pTimer->idCpu))
     222        return VERR_CPU_OFFLINE;
    220223
    221224    /*
     
    291294
    292295
     296RTDECL(int) RTTimerChangeInterval(PRTTIMER pTimer, uint64_t u64NanoInterval)
     297{
     298    AssertPtrReturn(pTimer, VERR_INVALID_HANDLE);
     299    AssertReturn(pTimer->u32Magic == RTTIMER_MAGIC, VERR_INVALID_HANDLE);
     300
     301    return VERR_NOT_SUPPORTED;
     302}
     303
     304
    293305RTDECL(int) RTTimerDestroy(PRTTIMER pTimer)
    294306{
     
    300312
    301313    /*
    302      * Invalidate the timer, stop it if it's running and finally                   .
     314     * Invalidate the timer, stop it if it's running and finally
    303315     * free up the memory.
    304316     */
     
    312324
    313325
    314 RTDECL(int) RTTimerCreateEx(PRTTIMER *ppTimer, uint64_t u64NanoInterval, unsigned fFlags, PFNRTTIMER pfnTimer, void *pvUser)
     326RTDECL(int) RTTimerCreateEx(PRTTIMER *ppTimer, uint64_t u64NanoInterval, uint32_t fFlags, PFNRTTIMER pfnTimer, void *pvUser)
    315327{
    316328    *ppTimer = NULL;
     
    323335    if (    (fFlags & RTTIMER_FLAGS_CPU_SPECIFIC)
    324336        &&  (fFlags & RTTIMER_FLAGS_CPU_ALL) != RTTIMER_FLAGS_CPU_ALL
    325         &&  !RTMpIsCpuOnline(fFlags & RTTIMER_FLAGS_CPU_MASK))
    326         return (fFlags & RTTIMER_FLAGS_CPU_MASK) > RTMpGetMaxCpuId()
    327              ? VERR_CPU_NOT_FOUND
    328              : VERR_CPU_OFFLINE;
     337        &&  !RTMpIsCpuPossible(RTMpCpuIdFromSetIndex(fFlags & RTTIMER_FLAGS_CPU_MASK)))
     338        return VERR_CPU_NOT_FOUND;
    329339
    330340    /*
     
    349359    pTimer->fSpecificCpu = (fFlags & RTTIMER_FLAGS_CPU_SPECIFIC) && (fFlags & RTTIMER_FLAGS_CPU_ALL) != RTTIMER_FLAGS_CPU_ALL;
    350360    pTimer->fOmniTimer = (fFlags & RTTIMER_FLAGS_CPU_ALL) == RTTIMER_FLAGS_CPU_ALL;
    351     pTimer->idCpu = fFlags & RTTIMER_FLAGS_CPU_MASK;
     361    pTimer->idCpu = pTimer->fSpecificCpu ? RTMpCpuIdFromSetIndex(fFlags & RTTIMER_FLAGS_CPU_MASK) : NIL_RTCPUID;
    352362    pTimer->cSubTimers = cSubTimers;
    353363    pTimer->pfnTimer = pfnTimer;
     
    362372         * ASSUMES that no cpus will ever go offline.
    363373         */
    364         pTimer->idCpu = NIL_RTCPUID; /* */
     374        pTimer->idCpu = NIL_RTCPUID;
    365375        for (unsigned iCpu = 0; iCpu < cSubTimers; iCpu++)
    366376        {
  • trunk/src/VBox/Runtime/r0drv/os2/timer-r0drv-os2.cpp

    r32504 r32572  
    109109
    110110
    111 RTDECL(int) RTTimerCreateEx(PRTTIMER *ppTimer, uint64_t u64NanoInterval, unsigned fFlags, PFNRTTIMER pfnTimer, void *pvUser)
     111RTDECL(int) RTTimerCreateEx(PRTTIMER *ppTimer, uint64_t u64NanoInterval, uint32_t fFlags, PFNRTTIMER pfnTimer, void *pvUser)
    112112{
    113113    *ppTimer = NULL;
     
    289289
    290290
     291RTDECL(int) RTTimerChangeInterval(PRTTIMER pTimer, uint64_t u64NanoInterval)
     292{
     293    if (!rtTimerIsValid(pTimer))
     294        return VERR_INVALID_HANDLE;
     295
     296    return VERR_NOT_SUPPORTED;
     297}
     298
     299
    291300DECLASM(void) rtTimerOs2Tick(void)
    292301{
  • trunk/src/VBox/Runtime/r0drv/solaris/vbi/timer-r0drv-solaris.c

    r32504 r32572  
    103103
    104104
    105 RTDECL(int) RTTimerCreateEx(PRTTIMER *ppTimer, uint64_t u64NanoInterval, unsigned fFlags, PFNRTTIMER pfnTimer, void *pvUser)
     105RTDECL(int) RTTimerCreateEx(PRTTIMER *ppTimer, uint64_t u64NanoInterval, uint32_t fFlags, PFNRTTIMER pfnTimer, void *pvUser)
    106106{
    107107    RT_ASSERT_PREEMPTIBLE();
     
    118118    if (    (fFlags & RTTIMER_FLAGS_CPU_SPECIFIC)
    119119        &&  (fFlags & RTTIMER_FLAGS_CPU_ALL) != RTTIMER_FLAGS_CPU_ALL
    120         &&  !RTMpIsCpuPossible((fFlags & RTTIMER_FLAGS_CPU_MASK)))
     120        &&  !RTMpIsCpuPossible(RTMpCpuIdFromSetIndex(fFlags & RTTIMER_FLAGS_CPU_MASK)))
    121121        return VERR_CPU_NOT_FOUND;
    122122
     
    143143        pTimer->fAllCpu = false;
    144144        pTimer->fSpecificCpu = true;
    145         pTimer->iCpu = fFlags & RTTIMER_FLAGS_CPU_MASK;
     145        pTimer->iCpu = fFlags & RTTIMER_FLAGS_CPU_MASK; /* ASSUMES: index == cpuid */
    146146    }
    147147    else
     
    237237
    238238
     239RTDECL(int) RTTimerChangeInterval(PRTTIMER pTimer, uint64_t u64NanoInterval)
     240{
     241    RTTIMER_ASSERT_VALID_RET(pTimer);
     242
     243    /** @todo implement me! */
     244
     245    return VERR_NOT_SUPPORTED;
     246}
     247
     248
    239249RTDECL(uint32_t) RTTimerGetSystemGranularity(void)
    240250{
     
    257267RTDECL(bool) RTTimerCanDoHighResolution(void)
    258268{
    259     return true;
    260 }
    261 
     269    /** @todo return true; - when missing bits have been implemented and tested*/
     270    return false;
     271}
     272
  • trunk/src/VBox/Runtime/r3/posix/timer-posix.cpp

    r28800 r32572  
    397397
    398398
    399 RTDECL(int) RTTimerCreateEx(PRTTIMER *ppTimer, uint64_t u64NanoInterval, unsigned fFlags, PFNRTTIMER pfnTimer, void *pvUser)
     399RTDECL(int) RTTimerCreateEx(PRTTIMER *ppTimer, uint64_t u64NanoInterval, uint32_t fFlags, PFNRTTIMER pfnTimer, void *pvUser)
    400400{
    401401    /*
     
    811811}
    812812
     813
     814RTDECL(int) RTTimerChangeInterval(PRTTIMER pTimer, uint64_t u64NanoInterval)
     815{
     816    AssertPtrReturn(pTimer, VERR_INVALID_POINTER);
     817    AssertReturn(pTimer->u32Magic == RTTIMER_MAGIC, VERR_INVALID_MAGIC);
     818    return VERR_NOT_SUPPORTED;
     819}
     820
  • trunk/src/VBox/VMM/VMMAll/TMAll.cpp

    r32489 r32572  
    23742374    /* Fudge factor. */
    23752375    /** @todo make this configurable. */
     2376#if 0 /* what's wrong with this expression? I end up with uHz = 0 after this multiplication... */
    23762377    uHz *= 110 + pVCpu->idCpu == pVM->tm.s.idTimerCpu;
     2378#else
     2379    if (pVCpu->idCpu == pVM->tm.s.idTimerCpu)
     2380        uHz *= 111;
     2381    else
     2382        uHz *= 110;
     2383#endif
    23772384    uHz /= 100;
    23782385
     2386    //LogAlways(("TMCalcHostTimerFrequency->%u\n", uHz));
    23792387    return uHz;
    23802388}
  • trunk/src/VBox/VMM/VMMR0/GVMMR0.cpp

    r32489 r32572  
    5757#include <iprt/memobj.h>
    5858#include <iprt/mp.h>
     59#include <iprt/cpuset.h>
     60#include <iprt/spinlock.h>
     61#include <iprt/timer.h>
     62
     63
     64/*******************************************************************************
     65*   Defined Constants And Macros                                               *
     66*******************************************************************************/
     67#ifdef DOXYGEN_RUNNING
     68/** Define this to enable the periodic preemption timer. */
     69# define GVMM_SCHED_WITH_PPT
     70#endif
    5971
    6072
     
    97109# define GVMM_MAX_HANDLES   128
    98110#endif
     111
     112/**
     113 * Per host CPU GVMM data.
     114 */
     115typedef struct GVMMHOSTCPU
     116{
     117    /** Magic number (GVMMHOSTCPU_MAGIC). */
     118    uint32_t volatile   u32Magic;
     119    /** The CPU ID. */
     120    RTCPUID             idCpu;
     121    /** The CPU set index. */
     122    uint32_t            idxCpuSet;
     123
     124#ifdef GVMM_SCHED_WITH_PPT
     125    /** Periodic preemption timer data. */
     126    struct
     127    {
     128        /** The handle to the periodic preemption timer. */
     129        PRTTIMER            pTimer;
     130        /** Spinlock protecting the data below. */
     131        RTSPINLOCK          hSpinlock;
     132        /** The smalles Hz that we need to care about. (static) */
     133        uint32_t            uMinHz;
     134        /** The number of ticks between each historization. */
     135        uint32_t            cTicksHistoriziationInterval;
     136        /** The current historization tick (counting up to
     137         * cTicksHistoriziationInterval and then resetting). */
     138        uint32_t            iTickHistorization;
     139        /** The current timer interval.  This is set to 0 when inactive. */
     140        uint32_t            cNsInterval;
     141        /** The current timer frequency.  This is set to 0 when inactive. */
     142        uint32_t            uTimerHz;
     143        /** The current max frequency reported by the EMTs.
     144         * This gets historicize and reset by the timer callback.  This is
     145         * read without holding the spinlock, so needs atomic updating. */
     146        uint32_t volatile   uDesiredHz;
     147        /** Whether the timer was started or not. */
     148        bool volatile       fStarted;
     149        /** Set if we're starting timer. */
     150        bool volatile       fStarting;
     151        /** The index of the next history entry (mod it). */
     152        uint32_t            iHzHistory;
     153        /** Hitoricized uDesiredHz values.  The array wraps around, new entries
     154         * are added at iHzHistory. This is updated approximately every
     155         * GVMMHOSTCPU_PPT_HIST_INTERVAL_NS by the timer callback. */
     156        uint32_t            aHzHistory[32];
     157        /** Statistics counter for recording the number of interval changes. */
     158        uint64_t            cChanges;
     159        /** Statistics counter for recording the number of timer starts. */
     160        uint64_t            cStarts;
     161    } Ppt;
     162#endif /* GVMM_SCHED_WITH_PPT */
     163
     164} GVMMHOSTCPU;
     165/** Pointer to the per host CPU GVMM data. */
     166typedef GVMMHOSTCPU *PGVMMHOSTCPU;
     167/** The GVMMHOSTCPU::u32Magic value (Petra, Tanya & Rachel Haden). */
     168#define GVMMHOSTCPU_MAGIC   UINT32_C(0x19711011)
     169/** The interval on history entry should cover (approximately) give in
     170 *  nanoseconds. */
     171#define GVMMHOSTCPU_PPT_HIST_INTERVAL_NS    UINT32_C(20000000)
     172
    99173
    100174/**
     
    148222     */
    149223    uint32_t            nsEarlyWakeUp2;
     224
     225    /** The number of entries in the host CPU array (aHostCpus). */
     226    uint32_t            cHostCpus;
     227    /** Per host CPU data (variable length). */
     228    GVMMHOSTCPU         aHostCpus[1];
    150229} GVMM;
    151230/** Pointer to the GVMM instance data. */
     
    198277static int gvmmR0ByVM(PVM pVM, PGVM *ppGVM, PGVMM *ppGVMM, bool fTakeUsedLock);
    199278static int gvmmR0ByVMAndEMT(PVM pVM, VMCPUID idCpu, PGVM *ppGVM, PGVMM *ppGVMM);
     279#ifdef GVMM_SCHED_WITH_PPT
     280static DECLCALLBACK(void) gvmmR0SchedPeriodicPreemptionTimerCallback(PRTTIMER pTimer, void *pvUser, uint64_t iTick);
     281#endif
    200282
    201283
     
    214296     * Allocate and initialize the instance data.
    215297     */
    216     PGVMM pGVMM = (PGVMM)RTMemAllocZ(sizeof(*pGVMM));
     298    uint32_t cHostCpus = RTMpGetArraySize();
     299    AssertMsgReturn(cHostCpus > 0 && cHostCpus < _64K, ("%d", (int)cHostCpus), VERR_INTERNAL_ERROR_2);
     300
     301    PGVMM pGVMM = (PGVMM)RTMemAllocZ(RT_UOFFSETOF(GVMM, aHostCpus[cHostCpus]));
    217302    if (!pGVMM)
    218303        return VERR_NO_MEMORY;
     
    250335            pGVMM->nsEarlyWakeUp2    =  50000 /* ns (0.050 ms) */;
    251336
    252             g_pGVMM = pGVMM;
    253             LogFlow(("GVMMR0Init: pGVMM=%p\n", pGVMM));
    254             return VINF_SUCCESS;
    255         }
    256 
     337            /* The host CPU data. */
     338            pGVMM->cHostCpus = cHostCpus;
     339            uint32_t    iCpu = cHostCpus;
     340            RTCPUSET    PossibleSet;
     341            RTMpGetSet(&PossibleSet);
     342            while (iCpu-- > 0)
     343            {
     344                pGVMM->aHostCpus[iCpu].idxCpuSet        = iCpu;
     345#ifdef GVMM_SCHED_WITH_PPT
     346                pGVMM->aHostCpus[iCpu].Ppt.pTimer       = NULL;
     347                pGVMM->aHostCpus[iCpu].Ppt.hSpinlock    = NIL_RTSPINLOCK;
     348                pGVMM->aHostCpus[iCpu].Ppt.uMinHz       = 5; /** @todo Add some API which figures this one out. (not *that* important) */
     349                pGVMM->aHostCpus[iCpu].Ppt.cTicksHistoriziationInterval = 1;
     350                //pGVMM->aHostCpus[iCpu].Ppt.iTickHistorization           = 0;
     351                //pGVMM->aHostCpus[iCpu].Ppt.cNsInterval  = 0;
     352                //pGVMM->aHostCpus[iCpu].Ppt.uTimerHz     = 0;
     353                //pGVMM->aHostCpus[iCpu].Ppt.uDesiredHz   = 0;
     354                //pGVMM->aHostCpus[iCpu].Ppt.fStarted     = false;
     355                //pGVMM->aHostCpus[iCpu].Ppt.fStarting    = false;
     356                //pGVMM->aHostCpus[iCpu].Ppt.iHzHistory   = 0;
     357                //pGVMM->aHostCpus[iCpu].Ppt.aHzHistory   = {0};
     358#endif
     359
     360                if (RTCpuSetIsMember(&PossibleSet, iCpu))
     361                {
     362                    pGVMM->aHostCpus[iCpu].idCpu        = RTMpCpuIdFromSetIndex(iCpu);
     363                    pGVMM->aHostCpus[iCpu].u32Magic     = GVMMHOSTCPU_MAGIC;
     364
     365#ifdef GVMM_SCHED_WITH_PPT
     366                    rc = RTTimerCreateEx(&pGVMM->aHostCpus[iCpu].Ppt.pTimer,
     367                                         50*1000*1000 /* whatever */,
     368                                         RTTIMER_FLAGS_CPU(iCpu) | RTTIMER_FLAGS_HIGH_RES,
     369                                         gvmmR0SchedPeriodicPreemptionTimerCallback,
     370                                         &pGVMM->aHostCpus[iCpu]);
     371                    if (RT_SUCCESS(rc))
     372                        rc = RTSpinlockCreate(&pGVMM->aHostCpus[iCpu].Ppt.hSpinlock);
     373                    if (RT_FAILURE(rc))
     374                    {
     375                        while (iCpu < cHostCpus)
     376                        {
     377                            RTTimerDestroy(pGVMM->aHostCpus[iCpu].Ppt.pTimer);
     378                            RTSpinlockDestroy(pGVMM->aHostCpus[iCpu].Ppt.hSpinlock);
     379                            pGVMM->aHostCpus[iCpu].Ppt.hSpinlock = NIL_RTSPINLOCK;
     380                            iCpu++;
     381                        }
     382                        break;
     383                    }
     384#endif
     385                }
     386                else
     387                {
     388                    pGVMM->aHostCpus[iCpu].idCpu        = NIL_RTCPUID;
     389                    pGVMM->aHostCpus[iCpu].u32Magic     = 0;
     390                }
     391            }
     392            if (RT_SUCCESS(rc))
     393            {
     394                g_pGVMM = pGVMM;
     395                LogFlow(("GVMMR0Init: pGVMM=%p cHostCpus=%u\n", pGVMM, cHostCpus));
     396                return VINF_SUCCESS;
     397            }
     398
     399            /* bail out. */
     400            RTSemFastMutexDestroy(pGVMM->UsedLock);
     401            pGVMM->UsedLock = NIL_RTSEMFASTMUTEX;
     402        }
    257403        RTSemFastMutexDestroy(pGVMM->CreateDestroyLock);
     404        pGVMM->CreateDestroyLock = NIL_RTSEMFASTMUTEX;
    258405    }
    259406
     
    282429    }
    283430
    284     pGVMM->u32Magic++;
    285 
     431    /*
     432     * First of all, stop all active timers.
     433     */
     434    uint32_t cActiveTimers = 0;
     435    uint32_t iCpu = pGVMM->cHostCpus;
     436    while (iCpu-- > 0)
     437    {
     438        ASMAtomicWriteU32(&pGVMM->aHostCpus[iCpu].u32Magic, ~GVMMHOSTCPU_MAGIC);
     439#ifdef GVMM_SCHED_WITH_PPT
     440        if (    pGVMM->aHostCpus[iCpu].Ppt.pTimer != NULL
     441            &&  RT_SUCCESS(RTTimerStop(pGVMM->aHostCpus[iCpu].Ppt.pTimer)))
     442            cActiveTimers++;
     443#endif
     444    }
     445    if (cActiveTimers)
     446        RTThreadSleep(1); /* fudge */
     447
     448    /*
     449     * Invalidate the and free resources.
     450     */
     451    pGVMM->u32Magic = ~GVMM_MAGIC;
    286452    RTSemFastMutexDestroy(pGVMM->UsedLock);
    287453    pGVMM->UsedLock = NIL_RTSEMFASTMUTEX;
     
    295461        pGVMM->iUsedHead = 0;
    296462    }
     463
     464#ifdef GVMM_SCHED_WITH_PPT
     465    iCpu = pGVMM->cHostCpus;
     466    while (iCpu-- > 0)
     467    {
     468        RTTimerDestroy(pGVMM->aHostCpus[iCpu].Ppt.pTimer);
     469        pGVMM->aHostCpus[iCpu].Ppt.pTimer = NULL;
     470        RTSpinlockDestroy(pGVMM->aHostCpus[iCpu].Ppt.hSpinlock);
     471        pGVMM->aHostCpus[iCpu].Ppt.hSpinlock = NIL_RTSPINLOCK;
     472    }
     473#endif
    297474
    298475    RTMemFree(pGVMM);
     
    18862063
    18872064
     2065#ifdef GVMM_SCHED_WITH_PPT
     2066/**
     2067 * Timer callback for the periodic preemption timer.
     2068 *
     2069 * @param   pTimer      The timer handle.
     2070 * @param   pvUser      Pointer to the per cpu structure.
     2071 * @param   iTick       The current tick.
     2072 */
     2073static DECLCALLBACK(void) gvmmR0SchedPeriodicPreemptionTimerCallback(PRTTIMER pTimer, void *pvUser, uint64_t iTick)
     2074{
     2075    PGVMMHOSTCPU pCpu = (PGVMMHOSTCPU)pvUser;
     2076
     2077    /*
     2078     * Termination check
     2079     */
     2080    if (pCpu->u32Magic != GVMMHOSTCPU_MAGIC)
     2081        return;
     2082
     2083    /*
     2084     * Do the house keeping.
     2085     */
     2086    RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
     2087    RTSpinlockAcquireNoInts(pCpu->Ppt.hSpinlock, &Tmp);
     2088
     2089    if (++pCpu->Ppt.iTickHistorization >= pCpu->Ppt.cTicksHistoriziationInterval)
     2090    {
     2091        /*
     2092         * Historicize the max frequency.
     2093         */
     2094        uint32_t iHzHistory = ++pCpu->Ppt.iHzHistory % RT_ELEMENTS(pCpu->Ppt.aHzHistory);
     2095        pCpu->Ppt.aHzHistory[iHzHistory] = pCpu->Ppt.uDesiredHz;
     2096        pCpu->Ppt.iTickHistorization = 0;
     2097        pCpu->Ppt.uDesiredHz         = 0;
     2098
     2099        /*
     2100         * Check if the current timer frequency.
     2101         */
     2102        uint32_t uHistMaxHz = 0;
     2103        for (uint32_t i = 0; i < RT_ELEMENTS(pCpu->Ppt.aHzHistory); i++)
     2104            if (pCpu->Ppt.aHzHistory[i] > uHistMaxHz)
     2105                uHistMaxHz = pCpu->Ppt.aHzHistory[i];
     2106        if (uHistMaxHz == pCpu->Ppt.uTimerHz)
     2107            RTSpinlockReleaseNoInts(pCpu->Ppt.hSpinlock, &Tmp);
     2108        else if (uHistMaxHz)
     2109        {
     2110            /*
     2111             * Reprogram it.
     2112             */
     2113            pCpu->Ppt.cChanges++;
     2114            pCpu->Ppt.iTickHistorization    = 0;
     2115            pCpu->Ppt.uTimerHz              = uHistMaxHz;
     2116            uint32_t const cNsInterval      = UINT32_C(1000000000) / uHistMaxHz;
     2117            pCpu->Ppt.cNsInterval           = cNsInterval;
     2118            if (cNsInterval < GVMMHOSTCPU_PPT_HIST_INTERVAL_NS)
     2119                pCpu->Ppt.cTicksHistoriziationInterval = (  GVMMHOSTCPU_PPT_HIST_INTERVAL_NS
     2120                                                          + GVMMHOSTCPU_PPT_HIST_INTERVAL_NS / 2 - 1)
     2121                                                       / cNsInterval;
     2122            else
     2123                pCpu->Ppt.cTicksHistoriziationInterval = 1;
     2124            RTSpinlockReleaseNoInts(pCpu->Ppt.hSpinlock, &Tmp);
     2125
     2126            /*SUPR0Printf("Cpu%u: change to %u Hz / %u ns\n", pCpu->idxCpuSet, uHistMaxHz, cNsInterval);*/
     2127            RTTimerChangeInterval(pTimer, cNsInterval);
     2128        }
     2129        else
     2130        {
     2131            /*
     2132             * Stop it.
     2133             */
     2134            pCpu->Ppt.fStarted    = false;
     2135            pCpu->Ppt.uTimerHz    = 0;
     2136            pCpu->Ppt.cNsInterval = 0;
     2137            RTSpinlockReleaseNoInts(pCpu->Ppt.hSpinlock, &Tmp);
     2138
     2139            /*SUPR0Printf("Cpu%u: stopping (%u Hz)\n", pCpu->idxCpuSet, uHistMaxHz);*/
     2140            RTTimerStop(pTimer);
     2141        }
     2142    }
     2143    else
     2144        RTSpinlockReleaseNoInts(pCpu->Ppt.hSpinlock, &Tmp);
     2145}
     2146#endif /* GVMM_SCHED_WITH_PPT */
     2147
    18882148
    18892149/**
     
    18912151 *
    18922152 * The caller must have disabled preemption!
     2153 * The caller must check that the host can do high resolution timers.
    18932154 *
    18942155 * @param   pVM         The VM handle.
     
    18982159GVMMR0DECL(void) GVMMR0SchedUpdatePeriodicPreemptionTimer(PVM pVM, RTCPUID idHostCpu, uint32_t uHz)
    18992160{
    1900 
     2161#ifdef GVMM_SCHED_WITH_PPT
     2162    Assert(!RTThreadPreemptIsEnabled(NIL_RTTHREAD));
     2163    Assert(RTTimerCanDoHighResolution());
     2164
     2165    /*
     2166     * Resolve the per CPU data.
     2167     */
     2168    uint32_t    iCpu  = RTMpCpuIdToSetIndex(idHostCpu);
     2169    PGVMM       pGVMM = g_pGVMM;
     2170    if (   !VALID_PTR(pGVMM)
     2171        || pGVMM->u32Magic != GVMM_MAGIC)
     2172        return;
     2173    AssertMsgReturnVoid(iCpu < pGVMM->cHostCpus, ("iCpu=%d cHostCpus=%d\n", iCpu, pGVMM->cHostCpus));
     2174    PGVMMHOSTCPU pCpu = &pGVMM->aHostCpus[iCpu];
     2175    AssertMsgReturnVoid(   pCpu->u32Magic == GVMMHOSTCPU_MAGIC
     2176                        && pCpu->idCpu    == idHostCpu,
     2177                        ("u32Magic=%#x idCpu=% idHostCpu=%d\n", pCpu->u32Magic, pCpu->idCpu, idHostCpu));
     2178
     2179    /*
     2180     * Check whether we need to do anything about the timer.
     2181     * We have to be a little bit careful since we might be race the timer
     2182     * callback here.
     2183     */
     2184    if (uHz > 20000)
     2185        uHz = 20000;
     2186    if (RT_UNLIKELY(   uHz > ASMAtomicReadU32(&pCpu->Ppt.uDesiredHz)
     2187                    && uHz >= pCpu->Ppt.uMinHz
     2188                    && !pCpu->Ppt.fStarting /* solaris paranoia */))
     2189    {
     2190        RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
     2191        RTSpinlockAcquireNoInts(pCpu->Ppt.hSpinlock, &Tmp);
     2192
     2193        pCpu->Ppt.uDesiredHz = uHz;
     2194        uint32_t cNsInterval = 0;
     2195        if (!pCpu->Ppt.fStarted)
     2196        {
     2197            pCpu->Ppt.cStarts++;
     2198            pCpu->Ppt.fStarted              = true;
     2199            pCpu->Ppt.fStarting             = true;
     2200            pCpu->Ppt.iTickHistorization    = 0;
     2201            pCpu->Ppt.uTimerHz              = uHz;
     2202            pCpu->Ppt.cNsInterval           = cNsInterval = UINT32_C(1000000000) / uHz;
     2203            if (cNsInterval < GVMMHOSTCPU_PPT_HIST_INTERVAL_NS)
     2204                pCpu->Ppt.cTicksHistoriziationInterval = (  GVMMHOSTCPU_PPT_HIST_INTERVAL_NS
     2205                                                          + GVMMHOSTCPU_PPT_HIST_INTERVAL_NS / 2 - 1)
     2206                                                       / cNsInterval;
     2207            else
     2208                pCpu->Ppt.cTicksHistoriziationInterval = 1;
     2209        }
     2210
     2211        RTSpinlockReleaseNoInts(pCpu->Ppt.hSpinlock, &Tmp);
     2212
     2213        if (cNsInterval)
     2214        {
     2215            RTTimerChangeInterval(pCpu->Ppt.pTimer, cNsInterval);
     2216            int rc = RTTimerStart(pCpu->Ppt.pTimer, cNsInterval);
     2217            AssertRC(rc);
     2218
     2219            RTSpinlockAcquireNoInts(pCpu->Ppt.hSpinlock, &Tmp);
     2220            if (RT_FAILURE(rc))
     2221                pCpu->Ppt.fStarted = false;
     2222            pCpu->Ppt.fStarting = false;
     2223            RTSpinlockReleaseNoInts(pCpu->Ppt.hSpinlock, &Tmp);
     2224        }
     2225    }
     2226#endif /* GVMM_SCHED_WITH_PPT */
    19012227}
    19022228
Note: See TracChangeset for help on using the changeset viewer.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette