ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync/* $Id$ */
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync/** @file
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync * IPRT - Timers, Ring-0 Driver, Linux.
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync */
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync/*
caa110e2153c635d3a0910161f3532ace7600bd3vboxsync * Copyright (C) 2006-2014 Oracle Corporation
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync *
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync * available from http://www.virtualbox.org. This file is free software;
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync * you can redistribute it and/or modify it under the terms of the GNU
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync * General Public License (GPL) as published by the Free Software
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync *
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync * The contents of this file may alternatively be used under the terms
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync * of the Common Development and Distribution License Version 1.0
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync * VirtualBox OSE distribution, in which case the provisions of the
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync * CDDL are applicable instead of those of the GPL.
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync *
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync * You may elect to license modified versions of this file under the
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync * terms and conditions of either the GPL or the CDDL or both.
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync */
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync
aa4bcf0a4b2db3ac352b56a291d49cb8d4b66d32vboxsync
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync/*******************************************************************************
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync* Header Files *
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync*******************************************************************************/
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync#include "the-linux-kernel.h"
aa4bcf0a4b2db3ac352b56a291d49cb8d4b66d32vboxsync#include "internal/iprt.h"
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync#include <iprt/timer.h>
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync#include <iprt/time.h>
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync#include <iprt/mp.h>
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync#include <iprt/cpuset.h>
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync#include <iprt/spinlock.h>
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync#include <iprt/err.h>
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync#include <iprt/asm.h>
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync#include <iprt/assert.h>
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync#include <iprt/alloc.h>
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync#include "internal/magics.h"
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsync/** @def RTTIMER_LINUX_WITH_HRTIMER
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsync * Whether to use high resolution timers. */
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsync#if !defined(RTTIMER_LINUX_WITH_HRTIMER) \
d1c36fd86d36726777e3d6f9d040573e0aaf30devboxsync && defined(IPRT_LINUX_HAS_HRTIMER)
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsync# define RTTIMER_LINUX_WITH_HRTIMER
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync#endif
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync
76cb9831bbeaff3bb30068363e35660a776736c4vboxsync#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31)
d68336e34409fd767807d5ef641a305de4d9ee59vboxsync# define mod_timer_pinned mod_timer
d68336e34409fd767807d5ef641a305de4d9ee59vboxsync# define HRTIMER_MODE_ABS_PINNED HRTIMER_MODE_ABS
76cb9831bbeaff3bb30068363e35660a776736c4vboxsync#endif
76cb9831bbeaff3bb30068363e35660a776736c4vboxsync
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync/*******************************************************************************
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync* Structures and Typedefs *
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync*******************************************************************************/
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync/**
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync * Timer state machine.
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync *
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync * This is used to try handle the issues with MP events and
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync * timers that runs on all CPUs. It's relatively nasty :-/
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync */
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsynctypedef enum RTTIMERLNXSTATE
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync{
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync /** Stopped. */
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync RTTIMERLNXSTATE_STOPPED = 0,
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync /** Transient state; next ACTIVE. */
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync RTTIMERLNXSTATE_STARTING,
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync /** Transient state; next ACTIVE. (not really necessary) */
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync RTTIMERLNXSTATE_MP_STARTING,
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync /** Active. */
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync RTTIMERLNXSTATE_ACTIVE,
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync /** Active and in callback; next ACTIVE, STOPPED or CALLBACK_DESTROYING. */
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync RTTIMERLNXSTATE_CALLBACK,
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync /** Stopped while in the callback; next STOPPED. */
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync RTTIMERLNXSTATE_CB_STOPPING,
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync /** Restarted while in the callback; next ACTIVE, STOPPED, DESTROYING. */
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync RTTIMERLNXSTATE_CB_RESTARTING,
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync /** The callback shall destroy the timer; next STOPPED. */
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync RTTIMERLNXSTATE_CB_DESTROYING,
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync /** Transient state; next STOPPED. */
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync RTTIMERLNXSTATE_STOPPING,
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync /** Transient state; next STOPPED. */
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync RTTIMERLNXSTATE_MP_STOPPING,
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync /** The usual 32-bit hack. */
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync RTTIMERLNXSTATE_32BIT_HACK = 0x7fffffff
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync} RTTIMERLNXSTATE;
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync/**
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync * A Linux sub-timer.
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync */
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsynctypedef struct RTTIMERLNXSUBTIMER
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync{
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsync /** Timer specific data. */
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsync union
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsync {
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsync#if defined(RTTIMER_LINUX_WITH_HRTIMER)
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsync /** High resolution timer. */
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsync struct
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsync {
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsync /** The linux timer structure. */
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsync struct hrtimer LnxTimer;
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsync } Hr;
619824b60d668e6e43f385ef78cf06e13d43aab6vboxsync#endif
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsync /** Standard timer. */
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsync struct
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsync {
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsync /** The linux timer structure. */
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsync struct timer_list LnxTimer;
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsync /** The start of the current run (ns).
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsync * This is used to calculate when the timer ought to fire the next time. */
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsync uint64_t u64NextTS;
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsync /** The u64NextTS in jiffies. */
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsync unsigned long ulNextJiffies;
852e87ceabd0234ac0f9e71537c11d08e35f736cvboxsync /** Set when starting or changing the timer so that u64StartTs
852e87ceabd0234ac0f9e71537c11d08e35f736cvboxsync * and u64NextTS gets reinitialized (eliminating some jitter). */
852e87ceabd0234ac0f9e71537c11d08e35f736cvboxsync bool volatile fFirstAfterChg;
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsync } Std;
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsync } u;
852e87ceabd0234ac0f9e71537c11d08e35f736cvboxsync /** The current tick number. */
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync uint64_t iTick;
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync /** Restart the single shot timer at this specific time.
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync * Used when a single shot timer is restarted from the callback. */
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync uint64_t volatile uNsRestartAt;
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync /** Pointer to the parent timer. */
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync PRTTIMER pParent;
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync /** The current sub-timer state. */
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync RTTIMERLNXSTATE volatile enmState;
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync} RTTIMERLNXSUBTIMER;
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync/** Pointer to a linux sub-timer. */
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsynctypedef RTTIMERLNXSUBTIMER *PRTTIMERLNXSUBTIMER;
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync/**
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync * The internal representation of an Linux timer handle.
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync */
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsynctypedef struct RTTIMER
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync{
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync /** Magic.
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync * This is RTTIMER_MAGIC, but changes to something else before the timer
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync * is destroyed to indicate clearly that thread should exit. */
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync uint32_t volatile u32Magic;
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync /** Spinlock synchronizing the fSuspended and MP event handling.
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync * This is NIL_RTSPINLOCK if cCpus == 1. */
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync RTSPINLOCK hSpinlock;
b3109af8dcc2a3da7f424aa05a4e84a64bf1c43fvboxsync /** Flag indicating that the timer is suspended. */
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync bool volatile fSuspended;
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync /** Whether the timer must run on one specific CPU or not. */
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync bool fSpecificCpu;
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync#ifdef CONFIG_SMP
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync /** Whether the timer must run on all CPUs or not. */
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync bool fAllCpus;
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync#endif /* else: All -> specific on non-SMP kernels */
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsync /** Whether it is a high resolution timer or a standard one. */
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsync bool fHighRes;
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsync /** The id of the CPU it must run on if fSpecificCpu is set. */
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync RTCPUID idCpu;
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync /** The number of CPUs this timer should run on. */
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync RTCPUID cCpus;
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync /** Callback. */
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync PFNRTTIMER pfnTimer;
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync /** User argument. */
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync void *pvUser;
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync /** The timer interval. 0 if one-shot. */
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsync uint64_t volatile u64NanoInterval;
4aafb1203580a5c145a7bdae57ebf69a36fa4f01vboxsync /** This is set to the number of jiffies between ticks if the interval is
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync * an exact number of jiffies. (Standard timers only.) */
852e87ceabd0234ac0f9e71537c11d08e35f736cvboxsync unsigned long volatile cJiffies;
852e87ceabd0234ac0f9e71537c11d08e35f736cvboxsync /** The change interval spinlock for standard timers only. */
852e87ceabd0234ac0f9e71537c11d08e35f736cvboxsync spinlock_t ChgIntLock;
10f0e3bfdb61e7bae30a1a1d9c17659a908c3d37vboxsync /** Workqueue item for delayed destruction. */
10f0e3bfdb61e7bae30a1a1d9c17659a908c3d37vboxsync RTR0LNXWORKQUEUEITEM DtorWorkqueueItem;
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync /** Sub-timers.
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync * Normally there is just one, but for RTTIMER_FLAGS_CPU_ALL this will contain
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync * an entry for all possible cpus. In that case the index will be the same as
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync * for the RTCpuSet. */
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync RTTIMERLNXSUBTIMER aSubTimers[1];
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync} RTTIMER;
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync/**
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync * A rtTimerLinuxStartOnCpu and rtTimerLinuxStartOnCpu argument package.
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync */
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsynctypedef struct RTTIMERLINUXSTARTONCPUARGS
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync{
852e87ceabd0234ac0f9e71537c11d08e35f736cvboxsync /** The current time (RTTimeSystemNanoTS). */
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync uint64_t u64Now;
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync /** When to start firing (delta). */
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync uint64_t u64First;
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync} RTTIMERLINUXSTARTONCPUARGS;
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync/** Pointer to a rtTimerLinuxStartOnCpu argument package. */
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsynctypedef RTTIMERLINUXSTARTONCPUARGS *PRTTIMERLINUXSTARTONCPUARGS;
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync/*******************************************************************************
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync* Internal Functions *
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync*******************************************************************************/
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync#ifdef CONFIG_SMP
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsyncstatic DECLCALLBACK(void) rtTimerLinuxMpEvent(RTMPEVENT enmEvent, RTCPUID idCpu, void *pvUser);
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync#endif
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync
9edbe160de7266b3b5d54ccf2f07ed95f9f40c6bvboxsync#if 0
9edbe160de7266b3b5d54ccf2f07ed95f9f40c6bvboxsync#define DEBUG_HACKING
9edbe160de7266b3b5d54ccf2f07ed95f9f40c6bvboxsync#include <iprt/string.h>
9edbe160de7266b3b5d54ccf2f07ed95f9f40c6bvboxsync#include <iprt/asm-amd64-x86.h>
9edbe160de7266b3b5d54ccf2f07ed95f9f40c6bvboxsyncstatic void myLogBackdoorPrintf(const char *pszFormat, ...)
9edbe160de7266b3b5d54ccf2f07ed95f9f40c6bvboxsync{
9edbe160de7266b3b5d54ccf2f07ed95f9f40c6bvboxsync char szTmp[256];
9edbe160de7266b3b5d54ccf2f07ed95f9f40c6bvboxsync va_list args;
9edbe160de7266b3b5d54ccf2f07ed95f9f40c6bvboxsync size_t cb;
9edbe160de7266b3b5d54ccf2f07ed95f9f40c6bvboxsync
9edbe160de7266b3b5d54ccf2f07ed95f9f40c6bvboxsync cb = RTStrPrintf(szTmp, sizeof(szTmp) - 10, "%d: ", RTMpCpuId());
9edbe160de7266b3b5d54ccf2f07ed95f9f40c6bvboxsync va_start(args, pszFormat);
9edbe160de7266b3b5d54ccf2f07ed95f9f40c6bvboxsync cb += RTStrPrintfV(&szTmp[cb], sizeof(szTmp) - cb, pszFormat, args);
9edbe160de7266b3b5d54ccf2f07ed95f9f40c6bvboxsync va_end(args);
9edbe160de7266b3b5d54ccf2f07ed95f9f40c6bvboxsync
9edbe160de7266b3b5d54ccf2f07ed95f9f40c6bvboxsync ASMOutStrU8(0x504, (uint8_t *)&szTmp[0], cb);
9edbe160de7266b3b5d54ccf2f07ed95f9f40c6bvboxsync}
951d1da36c2120dd8bf59a3b57800f8429dcd387vboxsync# define RTAssertMsg1Weak(pszExpr, uLine, pszFile, pszFunction) \
9edbe160de7266b3b5d54ccf2f07ed95f9f40c6bvboxsync myLogBackdoorPrintf("\n!!Guest Assertion failed!!\n%s(%d) %s\n%s\n", uLine, pszFile, pszFunction, (pszExpr))
951d1da36c2120dd8bf59a3b57800f8429dcd387vboxsync# define RTAssertMsg2Weak myLogBackdoorPrintf
951d1da36c2120dd8bf59a3b57800f8429dcd387vboxsync# define RTTIMERLNX_LOG(a) myLogBackdoorPrintf a
9edbe160de7266b3b5d54ccf2f07ed95f9f40c6bvboxsync#else
951d1da36c2120dd8bf59a3b57800f8429dcd387vboxsync# define RTTIMERLNX_LOG(a) do { } while (0)
9edbe160de7266b3b5d54ccf2f07ed95f9f40c6bvboxsync#endif
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync/**
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync * Sets the state.
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync */
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsyncDECLINLINE(void) rtTimerLnxSetState(RTTIMERLNXSTATE volatile *penmState, RTTIMERLNXSTATE enmNewState)
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync{
9edbe160de7266b3b5d54ccf2f07ed95f9f40c6bvboxsync#ifdef DEBUG_HACKING
951d1da36c2120dd8bf59a3b57800f8429dcd387vboxsync RTTIMERLNX_LOG(("set %d -> %d\n", *penmState, enmNewState));
9edbe160de7266b3b5d54ccf2f07ed95f9f40c6bvboxsync#endif
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync ASMAtomicWriteU32((uint32_t volatile *)penmState, enmNewState);
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync}
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync/**
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync * Sets the state if it has a certain value.
0780b79e94db3b60fb4a3057df7c64ba8b1cb75dvboxsync *
0780b79e94db3b60fb4a3057df7c64ba8b1cb75dvboxsync * @return true if xchg was done.
0780b79e94db3b60fb4a3057df7c64ba8b1cb75dvboxsync * @return false if xchg wasn't done.
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync */
9edbe160de7266b3b5d54ccf2f07ed95f9f40c6bvboxsync#ifdef DEBUG_HACKING
9edbe160de7266b3b5d54ccf2f07ed95f9f40c6bvboxsync#define rtTimerLnxCmpXchgState(penmState, enmNewState, enmCurState) rtTimerLnxCmpXchgStateDebug(penmState, enmNewState, enmCurState, __LINE__)
9edbe160de7266b3b5d54ccf2f07ed95f9f40c6bvboxsyncstatic bool rtTimerLnxCmpXchgStateDebug(RTTIMERLNXSTATE volatile *penmState, RTTIMERLNXSTATE enmNewState,
9edbe160de7266b3b5d54ccf2f07ed95f9f40c6bvboxsync RTTIMERLNXSTATE enmCurState, uint32_t uLine)
9edbe160de7266b3b5d54ccf2f07ed95f9f40c6bvboxsync{
9edbe160de7266b3b5d54ccf2f07ed95f9f40c6bvboxsync RTTIMERLNXSTATE enmOldState = enmCurState;
9edbe160de7266b3b5d54ccf2f07ed95f9f40c6bvboxsync bool fRc = ASMAtomicCmpXchgExU32((uint32_t volatile *)penmState, enmNewState, enmCurState, (uint32_t *)&enmOldState);
951d1da36c2120dd8bf59a3b57800f8429dcd387vboxsync RTTIMERLNX_LOG(("cxg %d -> %d - %d at %u\n", enmOldState, enmNewState, fRc, uLine));
9edbe160de7266b3b5d54ccf2f07ed95f9f40c6bvboxsync return fRc;
9edbe160de7266b3b5d54ccf2f07ed95f9f40c6bvboxsync}
9edbe160de7266b3b5d54ccf2f07ed95f9f40c6bvboxsync#else
9edbe160de7266b3b5d54ccf2f07ed95f9f40c6bvboxsyncDECLINLINE(bool) rtTimerLnxCmpXchgState(RTTIMERLNXSTATE volatile *penmState, RTTIMERLNXSTATE enmNewState,
9edbe160de7266b3b5d54ccf2f07ed95f9f40c6bvboxsync RTTIMERLNXSTATE enmCurState)
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync{
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync return ASMAtomicCmpXchgU32((uint32_t volatile *)penmState, enmNewState, enmCurState);
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync}
9edbe160de7266b3b5d54ccf2f07ed95f9f40c6bvboxsync#endif
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync/**
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync * Gets the state.
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync */
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsyncDECLINLINE(RTTIMERLNXSTATE) rtTimerLnxGetState(RTTIMERLNXSTATE volatile *penmState)
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync{
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync return (RTTIMERLNXSTATE)ASMAtomicUoReadU32((uint32_t volatile *)penmState);
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync}
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsync#ifdef RTTIMER_LINUX_WITH_HRTIMER
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync
4aafb1203580a5c145a7bdae57ebf69a36fa4f01vboxsync/**
4aafb1203580a5c145a7bdae57ebf69a36fa4f01vboxsync * Converts a nano second time stamp to ktime_t.
4aafb1203580a5c145a7bdae57ebf69a36fa4f01vboxsync *
852e87ceabd0234ac0f9e71537c11d08e35f736cvboxsync * ASSUMES RTTimeSystemNanoTS() is implemented using ktime_get_ts().
4aafb1203580a5c145a7bdae57ebf69a36fa4f01vboxsync *
4aafb1203580a5c145a7bdae57ebf69a36fa4f01vboxsync * @returns ktime_t.
4aafb1203580a5c145a7bdae57ebf69a36fa4f01vboxsync * @param cNanoSecs Nanoseconds.
4aafb1203580a5c145a7bdae57ebf69a36fa4f01vboxsync */
4aafb1203580a5c145a7bdae57ebf69a36fa4f01vboxsyncDECLINLINE(ktime_t) rtTimerLnxNanoToKt(uint64_t cNanoSecs)
4aafb1203580a5c145a7bdae57ebf69a36fa4f01vboxsync{
4aafb1203580a5c145a7bdae57ebf69a36fa4f01vboxsync /* With some luck the compiler optimizes the division out of this... (Bet it doesn't.) */
4aafb1203580a5c145a7bdae57ebf69a36fa4f01vboxsync return ktime_set(cNanoSecs / 1000000000, cNanoSecs % 1000000000);
4aafb1203580a5c145a7bdae57ebf69a36fa4f01vboxsync}
4aafb1203580a5c145a7bdae57ebf69a36fa4f01vboxsync
4aafb1203580a5c145a7bdae57ebf69a36fa4f01vboxsync/**
4aafb1203580a5c145a7bdae57ebf69a36fa4f01vboxsync * Converts ktime_t to a nano second time stamp.
4aafb1203580a5c145a7bdae57ebf69a36fa4f01vboxsync *
852e87ceabd0234ac0f9e71537c11d08e35f736cvboxsync * ASSUMES RTTimeSystemNanoTS() is implemented using ktime_get_ts().
4aafb1203580a5c145a7bdae57ebf69a36fa4f01vboxsync *
4aafb1203580a5c145a7bdae57ebf69a36fa4f01vboxsync * @returns nano second time stamp.
4aafb1203580a5c145a7bdae57ebf69a36fa4f01vboxsync * @param Kt ktime_t.
4aafb1203580a5c145a7bdae57ebf69a36fa4f01vboxsync */
4aafb1203580a5c145a7bdae57ebf69a36fa4f01vboxsyncDECLINLINE(uint64_t) rtTimerLnxKtToNano(ktime_t Kt)
4aafb1203580a5c145a7bdae57ebf69a36fa4f01vboxsync{
4aafb1203580a5c145a7bdae57ebf69a36fa4f01vboxsync return ktime_to_ns(Kt);
4aafb1203580a5c145a7bdae57ebf69a36fa4f01vboxsync}
4aafb1203580a5c145a7bdae57ebf69a36fa4f01vboxsync
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsync#endif /* RTTIMER_LINUX_WITH_HRTIMER */
4aafb1203580a5c145a7bdae57ebf69a36fa4f01vboxsync
0f77dc54d7ec617480988ccdfcd080f480e79698vboxsync/**
0f77dc54d7ec617480988ccdfcd080f480e79698vboxsync * Converts a nano second interval to jiffies.
0f77dc54d7ec617480988ccdfcd080f480e79698vboxsync *
0f77dc54d7ec617480988ccdfcd080f480e79698vboxsync * @returns Jiffies.
0f77dc54d7ec617480988ccdfcd080f480e79698vboxsync * @param cNanoSecs Nanoseconds.
0f77dc54d7ec617480988ccdfcd080f480e79698vboxsync */
0f77dc54d7ec617480988ccdfcd080f480e79698vboxsyncDECLINLINE(unsigned long) rtTimerLnxNanoToJiffies(uint64_t cNanoSecs)
0f77dc54d7ec617480988ccdfcd080f480e79698vboxsync{
0f77dc54d7ec617480988ccdfcd080f480e79698vboxsync /* this can be made even better... */
0f77dc54d7ec617480988ccdfcd080f480e79698vboxsync if (cNanoSecs > (uint64_t)TICK_NSEC * MAX_JIFFY_OFFSET)
0f77dc54d7ec617480988ccdfcd080f480e79698vboxsync return MAX_JIFFY_OFFSET;
619824b60d668e6e43f385ef78cf06e13d43aab6vboxsync# if ARCH_BITS == 32
0f77dc54d7ec617480988ccdfcd080f480e79698vboxsync if (RT_LIKELY(cNanoSecs <= UINT32_MAX))
0f77dc54d7ec617480988ccdfcd080f480e79698vboxsync return ((uint32_t)cNanoSecs + (TICK_NSEC-1)) / TICK_NSEC;
619824b60d668e6e43f385ef78cf06e13d43aab6vboxsync# endif
0f77dc54d7ec617480988ccdfcd080f480e79698vboxsync return (cNanoSecs + (TICK_NSEC-1)) / TICK_NSEC;
0f77dc54d7ec617480988ccdfcd080f480e79698vboxsync}
0f77dc54d7ec617480988ccdfcd080f480e79698vboxsync
0f77dc54d7ec617480988ccdfcd080f480e79698vboxsync
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync/**
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync * Starts a sub-timer (RTTimerStart).
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync *
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync * @param pSubTimer The sub-timer to start.
852e87ceabd0234ac0f9e71537c11d08e35f736cvboxsync * @param u64Now The current timestamp (RTTimeSystemNanoTS()).
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync * @param u64First The interval from u64Now to the first time the timer should fire.
76cb9831bbeaff3bb30068363e35660a776736c4vboxsync * @param fPinned true = timer pinned to a specific CPU,
76cb9831bbeaff3bb30068363e35660a776736c4vboxsync * false = timer can migrate between CPUs
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsync * @param fHighRes Whether the user requested a high resolution timer or not.
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync * @param enmOldState The old timer state.
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync */
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsyncstatic void rtTimerLnxStartSubTimer(PRTTIMERLNXSUBTIMER pSubTimer, uint64_t u64Now, uint64_t u64First,
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsync bool fPinned, bool fHighRes)
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync{
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync /*
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync * Calc when it should start firing.
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync */
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync uint64_t u64NextTS = u64Now + u64First;
5422fa26c16d9d065b5879feb3852da231be5c55vboxsync if (!fHighRes)
852e87ceabd0234ac0f9e71537c11d08e35f736cvboxsync pSubTimer->u.Std.u64NextTS = u64NextTS;
951d1da36c2120dd8bf59a3b57800f8429dcd387vboxsync RTTIMERLNX_LOG(("startsubtimer %p\n", pSubTimer->pParent));
619824b60d668e6e43f385ef78cf06e13d43aab6vboxsync
0f77dc54d7ec617480988ccdfcd080f480e79698vboxsync pSubTimer->iTick = 0;
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsync#ifdef RTTIMER_LINUX_WITH_HRTIMER
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsync if (fHighRes)
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsync hrtimer_start(&pSubTimer->u.Hr.LnxTimer, rtTimerLnxNanoToKt(u64NextTS),
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsync fPinned ? HRTIMER_MODE_ABS_PINNED : HRTIMER_MODE_ABS);
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsync else
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsync#endif
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync {
0f77dc54d7ec617480988ccdfcd080f480e79698vboxsync unsigned long cJiffies = !u64First ? 0 : rtTimerLnxNanoToJiffies(u64First);
852e87ceabd0234ac0f9e71537c11d08e35f736cvboxsync pSubTimer->u.Std.ulNextJiffies = jiffies + cJiffies;
852e87ceabd0234ac0f9e71537c11d08e35f736cvboxsync pSubTimer->u.Std.fFirstAfterChg = true;
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync#ifdef CONFIG_SMP
76cb9831bbeaff3bb30068363e35660a776736c4vboxsync if (fPinned)
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsync mod_timer_pinned(&pSubTimer->u.Std.LnxTimer, pSubTimer->u.Std.ulNextJiffies);
76cb9831bbeaff3bb30068363e35660a776736c4vboxsync else
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync#endif
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsync mod_timer(&pSubTimer->u.Std.LnxTimer, pSubTimer->u.Std.ulNextJiffies);
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync }
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync /* Be a bit careful here since we could be racing the callback. */
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync if (!rtTimerLnxCmpXchgState(&pSubTimer->enmState, RTTIMERLNXSTATE_ACTIVE, RTTIMERLNXSTATE_STARTING))
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync rtTimerLnxCmpXchgState(&pSubTimer->enmState, RTTIMERLNXSTATE_ACTIVE, RTTIMERLNXSTATE_MP_STARTING);
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync}
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync/**
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync * Stops a sub-timer (RTTimerStart and rtTimerLinuxMpEvent()).
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync *
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync * The caller has already changed the state, so we will not be in a callback
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync * situation wrt to the calling thread.
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync *
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync * @param pSubTimer The sub-timer.
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync * @param fHighRes Whether the user requested a high resolution timer or not.
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync */
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsyncstatic void rtTimerLnxStopSubTimer(PRTTIMERLNXSUBTIMER pSubTimer, bool fHighRes)
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync{
951d1da36c2120dd8bf59a3b57800f8429dcd387vboxsync RTTIMERLNX_LOG(("stopsubtimer %p %d\n", pSubTimer->pParent, fHighRes));
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsync#ifdef RTTIMER_LINUX_WITH_HRTIMER
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync if (fHighRes)
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsync {
10f0e3bfdb61e7bae30a1a1d9c17659a908c3d37vboxsync /* There is no equivalent to del_timer in the hrtimer API,
10f0e3bfdb61e7bae30a1a1d9c17659a908c3d37vboxsync hrtimer_cancel() == del_timer_sync(). Just like the WARN_ON in
10f0e3bfdb61e7bae30a1a1d9c17659a908c3d37vboxsync del_timer_sync() asserts, waiting for a timer callback to complete
10f0e3bfdb61e7bae30a1a1d9c17659a908c3d37vboxsync is deadlock prone, so don't do it. */
10f0e3bfdb61e7bae30a1a1d9c17659a908c3d37vboxsync int rc = hrtimer_try_to_cancel(&pSubTimer->u.Hr.LnxTimer);
10f0e3bfdb61e7bae30a1a1d9c17659a908c3d37vboxsync if (rc < 0)
10f0e3bfdb61e7bae30a1a1d9c17659a908c3d37vboxsync {
10f0e3bfdb61e7bae30a1a1d9c17659a908c3d37vboxsync hrtimer_start(&pSubTimer->u.Hr.LnxTimer, ktime_set(KTIME_SEC_MAX, 0), HRTIMER_MODE_ABS);
10f0e3bfdb61e7bae30a1a1d9c17659a908c3d37vboxsync hrtimer_try_to_cancel(&pSubTimer->u.Hr.LnxTimer);
10f0e3bfdb61e7bae30a1a1d9c17659a908c3d37vboxsync }
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsync }
10f0e3bfdb61e7bae30a1a1d9c17659a908c3d37vboxsync else
10f0e3bfdb61e7bae30a1a1d9c17659a908c3d37vboxsync#endif
10f0e3bfdb61e7bae30a1a1d9c17659a908c3d37vboxsync del_timer(&pSubTimer->u.Std.LnxTimer);
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync rtTimerLnxSetState(&pSubTimer->enmState, RTTIMERLNXSTATE_STOPPED);
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync}
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync/**
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync * Used by RTTimerDestroy and rtTimerLnxCallbackDestroy to do the actual work.
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync *
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync * @param pTimer The timer in question.
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync */
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsyncstatic void rtTimerLnxDestroyIt(PRTTIMER pTimer)
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync{
10f0e3bfdb61e7bae30a1a1d9c17659a908c3d37vboxsync RTSPINLOCK hSpinlock = pTimer->hSpinlock;
10f0e3bfdb61e7bae30a1a1d9c17659a908c3d37vboxsync RTCPUID iCpu;
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync Assert(pTimer->fSuspended);
951d1da36c2120dd8bf59a3b57800f8429dcd387vboxsync RTTIMERLNX_LOG(("destroyit %p\n", pTimer));
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync /*
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync * Remove the MP notifications first because it'll reduce the risk of
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync * us overtaking any MP event that might theoretically be racing us here.
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync */
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync#ifdef CONFIG_SMP
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync if ( pTimer->cCpus > 1
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync && hSpinlock != NIL_RTSPINLOCK)
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync {
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync int rc = RTMpNotificationDeregister(rtTimerLinuxMpEvent, pTimer);
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync AssertRC(rc);
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync }
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync#endif /* CONFIG_SMP */
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync /*
10f0e3bfdb61e7bae30a1a1d9c17659a908c3d37vboxsync * Invalidate the handle.
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync */
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync ASMAtomicWriteU32(&pTimer->u32Magic, ~RTTIMER_MAGIC);
10f0e3bfdb61e7bae30a1a1d9c17659a908c3d37vboxsync
10f0e3bfdb61e7bae30a1a1d9c17659a908c3d37vboxsync /*
10f0e3bfdb61e7bae30a1a1d9c17659a908c3d37vboxsync * Make sure all timers have stopped executing since we're stopping them in
10f0e3bfdb61e7bae30a1a1d9c17659a908c3d37vboxsync * an asynchronous manner up in rtTimerLnxStopSubTimer.
10f0e3bfdb61e7bae30a1a1d9c17659a908c3d37vboxsync */
10f0e3bfdb61e7bae30a1a1d9c17659a908c3d37vboxsync iCpu = pTimer->cCpus;
10f0e3bfdb61e7bae30a1a1d9c17659a908c3d37vboxsync while (iCpu-- > 0)
10f0e3bfdb61e7bae30a1a1d9c17659a908c3d37vboxsync {
10f0e3bfdb61e7bae30a1a1d9c17659a908c3d37vboxsync#ifdef RTTIMER_LINUX_WITH_HRTIMER
10f0e3bfdb61e7bae30a1a1d9c17659a908c3d37vboxsync if (pTimer->fHighRes)
10f0e3bfdb61e7bae30a1a1d9c17659a908c3d37vboxsync hrtimer_cancel(&pTimer->aSubTimers[iCpu].u.Hr.LnxTimer);
10f0e3bfdb61e7bae30a1a1d9c17659a908c3d37vboxsync else
10f0e3bfdb61e7bae30a1a1d9c17659a908c3d37vboxsync#endif
10f0e3bfdb61e7bae30a1a1d9c17659a908c3d37vboxsync del_timer_sync(&pTimer->aSubTimers[iCpu].u.Std.LnxTimer);
10f0e3bfdb61e7bae30a1a1d9c17659a908c3d37vboxsync }
10f0e3bfdb61e7bae30a1a1d9c17659a908c3d37vboxsync
10f0e3bfdb61e7bae30a1a1d9c17659a908c3d37vboxsync /*
10f0e3bfdb61e7bae30a1a1d9c17659a908c3d37vboxsync * Finally, free the resources.
10f0e3bfdb61e7bae30a1a1d9c17659a908c3d37vboxsync */
25c97a3e3ce2710f95faa6d181486df26b518e74vboxsync RTMemFreeEx(pTimer, RT_OFFSETOF(RTTIMER, aSubTimers[pTimer->cCpus]));
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync if (hSpinlock != NIL_RTSPINLOCK)
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync RTSpinlockDestroy(hSpinlock);
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync}
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync
10f0e3bfdb61e7bae30a1a1d9c17659a908c3d37vboxsync/**
10f0e3bfdb61e7bae30a1a1d9c17659a908c3d37vboxsync * Workqueue callback (no DECLCALLBACK!) for deferred destruction.
10f0e3bfdb61e7bae30a1a1d9c17659a908c3d37vboxsync *
10f0e3bfdb61e7bae30a1a1d9c17659a908c3d37vboxsync * @param pWork Pointer to the DtorWorkqueueItem member of our timer
10f0e3bfdb61e7bae30a1a1d9c17659a908c3d37vboxsync * structure.
10f0e3bfdb61e7bae30a1a1d9c17659a908c3d37vboxsync */
10f0e3bfdb61e7bae30a1a1d9c17659a908c3d37vboxsyncstatic void rtTimerLnxDestroyDeferred(RTR0LNXWORKQUEUEITEM *pWork)
10f0e3bfdb61e7bae30a1a1d9c17659a908c3d37vboxsync{
10f0e3bfdb61e7bae30a1a1d9c17659a908c3d37vboxsync PRTTIMER pTimer = RT_FROM_MEMBER(pWork, RTTIMER, DtorWorkqueueItem);
10f0e3bfdb61e7bae30a1a1d9c17659a908c3d37vboxsync rtTimerLnxDestroyIt(pTimer);
10f0e3bfdb61e7bae30a1a1d9c17659a908c3d37vboxsync}
10f0e3bfdb61e7bae30a1a1d9c17659a908c3d37vboxsync
10f0e3bfdb61e7bae30a1a1d9c17659a908c3d37vboxsync
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync/**
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync * Called when the timer was destroyed by the callback function.
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync *
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync * @param pTimer The timer.
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync * @param pSubTimer The sub-timer which we're handling, the state of this
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync * will be RTTIMERLNXSTATE_CALLBACK_DESTROYING.
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync */
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsyncstatic void rtTimerLnxCallbackDestroy(PRTTIMER pTimer, PRTTIMERLNXSUBTIMER pSubTimer)
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync{
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync /*
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync * If it's an omni timer, the last dude does the destroying.
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync */
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync if (pTimer->cCpus > 1)
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync {
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync uint32_t iCpu = pTimer->cCpus;
f0ed7ab5e7f8d2f73b5aa08e46eb3a04cbb31cb2vboxsync RTSpinlockAcquire(pTimer->hSpinlock);
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync Assert(pSubTimer->enmState == RTTIMERLNXSTATE_CB_DESTROYING);
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync rtTimerLnxSetState(&pSubTimer->enmState, RTTIMERLNXSTATE_STOPPED);
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync while (iCpu-- > 0)
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync if (rtTimerLnxGetState(&pTimer->aSubTimers[iCpu].enmState) != RTTIMERLNXSTATE_STOPPED)
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync {
f0ed7ab5e7f8d2f73b5aa08e46eb3a04cbb31cb2vboxsync RTSpinlockRelease(pTimer->hSpinlock);
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync return;
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync }
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync
f0ed7ab5e7f8d2f73b5aa08e46eb3a04cbb31cb2vboxsync RTSpinlockRelease(pTimer->hSpinlock);
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync }
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync
10f0e3bfdb61e7bae30a1a1d9c17659a908c3d37vboxsync /*
10f0e3bfdb61e7bae30a1a1d9c17659a908c3d37vboxsync * Destroying a timer from the callback is unsafe since the callout code
10f0e3bfdb61e7bae30a1a1d9c17659a908c3d37vboxsync * might be touching the timer structure upon return (hrtimer does!). So,
10f0e3bfdb61e7bae30a1a1d9c17659a908c3d37vboxsync * we have to defer the actual destruction to the IRPT workqueue.
10f0e3bfdb61e7bae30a1a1d9c17659a908c3d37vboxsync */
10f0e3bfdb61e7bae30a1a1d9c17659a908c3d37vboxsync rtR0LnxWorkqueuePush(&pTimer->DtorWorkqueueItem, rtTimerLnxDestroyDeferred);
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync}
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync#ifdef CONFIG_SMP
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync/**
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync * Deal with a sub-timer that has migrated.
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync *
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync * @param pTimer The timer.
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync * @param pSubTimer The sub-timer.
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync */
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsyncstatic void rtTimerLnxCallbackHandleMigration(PRTTIMER pTimer, PRTTIMERLNXSUBTIMER pSubTimer)
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync{
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync RTTIMERLNXSTATE enmState;
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync if (pTimer->cCpus > 1)
f0ed7ab5e7f8d2f73b5aa08e46eb3a04cbb31cb2vboxsync RTSpinlockAcquire(pTimer->hSpinlock);
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync do
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync {
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync enmState = rtTimerLnxGetState(&pSubTimer->enmState);
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync switch (enmState)
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync {
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync case RTTIMERLNXSTATE_STOPPING:
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync case RTTIMERLNXSTATE_MP_STOPPING:
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync enmState = RTTIMERLNXSTATE_STOPPED;
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync case RTTIMERLNXSTATE_STOPPED:
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync break;
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync default:
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync AssertMsgFailed(("%d\n", enmState));
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync case RTTIMERLNXSTATE_STARTING:
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync case RTTIMERLNXSTATE_MP_STARTING:
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync case RTTIMERLNXSTATE_ACTIVE:
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync case RTTIMERLNXSTATE_CALLBACK:
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync case RTTIMERLNXSTATE_CB_STOPPING:
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync case RTTIMERLNXSTATE_CB_RESTARTING:
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync if (rtTimerLnxCmpXchgState(&pSubTimer->enmState, RTTIMERLNXSTATE_STOPPED, enmState))
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync enmState = RTTIMERLNXSTATE_STOPPED;
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync break;
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync case RTTIMERLNXSTATE_CB_DESTROYING:
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync {
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync if (pTimer->cCpus > 1)
f0ed7ab5e7f8d2f73b5aa08e46eb3a04cbb31cb2vboxsync RTSpinlockRelease(pTimer->hSpinlock);
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync rtTimerLnxCallbackDestroy(pTimer, pSubTimer);
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync return;
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync }
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync }
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync } while (enmState != RTTIMERLNXSTATE_STOPPED);
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync if (pTimer->cCpus > 1)
f0ed7ab5e7f8d2f73b5aa08e46eb3a04cbb31cb2vboxsync RTSpinlockRelease(pTimer->hSpinlock);
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync}
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync#endif /* CONFIG_SMP */
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync/**
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync * The slow path of rtTimerLnxChangeToCallbackState.
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync *
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync * @returns true if changed successfully, false if not.
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync * @param pSubTimer The sub-timer.
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync */
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsyncstatic bool rtTimerLnxChangeToCallbackStateSlow(PRTTIMERLNXSUBTIMER pSubTimer)
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync{
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync for (;;)
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync {
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync RTTIMERLNXSTATE enmState = rtTimerLnxGetState(&pSubTimer->enmState);
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync switch (enmState)
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync {
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync case RTTIMERLNXSTATE_ACTIVE:
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync case RTTIMERLNXSTATE_STARTING:
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync case RTTIMERLNXSTATE_MP_STARTING:
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync if (rtTimerLnxCmpXchgState(&pSubTimer->enmState, RTTIMERLNXSTATE_CALLBACK, enmState))
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync return true;
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync break;
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync case RTTIMERLNXSTATE_CALLBACK:
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync case RTTIMERLNXSTATE_CB_STOPPING:
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync case RTTIMERLNXSTATE_CB_RESTARTING:
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync case RTTIMERLNXSTATE_CB_DESTROYING:
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync AssertMsgFailed(("%d\n", enmState));
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync default:
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync return false;
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync }
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync ASMNopPause();
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync }
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync}
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync/**
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync * Tries to change the sub-timer state to 'callback'.
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync *
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync * @returns true if changed successfully, false if not.
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync * @param pSubTimer The sub-timer.
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync */
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsyncDECLINLINE(bool) rtTimerLnxChangeToCallbackState(PRTTIMERLNXSUBTIMER pSubTimer)
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync{
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync if (RT_LIKELY(rtTimerLnxCmpXchgState(&pSubTimer->enmState, RTTIMERLNXSTATE_CALLBACK, RTTIMERLNXSTATE_ACTIVE)))
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync return true;
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync return rtTimerLnxChangeToCallbackStateSlow(pSubTimer);
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync}
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsync#ifdef RTTIMER_LINUX_WITH_HRTIMER
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync/**
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsync * Timer callback function for high resolution timers.
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsync *
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsync * @returns HRTIMER_NORESTART or HRTIMER_RESTART depending on whether it's a
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsync * one-shot or interval timer.
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync * @param pHrTimer Pointer to the sub-timer structure.
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync */
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsyncstatic enum hrtimer_restart rtTimerLinuxHrCallback(struct hrtimer *pHrTimer)
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync{
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsync PRTTIMERLNXSUBTIMER pSubTimer = RT_FROM_MEMBER(pHrTimer, RTTIMERLNXSUBTIMER, u.Hr.LnxTimer);
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsync PRTTIMER pTimer = pSubTimer->pParent;
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync
951d1da36c2120dd8bf59a3b57800f8429dcd387vboxsync RTTIMERLNX_LOG(("hrcallback %p\n", pTimer));
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync if (RT_UNLIKELY(!rtTimerLnxChangeToCallbackState(pSubTimer)))
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync return HRTIMER_NORESTART;
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync#ifdef CONFIG_SMP
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync /*
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync * Check for unwanted migration.
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync */
951d1da36c2120dd8bf59a3b57800f8429dcd387vboxsync if (pTimer->fAllCpus || pTimer->fSpecificCpu)
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync {
951d1da36c2120dd8bf59a3b57800f8429dcd387vboxsync RTCPUID idCpu = RTMpCpuId();
951d1da36c2120dd8bf59a3b57800f8429dcd387vboxsync if (RT_UNLIKELY( pTimer->fAllCpus
951d1da36c2120dd8bf59a3b57800f8429dcd387vboxsync ? (RTCPUID)(pSubTimer - &pTimer->aSubTimers[0]) != idCpu
951d1da36c2120dd8bf59a3b57800f8429dcd387vboxsync : pTimer->idCpu != idCpu))
951d1da36c2120dd8bf59a3b57800f8429dcd387vboxsync {
951d1da36c2120dd8bf59a3b57800f8429dcd387vboxsync rtTimerLnxCallbackHandleMigration(pTimer, pSubTimer);
951d1da36c2120dd8bf59a3b57800f8429dcd387vboxsync return HRTIMER_NORESTART;
951d1da36c2120dd8bf59a3b57800f8429dcd387vboxsync }
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync }
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync#endif
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync if (pTimer->u64NanoInterval)
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync {
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync /*
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync * Periodic timer, run it and update the native timer afterwards so
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync * we can handle RTTimerStop and RTTimerChangeInterval from the
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync * callback as well as a racing control thread.
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync */
0f77dc54d7ec617480988ccdfcd080f480e79698vboxsync pTimer->pfnTimer(pTimer, pTimer->pvUser, ++pSubTimer->iTick);
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync hrtimer_add_expires_ns(&pSubTimer->u.Hr.LnxTimer, ASMAtomicReadU64(&pTimer->u64NanoInterval));
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync if (RT_LIKELY(rtTimerLnxCmpXchgState(&pSubTimer->enmState, RTTIMERLNXSTATE_ACTIVE, RTTIMERLNXSTATE_CALLBACK)))
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync return HRTIMER_RESTART;
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync }
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync else
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync {
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsync /*
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync * One shot timer (no omni), stop it before dispatching it.
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync * Allow RTTimerStart as well as RTTimerDestroy to be called from
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync * the callback.
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsync */
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync ASMAtomicWriteBool(&pTimer->fSuspended, true);
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync pTimer->pfnTimer(pTimer, pTimer->pvUser, ++pSubTimer->iTick);
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync if (RT_LIKELY(rtTimerLnxCmpXchgState(&pSubTimer->enmState, RTTIMERLNXSTATE_STOPPED, RTTIMERLNXSTATE_CALLBACK)))
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync return HRTIMER_NORESTART;
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync }
619824b60d668e6e43f385ef78cf06e13d43aab6vboxsync
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync /*
ad27e1d5e48ca41245120c331cc88b50464813cevboxsync * Some state change occurred while we were in the callback routine.
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync */
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync for (;;)
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync {
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync RTTIMERLNXSTATE enmState = rtTimerLnxGetState(&pSubTimer->enmState);
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync switch (enmState)
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsync {
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync case RTTIMERLNXSTATE_CB_DESTROYING:
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync rtTimerLnxCallbackDestroy(pTimer, pSubTimer);
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync return HRTIMER_NORESTART;
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync case RTTIMERLNXSTATE_CB_STOPPING:
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync if (rtTimerLnxCmpXchgState(&pSubTimer->enmState, RTTIMERLNXSTATE_STOPPED, RTTIMERLNXSTATE_CB_STOPPING))
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync return HRTIMER_NORESTART;
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync break;
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync case RTTIMERLNXSTATE_CB_RESTARTING:
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync if (rtTimerLnxCmpXchgState(&pSubTimer->enmState, RTTIMERLNXSTATE_ACTIVE, RTTIMERLNXSTATE_CB_RESTARTING))
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync {
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync pSubTimer->iTick = 0;
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync hrtimer_set_expires(&pSubTimer->u.Hr.LnxTimer, rtTimerLnxNanoToKt(pSubTimer->uNsRestartAt));
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync return HRTIMER_RESTART;
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync }
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync break;
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync default:
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync AssertMsgFailed(("%d\n", enmState));
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync return HRTIMER_NORESTART;
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsync }
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync ASMNopPause();
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsync }
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsync}
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync#endif /* RTTIMER_LINUX_WITH_HRTIMER */
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsync
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsync
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsync/**
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsync * Timer callback function for standard timers.
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsync *
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsync * @param ulUser Address of the sub-timer structure.
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsync */
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsyncstatic void rtTimerLinuxStdCallback(unsigned long ulUser)
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsync{
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsync PRTTIMERLNXSUBTIMER pSubTimer = (PRTTIMERLNXSUBTIMER)ulUser;
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsync PRTTIMER pTimer = pSubTimer->pParent;
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsync
951d1da36c2120dd8bf59a3b57800f8429dcd387vboxsync RTTIMERLNX_LOG(("stdcallback %p\n", pTimer));
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync if (RT_UNLIKELY(!rtTimerLnxChangeToCallbackState(pSubTimer)))
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync return;
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync#ifdef CONFIG_SMP
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsync /*
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync * Check for unwanted migration.
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsync */
951d1da36c2120dd8bf59a3b57800f8429dcd387vboxsync if (pTimer->fAllCpus || pTimer->fSpecificCpu)
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsync {
951d1da36c2120dd8bf59a3b57800f8429dcd387vboxsync RTCPUID idCpu = RTMpCpuId();
951d1da36c2120dd8bf59a3b57800f8429dcd387vboxsync if (RT_UNLIKELY( pTimer->fAllCpus
951d1da36c2120dd8bf59a3b57800f8429dcd387vboxsync ? (RTCPUID)(pSubTimer - &pTimer->aSubTimers[0]) != idCpu
951d1da36c2120dd8bf59a3b57800f8429dcd387vboxsync : pTimer->idCpu != idCpu))
951d1da36c2120dd8bf59a3b57800f8429dcd387vboxsync {
951d1da36c2120dd8bf59a3b57800f8429dcd387vboxsync rtTimerLnxCallbackHandleMigration(pTimer, pSubTimer);
951d1da36c2120dd8bf59a3b57800f8429dcd387vboxsync return;
951d1da36c2120dd8bf59a3b57800f8429dcd387vboxsync }
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsync }
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync#endif
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync if (pTimer->u64NanoInterval)
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsync {
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync /*
852e87ceabd0234ac0f9e71537c11d08e35f736cvboxsync * Interval timer, calculate the next timeout.
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync *
852e87ceabd0234ac0f9e71537c11d08e35f736cvboxsync * The first time around, we'll re-adjust the u.Std.u64NextTS to
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync * try prevent some jittering if we were started at a bad time.
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync */
852e87ceabd0234ac0f9e71537c11d08e35f736cvboxsync const uint64_t iTick = ++pSubTimer->iTick;
852e87ceabd0234ac0f9e71537c11d08e35f736cvboxsync uint64_t u64NanoInterval;
852e87ceabd0234ac0f9e71537c11d08e35f736cvboxsync unsigned long cJiffies;
852e87ceabd0234ac0f9e71537c11d08e35f736cvboxsync unsigned long flFlags;
852e87ceabd0234ac0f9e71537c11d08e35f736cvboxsync
852e87ceabd0234ac0f9e71537c11d08e35f736cvboxsync spin_lock_irqsave(&pTimer->ChgIntLock, flFlags);
852e87ceabd0234ac0f9e71537c11d08e35f736cvboxsync u64NanoInterval = pTimer->u64NanoInterval;
852e87ceabd0234ac0f9e71537c11d08e35f736cvboxsync cJiffies = pTimer->cJiffies;
852e87ceabd0234ac0f9e71537c11d08e35f736cvboxsync if (RT_UNLIKELY(pSubTimer->u.Std.fFirstAfterChg))
4aafb1203580a5c145a7bdae57ebf69a36fa4f01vboxsync {
852e87ceabd0234ac0f9e71537c11d08e35f736cvboxsync pSubTimer->u.Std.fFirstAfterChg = false;
852e87ceabd0234ac0f9e71537c11d08e35f736cvboxsync pSubTimer->u.Std.u64NextTS = RTTimeSystemNanoTS();
852e87ceabd0234ac0f9e71537c11d08e35f736cvboxsync pSubTimer->u.Std.ulNextJiffies = jiffies;
4aafb1203580a5c145a7bdae57ebf69a36fa4f01vboxsync }
852e87ceabd0234ac0f9e71537c11d08e35f736cvboxsync spin_unlock_irqrestore(&pTimer->ChgIntLock, flFlags);
4aafb1203580a5c145a7bdae57ebf69a36fa4f01vboxsync
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsync pSubTimer->u.Std.u64NextTS += u64NanoInterval;
852e87ceabd0234ac0f9e71537c11d08e35f736cvboxsync if (cJiffies)
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync {
852e87ceabd0234ac0f9e71537c11d08e35f736cvboxsync pSubTimer->u.Std.ulNextJiffies += cJiffies;
3a2aedd9e337c0cc515ce501a066359ba2f9505cvboxsync /* Prevent overflows when the jiffies counter wraps around.
3a2aedd9e337c0cc515ce501a066359ba2f9505cvboxsync * Special thanks to Ken Preslan for helping debugging! */
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsync while (time_before(pSubTimer->u.Std.ulNextJiffies, jiffies))
4aafb1203580a5c145a7bdae57ebf69a36fa4f01vboxsync {
852e87ceabd0234ac0f9e71537c11d08e35f736cvboxsync pSubTimer->u.Std.ulNextJiffies += cJiffies;
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync pSubTimer->u.Std.u64NextTS += u64NanoInterval;
4aafb1203580a5c145a7bdae57ebf69a36fa4f01vboxsync }
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync }
4aafb1203580a5c145a7bdae57ebf69a36fa4f01vboxsync else
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync {
852e87ceabd0234ac0f9e71537c11d08e35f736cvboxsync const uint64_t u64NanoTS = RTTimeSystemNanoTS();
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsync while (pSubTimer->u.Std.u64NextTS < u64NanoTS)
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsync pSubTimer->u.Std.u64NextTS += u64NanoInterval;
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsync pSubTimer->u.Std.ulNextJiffies = jiffies + rtTimerLnxNanoToJiffies(pSubTimer->u.Std.u64NextTS - u64NanoTS);
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync }
4aafb1203580a5c145a7bdae57ebf69a36fa4f01vboxsync
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync /*
852e87ceabd0234ac0f9e71537c11d08e35f736cvboxsync * Run the timer and re-arm it unless the state changed .
852e87ceabd0234ac0f9e71537c11d08e35f736cvboxsync * .
852e87ceabd0234ac0f9e71537c11d08e35f736cvboxsync * We must re-arm it afterwards as we're not in a position to undo this .
852e87ceabd0234ac0f9e71537c11d08e35f736cvboxsync * operation if for instance someone stopped or destroyed us while we .
852e87ceabd0234ac0f9e71537c11d08e35f736cvboxsync * were in the callback. (Linux takes care of any races here.)
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync */
0f77dc54d7ec617480988ccdfcd080f480e79698vboxsync pTimer->pfnTimer(pTimer, pTimer->pvUser, iTick);
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync if (RT_LIKELY(rtTimerLnxCmpXchgState(&pSubTimer->enmState, RTTIMERLNXSTATE_ACTIVE, RTTIMERLNXSTATE_CALLBACK)))
852e87ceabd0234ac0f9e71537c11d08e35f736cvboxsync {
852e87ceabd0234ac0f9e71537c11d08e35f736cvboxsync#ifdef CONFIG_SMP
852e87ceabd0234ac0f9e71537c11d08e35f736cvboxsync if (pTimer->fSpecificCpu || pTimer->fAllCpus)
852e87ceabd0234ac0f9e71537c11d08e35f736cvboxsync mod_timer_pinned(&pSubTimer->u.Std.LnxTimer, pSubTimer->u.Std.ulNextJiffies);
852e87ceabd0234ac0f9e71537c11d08e35f736cvboxsync else
852e87ceabd0234ac0f9e71537c11d08e35f736cvboxsync#endif
852e87ceabd0234ac0f9e71537c11d08e35f736cvboxsync mod_timer(&pSubTimer->u.Std.LnxTimer, pSubTimer->u.Std.ulNextJiffies);
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync return;
852e87ceabd0234ac0f9e71537c11d08e35f736cvboxsync }
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync }
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync else
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync {
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync /*
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync * One shot timer, stop it before dispatching it.
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync * Allow RTTimerStart as well as RTTimerDestroy to be called from
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync * the callback.
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync */
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync ASMAtomicWriteBool(&pTimer->fSuspended, true);
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync pTimer->pfnTimer(pTimer, pTimer->pvUser, ++pSubTimer->iTick);
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync if (RT_LIKELY(rtTimerLnxCmpXchgState(&pSubTimer->enmState, RTTIMERLNXSTATE_STOPPED, RTTIMERLNXSTATE_CALLBACK)))
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync return;
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync }
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync /*
ad27e1d5e48ca41245120c331cc88b50464813cevboxsync * Some state change occurred while we were in the callback routine.
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync */
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync for (;;)
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync {
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync RTTIMERLNXSTATE enmState = rtTimerLnxGetState(&pSubTimer->enmState);
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync switch (enmState)
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync {
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync case RTTIMERLNXSTATE_CB_DESTROYING:
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync rtTimerLnxCallbackDestroy(pTimer, pSubTimer);
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync return;
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync case RTTIMERLNXSTATE_CB_STOPPING:
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync if (rtTimerLnxCmpXchgState(&pSubTimer->enmState, RTTIMERLNXSTATE_STOPPED, RTTIMERLNXSTATE_CB_STOPPING))
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync return;
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync break;
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsync
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync case RTTIMERLNXSTATE_CB_RESTARTING:
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync if (rtTimerLnxCmpXchgState(&pSubTimer->enmState, RTTIMERLNXSTATE_ACTIVE, RTTIMERLNXSTATE_CB_RESTARTING))
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync {
852e87ceabd0234ac0f9e71537c11d08e35f736cvboxsync uint64_t u64NanoTS;
852e87ceabd0234ac0f9e71537c11d08e35f736cvboxsync uint64_t u64NextTS;
852e87ceabd0234ac0f9e71537c11d08e35f736cvboxsync unsigned long flFlags;
852e87ceabd0234ac0f9e71537c11d08e35f736cvboxsync
852e87ceabd0234ac0f9e71537c11d08e35f736cvboxsync spin_lock_irqsave(&pTimer->ChgIntLock, flFlags);
852e87ceabd0234ac0f9e71537c11d08e35f736cvboxsync u64NextTS = pSubTimer->uNsRestartAt;
852e87ceabd0234ac0f9e71537c11d08e35f736cvboxsync u64NanoTS = RTTimeSystemNanoTS();
852e87ceabd0234ac0f9e71537c11d08e35f736cvboxsync pSubTimer->iTick = 0;
852e87ceabd0234ac0f9e71537c11d08e35f736cvboxsync pSubTimer->u.Std.u64NextTS = u64NextTS;
852e87ceabd0234ac0f9e71537c11d08e35f736cvboxsync pSubTimer->u.Std.fFirstAfterChg = true;
852e87ceabd0234ac0f9e71537c11d08e35f736cvboxsync pSubTimer->u.Std.ulNextJiffies = u64NextTS > u64NanoTS
852e87ceabd0234ac0f9e71537c11d08e35f736cvboxsync ? jiffies + rtTimerLnxNanoToJiffies(u64NextTS - u64NanoTS)
852e87ceabd0234ac0f9e71537c11d08e35f736cvboxsync : jiffies;
852e87ceabd0234ac0f9e71537c11d08e35f736cvboxsync spin_unlock_irqrestore(&pTimer->ChgIntLock, flFlags);
852e87ceabd0234ac0f9e71537c11d08e35f736cvboxsync
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync#ifdef CONFIG_SMP
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync if (pTimer->fSpecificCpu || pTimer->fAllCpus)
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync mod_timer_pinned(&pSubTimer->u.Std.LnxTimer, pSubTimer->u.Std.ulNextJiffies);
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync else
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync#endif
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync mod_timer(&pSubTimer->u.Std.LnxTimer, pSubTimer->u.Std.ulNextJiffies);
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync return;
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync }
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync break;
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync default:
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync AssertMsgFailed(("%d\n", enmState));
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync return;
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync }
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync ASMNopPause();
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync }
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync}
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync#ifdef CONFIG_SMP
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync/**
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync * Per-cpu callback function (RTMpOnAll/RTMpOnSpecific).
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync *
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync * @param idCpu The current CPU.
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync * @param pvUser1 Pointer to the timer.
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync * @param pvUser2 Pointer to the argument structure.
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync */
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsyncstatic DECLCALLBACK(void) rtTimerLnxStartAllOnCpu(RTCPUID idCpu, void *pvUser1, void *pvUser2)
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync{
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync PRTTIMERLINUXSTARTONCPUARGS pArgs = (PRTTIMERLINUXSTARTONCPUARGS)pvUser2;
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync PRTTIMER pTimer = (PRTTIMER)pvUser1;
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync Assert(idCpu < pTimer->cCpus);
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsync rtTimerLnxStartSubTimer(&pTimer->aSubTimers[idCpu], pArgs->u64Now, pArgs->u64First, true /*fPinned*/, pTimer->fHighRes);
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync}
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync/**
2b6e5e029d7448f21b9f8b6fb2c87b13c22b4997vboxsync * Worker for RTTimerStart() that takes care of the ugly bits.
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync *
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync * @returns RTTimerStart() return value.
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync * @param pTimer The timer.
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync * @param pArgs The argument structure.
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync */
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsyncstatic int rtTimerLnxOmniStart(PRTTIMER pTimer, PRTTIMERLINUXSTARTONCPUARGS pArgs)
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync{
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync RTCPUID iCpu;
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync RTCPUSET OnlineSet;
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync RTCPUSET OnlineSet2;
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync int rc2;
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync /*
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync * Prepare all the sub-timers for the startup and then flag the timer
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync * as a whole as non-suspended, make sure we get them all before
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync * clearing fSuspended as the MP handler will be waiting on this
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync * should something happen while we're looping.
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync */
f0ed7ab5e7f8d2f73b5aa08e46eb3a04cbb31cb2vboxsync RTSpinlockAcquire(pTimer->hSpinlock);
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync /* Just make it a omni timer restriction that no stop/start races are allowed. */
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync for (iCpu = 0; iCpu < pTimer->cCpus; iCpu++)
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync if (rtTimerLnxGetState(&pTimer->aSubTimers[iCpu].enmState) != RTTIMERLNXSTATE_STOPPED)
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync {
f0ed7ab5e7f8d2f73b5aa08e46eb3a04cbb31cb2vboxsync RTSpinlockRelease(pTimer->hSpinlock);
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync return VERR_TIMER_BUSY;
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync }
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync do
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync {
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync RTMpGetOnlineSet(&OnlineSet);
affcf9ad9ceb4b20938f02dd7cd284b4aaf6b5bbvboxsync for (iCpu = 0; iCpu < pTimer->cCpus; iCpu++)
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync {
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync Assert(pTimer->aSubTimers[iCpu].enmState != RTTIMERLNXSTATE_MP_STOPPING);
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync rtTimerLnxSetState(&pTimer->aSubTimers[iCpu].enmState,
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync RTCpuSetIsMember(&OnlineSet, iCpu)
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync ? RTTIMERLNXSTATE_STARTING
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync : RTTIMERLNXSTATE_STOPPED);
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync }
67c73271505adae0686ddbc74eaeef778ef16792vboxsync } while (!RTCpuSetIsEqual(&OnlineSet, RTMpGetOnlineSet(&OnlineSet2)));
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync ASMAtomicWriteBool(&pTimer->fSuspended, false);
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync
f0ed7ab5e7f8d2f73b5aa08e46eb3a04cbb31cb2vboxsync RTSpinlockRelease(pTimer->hSpinlock);
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync /*
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync * Start them (can't find any exported function that allows me to
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync * do this without the cross calls).
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync */
852e87ceabd0234ac0f9e71537c11d08e35f736cvboxsync pArgs->u64Now = RTTimeSystemNanoTS();
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync rc2 = RTMpOnAll(rtTimerLnxStartAllOnCpu, pTimer, pArgs);
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync AssertRC(rc2); /* screw this if it fails. */
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync /*
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync * Reset the sub-timers who didn't start up (ALL CPUs case).
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync */
f0ed7ab5e7f8d2f73b5aa08e46eb3a04cbb31cb2vboxsync RTSpinlockAcquire(pTimer->hSpinlock);
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync
affcf9ad9ceb4b20938f02dd7cd284b4aaf6b5bbvboxsync for (iCpu = 0; iCpu < pTimer->cCpus; iCpu++)
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync if (rtTimerLnxCmpXchgState(&pTimer->aSubTimers[iCpu].enmState, RTTIMERLNXSTATE_STOPPED, RTTIMERLNXSTATE_STARTING))
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync {
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync /** @todo very odd case for a rainy day. Cpus that temporarily went offline while
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync * we were between calls needs to nudged as the MP handler will ignore events for
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync * them because of the STARTING state. This is an extremely unlikely case - not that
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync * that means anything in my experience... ;-) */
951d1da36c2120dd8bf59a3b57800f8429dcd387vboxsync RTTIMERLNX_LOG(("what!? iCpu=%u -> didn't start\n", iCpu));
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync }
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync
f0ed7ab5e7f8d2f73b5aa08e46eb3a04cbb31cb2vboxsync RTSpinlockRelease(pTimer->hSpinlock);
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync return VINF_SUCCESS;
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync}
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync/**
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync * Worker for RTTimerStop() that takes care of the ugly SMP bits.
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync *
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync * @returns true if there was any active callbacks, false if not.
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync * @param pTimer The timer (valid).
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync * @param fForDestroy Whether this is for RTTimerDestroy or not.
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync */
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsyncstatic bool rtTimerLnxOmniStop(PRTTIMER pTimer, bool fForDestroy)
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync{
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync bool fActiveCallbacks = false;
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync RTCPUID iCpu;
10f0e3bfdb61e7bae30a1a1d9c17659a908c3d37vboxsync RTTIMERLNXSTATE enmState;
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync /*
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync * Mark the timer as suspended and flag all timers as stopping, except
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync * for those being stopped by an MP event.
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync */
f0ed7ab5e7f8d2f73b5aa08e46eb3a04cbb31cb2vboxsync RTSpinlockAcquire(pTimer->hSpinlock);
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync ASMAtomicWriteBool(&pTimer->fSuspended, true);
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync for (iCpu = 0; iCpu < pTimer->cCpus; iCpu++)
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync {
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync for (;;)
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync {
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync enmState = rtTimerLnxGetState(&pTimer->aSubTimers[iCpu].enmState);
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync if ( enmState == RTTIMERLNXSTATE_STOPPED
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync || enmState == RTTIMERLNXSTATE_MP_STOPPING)
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync break;
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync if ( enmState == RTTIMERLNXSTATE_CALLBACK
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync || enmState == RTTIMERLNXSTATE_CB_STOPPING
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync || enmState == RTTIMERLNXSTATE_CB_RESTARTING)
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync {
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync Assert(enmState != RTTIMERLNXSTATE_CB_STOPPING || fForDestroy);
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync if (rtTimerLnxCmpXchgState(&pTimer->aSubTimers[iCpu].enmState,
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync !fForDestroy ? RTTIMERLNXSTATE_CB_STOPPING : RTTIMERLNXSTATE_CB_DESTROYING,
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync enmState))
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync {
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync fActiveCallbacks = true;
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync break;
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync }
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync }
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync else
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync {
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync Assert(enmState == RTTIMERLNXSTATE_ACTIVE);
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync if (rtTimerLnxCmpXchgState(&pTimer->aSubTimers[iCpu].enmState, RTTIMERLNXSTATE_STOPPING, enmState))
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync break;
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync }
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync ASMNopPause();
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync }
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync }
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync
f0ed7ab5e7f8d2f73b5aa08e46eb3a04cbb31cb2vboxsync RTSpinlockRelease(pTimer->hSpinlock);
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync /*
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync * Do the actual stopping. Fortunately, this doesn't require any IPIs.
10f0e3bfdb61e7bae30a1a1d9c17659a908c3d37vboxsync * Unfortunately it cannot be done synchronously.
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync */
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync for (iCpu = 0; iCpu < pTimer->cCpus; iCpu++)
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync if (rtTimerLnxGetState(&pTimer->aSubTimers[iCpu].enmState) == RTTIMERLNXSTATE_STOPPING)
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync rtTimerLnxStopSubTimer(&pTimer->aSubTimers[iCpu], pTimer->fHighRes);
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync return fActiveCallbacks;
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync}
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync/**
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync * Per-cpu callback function (RTMpOnSpecific) used by rtTimerLinuxMpEvent()
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync * to start a sub-timer on a cpu that just have come online.
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync *
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync * @param idCpu The current CPU.
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync * @param pvUser1 Pointer to the timer.
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync * @param pvUser2 Pointer to the argument structure.
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync */
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsyncstatic DECLCALLBACK(void) rtTimerLinuxMpStartOnCpu(RTCPUID idCpu, void *pvUser1, void *pvUser2)
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync{
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync PRTTIMERLINUXSTARTONCPUARGS pArgs = (PRTTIMERLINUXSTARTONCPUARGS)pvUser2;
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync PRTTIMER pTimer = (PRTTIMER)pvUser1;
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync RTSPINLOCK hSpinlock;
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync Assert(idCpu < pTimer->cCpus);
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync /*
0f77dc54d7ec617480988ccdfcd080f480e79698vboxsync * We have to be kind of careful here as we might be racing RTTimerStop
0f77dc54d7ec617480988ccdfcd080f480e79698vboxsync * (and/or RTTimerDestroy, thus the paranoia.
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync */
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync hSpinlock = pTimer->hSpinlock;
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync if ( hSpinlock != NIL_RTSPINLOCK
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync && pTimer->u32Magic == RTTIMER_MAGIC)
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync {
f0ed7ab5e7f8d2f73b5aa08e46eb3a04cbb31cb2vboxsync RTSpinlockAcquire(hSpinlock);
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync
0f77dc54d7ec617480988ccdfcd080f480e79698vboxsync if ( !ASMAtomicUoReadBool(&pTimer->fSuspended)
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync && pTimer->u32Magic == RTTIMER_MAGIC)
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync {
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync /* We're sane and the timer is not suspended yet. */
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync PRTTIMERLNXSUBTIMER pSubTimer = &pTimer->aSubTimers[idCpu];
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync if (rtTimerLnxCmpXchgState(&pSubTimer->enmState, RTTIMERLNXSTATE_MP_STARTING, RTTIMERLNXSTATE_STOPPED))
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsync rtTimerLnxStartSubTimer(pSubTimer, pArgs->u64Now, pArgs->u64First, true /*fPinned*/, pTimer->fHighRes);
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync }
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync
f0ed7ab5e7f8d2f73b5aa08e46eb3a04cbb31cb2vboxsync RTSpinlockRelease(hSpinlock);
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync }
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync}
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync/**
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync * MP event notification callback.
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync *
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync * @param enmEvent The event.
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync * @param idCpu The cpu it applies to.
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync * @param pvUser The timer.
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync */
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsyncstatic DECLCALLBACK(void) rtTimerLinuxMpEvent(RTMPEVENT enmEvent, RTCPUID idCpu, void *pvUser)
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync{
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync PRTTIMER pTimer = (PRTTIMER)pvUser;
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync PRTTIMERLNXSUBTIMER pSubTimer = &pTimer->aSubTimers[idCpu];
8e2e6c9f8f2157e3ec6599f87343bdc453734c4cvboxsync RTSPINLOCK hSpinlock;
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync Assert(idCpu < pTimer->cCpus);
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync /*
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync * Some initial paranoia.
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync */
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync if (pTimer->u32Magic != RTTIMER_MAGIC)
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync return;
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync hSpinlock = pTimer->hSpinlock;
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync if (hSpinlock == NIL_RTSPINLOCK)
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync return;
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync
f0ed7ab5e7f8d2f73b5aa08e46eb3a04cbb31cb2vboxsync RTSpinlockAcquire(hSpinlock);
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync /* Is it active? */
0f77dc54d7ec617480988ccdfcd080f480e79698vboxsync if ( !ASMAtomicUoReadBool(&pTimer->fSuspended)
0f77dc54d7ec617480988ccdfcd080f480e79698vboxsync && pTimer->u32Magic == RTTIMER_MAGIC)
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync {
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync switch (enmEvent)
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync {
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync /*
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync * Try do it without leaving the spin lock, but if we have to, retake it
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync * when we're on the right cpu.
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync */
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync case RTMPEVENT_ONLINE:
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync if (rtTimerLnxCmpXchgState(&pSubTimer->enmState, RTTIMERLNXSTATE_MP_STARTING, RTTIMERLNXSTATE_STOPPED))
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync {
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync RTTIMERLINUXSTARTONCPUARGS Args;
852e87ceabd0234ac0f9e71537c11d08e35f736cvboxsync Args.u64Now = RTTimeSystemNanoTS();
0f77dc54d7ec617480988ccdfcd080f480e79698vboxsync Args.u64First = 0;
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync if (RTMpCpuId() == idCpu)
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsync rtTimerLnxStartSubTimer(pSubTimer, Args.u64Now, Args.u64First, true /*fPinned*/, pTimer->fHighRes);
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync else
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync {
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync rtTimerLnxSetState(&pSubTimer->enmState, RTTIMERLNXSTATE_STOPPED); /* we'll recheck it. */
f0ed7ab5e7f8d2f73b5aa08e46eb3a04cbb31cb2vboxsync RTSpinlockRelease(hSpinlock);
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync RTMpOnSpecific(idCpu, rtTimerLinuxMpStartOnCpu, pTimer, &Args);
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync return; /* we've left the spinlock */
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync }
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync }
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync break;
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync /*
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync * The CPU is (going) offline, make sure the sub-timer is stopped.
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync *
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync * Linux will migrate it to a different CPU, but we don't want this. The
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync * timer function is checking for this.
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync */
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync case RTMPEVENT_OFFLINE:
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync {
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync RTTIMERLNXSTATE enmState;
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync while ( (enmState = rtTimerLnxGetState(&pSubTimer->enmState)) == RTTIMERLNXSTATE_ACTIVE
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync || enmState == RTTIMERLNXSTATE_CALLBACK
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync || enmState == RTTIMERLNXSTATE_CB_RESTARTING)
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync {
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync if (enmState == RTTIMERLNXSTATE_ACTIVE)
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync {
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync if (rtTimerLnxCmpXchgState(&pSubTimer->enmState, RTTIMERLNXSTATE_MP_STOPPING, RTTIMERLNXSTATE_ACTIVE))
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync {
f0ed7ab5e7f8d2f73b5aa08e46eb3a04cbb31cb2vboxsync RTSpinlockRelease(hSpinlock);
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync rtTimerLnxStopSubTimer(pSubTimer, pTimer->fHighRes);
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync return; /* we've left the spinlock */
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync }
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync }
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync else if (rtTimerLnxCmpXchgState(&pSubTimer->enmState, RTTIMERLNXSTATE_CB_STOPPING, enmState))
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync break;
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync /* State not stable, try again. */
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync ASMNopPause();
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync }
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync break;
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync }
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync }
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync }
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync
f0ed7ab5e7f8d2f73b5aa08e46eb3a04cbb31cb2vboxsync RTSpinlockRelease(hSpinlock);
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync}
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync
ae41886ba231ade1b868dd32ff24ee49813ebbabvboxsync#endif /* CONFIG_SMP */
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsync
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsync
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsync/**
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync * Callback function use by RTTimerStart via RTMpOnSpecific to start a timer
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync * running on a specific CPU.
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsync *
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsync * @param idCpu The current CPU.
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsync * @param pvUser1 Pointer to the timer.
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsync * @param pvUser2 Pointer to the argument structure.
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsync */
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsyncstatic DECLCALLBACK(void) rtTimerLnxStartOnSpecificCpu(RTCPUID idCpu, void *pvUser1, void *pvUser2)
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsync{
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsync PRTTIMERLINUXSTARTONCPUARGS pArgs = (PRTTIMERLINUXSTARTONCPUARGS)pvUser2;
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsync PRTTIMER pTimer = (PRTTIMER)pvUser1;
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsync rtTimerLnxStartSubTimer(&pTimer->aSubTimers[0], pArgs->u64Now, pArgs->u64First, true /*fPinned*/, pTimer->fHighRes);
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsync}
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsync
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsync
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsyncRTDECL(int) RTTimerStart(PRTTIMER pTimer, uint64_t u64First)
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsync{
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsync RTTIMERLINUXSTARTONCPUARGS Args;
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsync int rc2;
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsync
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsync /*
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsync * Validate.
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsync */
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsync AssertPtrReturn(pTimer, VERR_INVALID_HANDLE);
b377a71756cce9f39d25b561f72bfa33ce8a39devboxsync AssertReturn(pTimer->u32Magic == RTTIMER_MAGIC, VERR_INVALID_HANDLE);
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsync
0f77dc54d7ec617480988ccdfcd080f480e79698vboxsync if (!ASMAtomicUoReadBool(&pTimer->fSuspended))
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsync return VERR_TIMER_ACTIVE;
951d1da36c2120dd8bf59a3b57800f8429dcd387vboxsync RTTIMERLNX_LOG(("start %p cCpus=%d\n", pTimer, pTimer->cCpus));
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsync
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsync Args.u64First = u64First;
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsync#ifdef CONFIG_SMP
0f77dc54d7ec617480988ccdfcd080f480e79698vboxsync /*
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync * Omni timer?
0f77dc54d7ec617480988ccdfcd080f480e79698vboxsync */
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsync if (pTimer->fAllCpus)
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync return rtTimerLnxOmniStart(pTimer, &Args);
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsync#endif
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsync
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsync /*
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync * Simple timer - Pretty straight forward if it wasn't for restarting.
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsync */
852e87ceabd0234ac0f9e71537c11d08e35f736cvboxsync Args.u64Now = RTTimeSystemNanoTS();
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync ASMAtomicWriteU64(&pTimer->aSubTimers[0].uNsRestartAt, Args.u64Now + u64First);
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync for (;;)
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsync {
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync RTTIMERLNXSTATE enmState = rtTimerLnxGetState(&pTimer->aSubTimers[0].enmState);
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync switch (enmState)
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsync {
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync case RTTIMERLNXSTATE_STOPPED:
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync if (rtTimerLnxCmpXchgState(&pTimer->aSubTimers[0].enmState, RTTIMERLNXSTATE_STARTING, RTTIMERLNXSTATE_STOPPED))
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync {
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync ASMAtomicWriteBool(&pTimer->fSuspended, false);
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync if (!pTimer->fSpecificCpu)
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync rtTimerLnxStartSubTimer(&pTimer->aSubTimers[0], Args.u64Now, Args.u64First,
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync false /*fPinned*/, pTimer->fHighRes);
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync else
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync {
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync rc2 = RTMpOnSpecific(pTimer->idCpu, rtTimerLnxStartOnSpecificCpu, pTimer, &Args);
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync if (RT_FAILURE(rc2))
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync {
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync /* Suspend it, the cpu id is probably invalid or offline. */
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync ASMAtomicWriteBool(&pTimer->fSuspended, true);
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync rtTimerLnxSetState(&pTimer->aSubTimers[0].enmState, RTTIMERLNXSTATE_STOPPED);
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync return rc2;
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync }
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync }
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync return VINF_SUCCESS;
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync }
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync break;
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync case RTTIMERLNXSTATE_CALLBACK:
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync case RTTIMERLNXSTATE_CB_STOPPING:
9edbe160de7266b3b5d54ccf2f07ed95f9f40c6bvboxsync if (rtTimerLnxCmpXchgState(&pTimer->aSubTimers[0].enmState, RTTIMERLNXSTATE_CB_RESTARTING, enmState))
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync {
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync ASMAtomicWriteBool(&pTimer->fSuspended, false);
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync return VINF_SUCCESS;
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync }
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync break;
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync default:
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync AssertMsgFailed(("%d\n", enmState));
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync return VERR_INTERNAL_ERROR_4;
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsync }
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync ASMNopPause();
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsync }
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsync}
aa4bcf0a4b2db3ac352b56a291d49cb8d4b66d32vboxsyncRT_EXPORT_SYMBOL(RTTimerStart);
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsync
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsync
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync/**
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync * Common worker for RTTimerStop and RTTimerDestroy.
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync *
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync * @returns true if there was any active callbacks, false if not.
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync * @param pTimer The timer to stop.
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync * @param fForDestroy Whether it's RTTimerDestroy calling or not.
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync */
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsyncstatic bool rtTimerLnxStop(PRTTIMER pTimer, bool fForDestroy)
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsync{
951d1da36c2120dd8bf59a3b57800f8429dcd387vboxsync RTTIMERLNX_LOG(("lnxstop %p %d\n", pTimer, fForDestroy));
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsync#ifdef CONFIG_SMP
0f77dc54d7ec617480988ccdfcd080f480e79698vboxsync /*
0f77dc54d7ec617480988ccdfcd080f480e79698vboxsync * Omni timer?
0f77dc54d7ec617480988ccdfcd080f480e79698vboxsync */
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsync if (pTimer->fAllCpus)
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync return rtTimerLnxOmniStop(pTimer, fForDestroy);
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsync#endif
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsync
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsync /*
0f77dc54d7ec617480988ccdfcd080f480e79698vboxsync * Simple timer.
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsync */
0f77dc54d7ec617480988ccdfcd080f480e79698vboxsync ASMAtomicWriteBool(&pTimer->fSuspended, true);
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync for (;;)
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync {
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync RTTIMERLNXSTATE enmState = rtTimerLnxGetState(&pTimer->aSubTimers[0].enmState);
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync switch (enmState)
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync {
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync case RTTIMERLNXSTATE_ACTIVE:
852e87ceabd0234ac0f9e71537c11d08e35f736cvboxsync if (rtTimerLnxCmpXchgState(&pTimer->aSubTimers[0].enmState, RTTIMERLNXSTATE_STOPPING, RTTIMERLNXSTATE_ACTIVE))
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync {
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync rtTimerLnxStopSubTimer(&pTimer->aSubTimers[0], pTimer->fHighRes);
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync return false;
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync }
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync break;
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync case RTTIMERLNXSTATE_CALLBACK:
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync case RTTIMERLNXSTATE_CB_RESTARTING:
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync case RTTIMERLNXSTATE_CB_STOPPING:
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync Assert(enmState != RTTIMERLNXSTATE_CB_STOPPING || fForDestroy);
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync if (rtTimerLnxCmpXchgState(&pTimer->aSubTimers[0].enmState,
852e87ceabd0234ac0f9e71537c11d08e35f736cvboxsync !fForDestroy ? RTTIMERLNXSTATE_CB_STOPPING : RTTIMERLNXSTATE_CB_DESTROYING,
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync enmState))
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync return true;
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync break;
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync case RTTIMERLNXSTATE_STOPPED:
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync return VINF_SUCCESS;
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync case RTTIMERLNXSTATE_CB_DESTROYING:
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync AssertMsgFailed(("enmState=%d pTimer=%p\n", enmState, pTimer));
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync return true;
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync default:
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync case RTTIMERLNXSTATE_STARTING:
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync case RTTIMERLNXSTATE_MP_STARTING:
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync case RTTIMERLNXSTATE_STOPPING:
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync case RTTIMERLNXSTATE_MP_STOPPING:
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync AssertMsgFailed(("enmState=%d pTimer=%p\n", enmState, pTimer));
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync return false;
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync }
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync /* State not stable, try again. */
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync ASMNopPause();
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync }
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync}
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsyncRTDECL(int) RTTimerStop(PRTTIMER pTimer)
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync{
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync /*
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync * Validate.
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync */
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync AssertPtrReturn(pTimer, VERR_INVALID_HANDLE);
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync AssertReturn(pTimer->u32Magic == RTTIMER_MAGIC, VERR_INVALID_HANDLE);
951d1da36c2120dd8bf59a3b57800f8429dcd387vboxsync RTTIMERLNX_LOG(("stop %p\n", pTimer));
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsync
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync if (ASMAtomicUoReadBool(&pTimer->fSuspended))
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync return VERR_TIMER_SUSPENDED;
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync rtTimerLnxStop(pTimer, false /*fForDestroy*/);
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsync return VINF_SUCCESS;
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsync}
aa4bcf0a4b2db3ac352b56a291d49cb8d4b66d32vboxsyncRT_EXPORT_SYMBOL(RTTimerStop);
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsync
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsync
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsyncRTDECL(int) RTTimerChangeInterval(PRTTIMER pTimer, uint64_t u64NanoInterval)
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsync{
852e87ceabd0234ac0f9e71537c11d08e35f736cvboxsync unsigned long cJiffies;
852e87ceabd0234ac0f9e71537c11d08e35f736cvboxsync unsigned long flFlags;
852e87ceabd0234ac0f9e71537c11d08e35f736cvboxsync
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsync /*
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsync * Validate.
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsync */
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsync AssertPtrReturn(pTimer, VERR_INVALID_HANDLE);
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsync AssertReturn(pTimer->u32Magic == RTTIMER_MAGIC, VERR_INVALID_HANDLE);
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsync AssertReturn(u64NanoInterval, VERR_INVALID_PARAMETER);
1f17427b60832e237f8277e1aef8cae3b441f52avboxsync AssertReturn(u64NanoInterval < UINT64_MAX / 8, VERR_INVALID_PARAMETER);
1f17427b60832e237f8277e1aef8cae3b441f52avboxsync AssertReturn(pTimer->u64NanoInterval, VERR_INVALID_STATE);
951d1da36c2120dd8bf59a3b57800f8429dcd387vboxsync RTTIMERLNX_LOG(("change %p %llu\n", pTimer, u64NanoInterval));
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsync
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync#ifdef RTTIMER_LINUX_WITH_HRTIMER
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsync /*
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync * For the high resolution timers it is easy since we don't care so much
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync * about when it is applied to the sub-timers.
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsync */
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsync if (pTimer->fHighRes)
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync {
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsync ASMAtomicWriteU64(&pTimer->u64NanoInterval, u64NanoInterval);
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync return VINF_SUCCESS;
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync }
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsync#endif
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsync
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync /*
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync * Standard timers have a bit more complicated way of calculating
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync * their interval and such. So, forget omni timers for now.
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync */
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync if (pTimer->cCpus > 1)
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync return VERR_NOT_SUPPORTED;
852e87ceabd0234ac0f9e71537c11d08e35f736cvboxsync
852e87ceabd0234ac0f9e71537c11d08e35f736cvboxsync cJiffies = u64NanoInterval / RTTimerGetSystemGranularity();
852e87ceabd0234ac0f9e71537c11d08e35f736cvboxsync if (cJiffies * RTTimerGetSystemGranularity() != u64NanoInterval)
852e87ceabd0234ac0f9e71537c11d08e35f736cvboxsync cJiffies = 0;
852e87ceabd0234ac0f9e71537c11d08e35f736cvboxsync
852e87ceabd0234ac0f9e71537c11d08e35f736cvboxsync spin_lock_irqsave(&pTimer->ChgIntLock, flFlags);
852e87ceabd0234ac0f9e71537c11d08e35f736cvboxsync pTimer->aSubTimers[0].u.Std.fFirstAfterChg = true;
852e87ceabd0234ac0f9e71537c11d08e35f736cvboxsync pTimer->cJiffies = cJiffies;
852e87ceabd0234ac0f9e71537c11d08e35f736cvboxsync ASMAtomicWriteU64(&pTimer->u64NanoInterval, u64NanoInterval);
852e87ceabd0234ac0f9e71537c11d08e35f736cvboxsync spin_unlock_irqrestore(&pTimer->ChgIntLock, flFlags);
852e87ceabd0234ac0f9e71537c11d08e35f736cvboxsync return VINF_SUCCESS;
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsync}
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsyncRT_EXPORT_SYMBOL(RTTimerChangeInterval);
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsync
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsync
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsyncRTDECL(int) RTTimerDestroy(PRTTIMER pTimer)
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsync{
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync bool fCanDestroy;
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsync
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync /*
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync * Validate. It's ok to pass NULL pointer.
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync */
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsync if (pTimer == /*NIL_RTTIMER*/ NULL)
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsync return VINF_SUCCESS;
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsync AssertPtrReturn(pTimer, VERR_INVALID_HANDLE);
b377a71756cce9f39d25b561f72bfa33ce8a39devboxsync AssertReturn(pTimer->u32Magic == RTTIMER_MAGIC, VERR_INVALID_HANDLE);
951d1da36c2120dd8bf59a3b57800f8429dcd387vboxsync RTTIMERLNX_LOG(("destroy %p\n", pTimer));
7202d537edf6d2c5fc2c26bade6855541c675fa0vboxsync/** @todo We should invalidate the magic here! */
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsync
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsync /*
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync * Stop the timer if it's still active, then destroy it if we can.
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsync */
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync if (!ASMAtomicUoReadBool(&pTimer->fSuspended))
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync fCanDestroy = rtTimerLnxStop(pTimer, true /*fForDestroy*/);
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync else
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsync {
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync uint32_t iCpu = pTimer->cCpus;
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync if (pTimer->cCpus > 1)
f0ed7ab5e7f8d2f73b5aa08e46eb3a04cbb31cb2vboxsync RTSpinlockAcquire(pTimer->hSpinlock);
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsync
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync fCanDestroy = true;
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync while (iCpu-- > 0)
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync {
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync for (;;)
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync {
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync RTTIMERLNXSTATE enmState = rtTimerLnxGetState(&pTimer->aSubTimers[iCpu].enmState);
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync switch (enmState)
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync {
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync case RTTIMERLNXSTATE_CALLBACK:
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync case RTTIMERLNXSTATE_CB_RESTARTING:
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync case RTTIMERLNXSTATE_CB_STOPPING:
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync if (!rtTimerLnxCmpXchgState(&pTimer->aSubTimers[iCpu].enmState, RTTIMERLNXSTATE_CB_DESTROYING, enmState))
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync continue;
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync fCanDestroy = false;
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync break;
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync case RTTIMERLNXSTATE_CB_DESTROYING:
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync AssertMsgFailed(("%d\n", enmState));
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync fCanDestroy = false;
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync break;
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync default:
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync break;
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync }
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync break;
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync }
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync }
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsync
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync if (pTimer->cCpus > 1)
c0b6af690ad705bddfa87c643b89770a7a0aaf5avboxsync RTSpinlockRelease(pTimer->hSpinlock);
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync }
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync if (fCanDestroy)
7202d537edf6d2c5fc2c26bade6855541c675fa0vboxsync {
7202d537edf6d2c5fc2c26bade6855541c675fa0vboxsync /* For paranoid reasons, defer actually destroying the semaphore when
7202d537edf6d2c5fc2c26bade6855541c675fa0vboxsync in atomic or interrupt context. */
e9e12792a48d30217ce62abc9051b4fdd55e7fa1vboxsync#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 32)
7202d537edf6d2c5fc2c26bade6855541c675fa0vboxsync if (in_atomic() || in_interrupt())
e9e12792a48d30217ce62abc9051b4fdd55e7fa1vboxsync#else
e9e12792a48d30217ce62abc9051b4fdd55e7fa1vboxsync if (in_interrupt())
e9e12792a48d30217ce62abc9051b4fdd55e7fa1vboxsync#endif
7202d537edf6d2c5fc2c26bade6855541c675fa0vboxsync rtR0LnxWorkqueuePush(&pTimer->DtorWorkqueueItem, rtTimerLnxDestroyDeferred);
7202d537edf6d2c5fc2c26bade6855541c675fa0vboxsync else
7202d537edf6d2c5fc2c26bade6855541c675fa0vboxsync rtTimerLnxDestroyIt(pTimer);
7202d537edf6d2c5fc2c26bade6855541c675fa0vboxsync }
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsync
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsync return VINF_SUCCESS;
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsync}
aa4bcf0a4b2db3ac352b56a291d49cb8d4b66d32vboxsyncRT_EXPORT_SYMBOL(RTTimerDestroy);
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsync
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsync
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsyncRTDECL(int) RTTimerCreateEx(PRTTIMER *ppTimer, uint64_t u64NanoInterval, uint32_t fFlags, PFNRTTIMER pfnTimer, void *pvUser)
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsync{
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsync PRTTIMER pTimer;
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsync RTCPUID iCpu;
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsync unsigned cCpus;
25c97a3e3ce2710f95faa6d181486df26b518e74vboxsync int rc;
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsync
10f0e3bfdb61e7bae30a1a1d9c17659a908c3d37vboxsync rtR0LnxWorkqueueFlush(); /* for 2.4 */
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsync *ppTimer = NULL;
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsync
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsync /*
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsync * Validate flags.
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsync */
0f77dc54d7ec617480988ccdfcd080f480e79698vboxsync if (!RTTIMER_FLAGS_ARE_VALID(fFlags))
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsync return VERR_INVALID_PARAMETER;
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsync if ( (fFlags & RTTIMER_FLAGS_CPU_SPECIFIC)
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsync && (fFlags & RTTIMER_FLAGS_CPU_ALL) != RTTIMER_FLAGS_CPU_ALL
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsync && !RTMpIsCpuPossible(RTMpCpuIdFromSetIndex(fFlags & RTTIMER_FLAGS_CPU_MASK)))
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsync return VERR_CPU_NOT_FOUND;
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsync
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsync /*
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsync * Allocate the timer handler.
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsync */
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsync cCpus = 1;
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsync#ifdef CONFIG_SMP
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsync if ((fFlags & RTTIMER_FLAGS_CPU_ALL) == RTTIMER_FLAGS_CPU_ALL)
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsync {
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsync cCpus = RTMpGetMaxCpuId() + 1;
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsync Assert(cCpus <= RTCPUSET_MAX_CPUS); /* On linux we have a 1:1 relationship between cpuid and set index. */
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsync AssertReturn(u64NanoInterval, VERR_NOT_IMPLEMENTED); /* We don't implement single shot on all cpus, sorry. */
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsync }
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsync#endif
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsync
25c97a3e3ce2710f95faa6d181486df26b518e74vboxsync rc = RTMemAllocEx(RT_OFFSETOF(RTTIMER, aSubTimers[cCpus]), 0,
25c97a3e3ce2710f95faa6d181486df26b518e74vboxsync RTMEMALLOCEX_FLAGS_ZEROED | RTMEMALLOCEX_FLAGS_ANY_CTX_FREE, (void **)&pTimer);
25c97a3e3ce2710f95faa6d181486df26b518e74vboxsync if (RT_FAILURE(rc))
25c97a3e3ce2710f95faa6d181486df26b518e74vboxsync return rc;
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsync
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsync /*
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsync * Initialize it.
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsync */
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync pTimer->u32Magic = RTTIMER_MAGIC;
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync pTimer->hSpinlock = NIL_RTSPINLOCK;
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync pTimer->fSuspended = true;
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync pTimer->fHighRes = !!(fFlags & RTTIMER_FLAGS_HIGH_RES);
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsync#ifdef CONFIG_SMP
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync pTimer->fSpecificCpu = (fFlags & RTTIMER_FLAGS_CPU_SPECIFIC) && (fFlags & RTTIMER_FLAGS_CPU_ALL) != RTTIMER_FLAGS_CPU_ALL;
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync pTimer->fAllCpus = (fFlags & RTTIMER_FLAGS_CPU_ALL) == RTTIMER_FLAGS_CPU_ALL;
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync pTimer->idCpu = pTimer->fSpecificCpu
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync ? RTMpCpuIdFromSetIndex(fFlags & RTTIMER_FLAGS_CPU_MASK)
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync : NIL_RTCPUID;
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsync#else
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync pTimer->fSpecificCpu = !!(fFlags & RTTIMER_FLAGS_CPU_SPECIFIC);
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync pTimer->idCpu = RTMpCpuId();
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsync#endif
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync pTimer->cCpus = cCpus;
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync pTimer->pfnTimer = pfnTimer;
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync pTimer->pvUser = pvUser;
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsync pTimer->u64NanoInterval = u64NanoInterval;
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync pTimer->cJiffies = u64NanoInterval / RTTimerGetSystemGranularity();
4aafb1203580a5c145a7bdae57ebf69a36fa4f01vboxsync if (pTimer->cJiffies * RTTimerGetSystemGranularity() != u64NanoInterval)
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync pTimer->cJiffies = 0;
852e87ceabd0234ac0f9e71537c11d08e35f736cvboxsync spin_lock_init(&pTimer->ChgIntLock);
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsync
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsync for (iCpu = 0; iCpu < cCpus; iCpu++)
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsync {
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsync#ifdef RTTIMER_LINUX_WITH_HRTIMER
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsync if (pTimer->fHighRes)
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsync {
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsync hrtimer_init(&pTimer->aSubTimers[iCpu].u.Hr.LnxTimer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS);
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync pTimer->aSubTimers[iCpu].u.Hr.LnxTimer.function = rtTimerLinuxHrCallback;
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsync }
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsync else
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsync#endif
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsync {
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsync init_timer(&pTimer->aSubTimers[iCpu].u.Std.LnxTimer);
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync pTimer->aSubTimers[iCpu].u.Std.LnxTimer.data = (unsigned long)&pTimer->aSubTimers[iCpu];
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync pTimer->aSubTimers[iCpu].u.Std.LnxTimer.function = rtTimerLinuxStdCallback;
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync pTimer->aSubTimers[iCpu].u.Std.LnxTimer.expires = jiffies;
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync pTimer->aSubTimers[iCpu].u.Std.u64NextTS = 0;
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsync }
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync pTimer->aSubTimers[iCpu].iTick = 0;
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync pTimer->aSubTimers[iCpu].pParent = pTimer;
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync pTimer->aSubTimers[iCpu].enmState = RTTIMERLNXSTATE_STOPPED;
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsync }
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsync
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsync#ifdef CONFIG_SMP
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsync /*
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsync * If this is running on ALL cpus, we'll have to register a callback
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsync * for MP events (so timers can be started/stopped on cpus going
ad27e1d5e48ca41245120c331cc88b50464813cevboxsync * online/offline). We also create the spinlock for synchronizing
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsync * stop/start/mp-event.
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsync */
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsync if (cCpus > 1)
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsync {
4b65b0b7127fe2f685bb5c3319f803a16b84ee6cvboxsync int rc = RTSpinlockCreate(&pTimer->hSpinlock, RTSPINLOCK_FLAGS_INTERRUPT_SAFE, "RTTimerLnx");
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsync if (RT_SUCCESS(rc))
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsync rc = RTMpNotificationRegister(rtTimerLinuxMpEvent, pTimer);
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsync else
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsync pTimer->hSpinlock = NIL_RTSPINLOCK;
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsync if (RT_FAILURE(rc))
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsync {
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsync RTTimerDestroy(pTimer);
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsync return rc;
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsync }
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsync }
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsync#endif /* CONFIG_SMP */
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsync
951d1da36c2120dd8bf59a3b57800f8429dcd387vboxsync RTTIMERLNX_LOG(("create %p hires=%d fFlags=%#x cCpus=%u\n", pTimer, pTimer->fHighRes, fFlags, cCpus));
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsync *ppTimer = pTimer;
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsync return VINF_SUCCESS;
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsync}
aa4bcf0a4b2db3ac352b56a291d49cb8d4b66d32vboxsyncRT_EXPORT_SYMBOL(RTTimerCreateEx);
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsync
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsync
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsyncRTDECL(uint32_t) RTTimerGetSystemGranularity(void)
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsync{
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync#if 0 /** @todo Not sure if this is what we want or not... Add new API for
7e3ff7c4e45ee1f8eb46a1aba9d2d8816d337c4avboxsync * querying the resolution of the high res timers? */
4aafb1203580a5c145a7bdae57ebf69a36fa4f01vboxsync struct timespec Ts;
4aafb1203580a5c145a7bdae57ebf69a36fa4f01vboxsync int rc = hrtimer_get_res(CLOCK_MONOTONIC, &Ts);
4aafb1203580a5c145a7bdae57ebf69a36fa4f01vboxsync if (!rc)
4aafb1203580a5c145a7bdae57ebf69a36fa4f01vboxsync {
4aafb1203580a5c145a7bdae57ebf69a36fa4f01vboxsync Assert(!Ts.tv_sec);
4aafb1203580a5c145a7bdae57ebf69a36fa4f01vboxsync return Ts.tv_nsec;
4aafb1203580a5c145a7bdae57ebf69a36fa4f01vboxsync }
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsync#endif
caa110e2153c635d3a0910161f3532ace7600bd3vboxsync return RT_NS_1SEC / HZ; /* ns */
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsync}
aa4bcf0a4b2db3ac352b56a291d49cb8d4b66d32vboxsyncRT_EXPORT_SYMBOL(RTTimerGetSystemGranularity);
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsync
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsync
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsyncRTDECL(int) RTTimerRequestSystemGranularity(uint32_t u32Request, uint32_t *pu32Granted)
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsync{
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsync return VERR_NOT_SUPPORTED;
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsync}
aa4bcf0a4b2db3ac352b56a291d49cb8d4b66d32vboxsyncRT_EXPORT_SYMBOL(RTTimerRequestSystemGranularity);
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsync
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsync
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsyncRTDECL(int) RTTimerReleaseSystemGranularity(uint32_t u32Granted)
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsync{
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsync return VERR_NOT_SUPPORTED;
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsync}
aa4bcf0a4b2db3ac352b56a291d49cb8d4b66d32vboxsyncRT_EXPORT_SYMBOL(RTTimerReleaseSystemGranularity);
bc0c1e33e433d1276ea1606ace81f61594ee3838vboxsync
0dfc79e0666da4c8853deda18a14ebf5819d0d78vboxsync
0dfc79e0666da4c8853deda18a14ebf5819d0d78vboxsyncRTDECL(bool) RTTimerCanDoHighResolution(void)
0dfc79e0666da4c8853deda18a14ebf5819d0d78vboxsync{
0cde281779e97ead3181bbd3b628451fa2b1efe1vboxsync#ifdef RTTIMER_LINUX_WITH_HRTIMER
0dfc79e0666da4c8853deda18a14ebf5819d0d78vboxsync return true;
0dfc79e0666da4c8853deda18a14ebf5819d0d78vboxsync#else
0dfc79e0666da4c8853deda18a14ebf5819d0d78vboxsync return false;
0dfc79e0666da4c8853deda18a14ebf5819d0d78vboxsync#endif
0dfc79e0666da4c8853deda18a14ebf5819d0d78vboxsync}
0dfc79e0666da4c8853deda18a14ebf5819d0d78vboxsyncRT_EXPORT_SYMBOL(RTTimerCanDoHighResolution);
0dfc79e0666da4c8853deda18a14ebf5819d0d78vboxsync