VirtualBox

source: vbox/trunk/src/VBox/Runtime/r0drv/freebsd/timer-r0drv-freebsd.c@ 78401

Last change on this file since 78401 was 77120, checked in by vboxsync, 6 years ago

IPRT: Some license header cleanups.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 9.8 KB
Line 
1/* $Id: timer-r0drv-freebsd.c 77120 2019-02-01 15:08:46Z vboxsync $ */
2/** @file
3 * IPRT - Memory Allocation, Ring-0 Driver, FreeBSD.
4 */
5
6/*
7 * Contributed by knut st. osmundsen.
8 *
9 * Copyright (C) 2007-2019 Oracle Corporation
10 *
11 * This file is part of VirtualBox Open Source Edition (OSE), as
12 * available from http://www.virtualbox.org. This file is free software;
13 * you can redistribute it and/or modify it under the terms of the GNU
14 * General Public License (GPL) as published by the Free Software
15 * Foundation, in version 2 as it comes in the "COPYING" file of the
16 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
17 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
18 *
19 * The contents of this file may alternatively be used under the terms
20 * of the Common Development and Distribution License Version 1.0
21 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
22 * VirtualBox OSE distribution, in which case the provisions of the
23 * CDDL are applicable instead of those of the GPL.
24 *
25 * You may elect to license modified versions of this file under the
26 * terms and conditions of either the GPL or the CDDL or both.
27 *
28 * --------------------------------------------------------------------
29 *
30 * This code is based on:
31 *
32 * Copyright (c) 2007 knut st. osmundsen <[email protected]>
33 *
34 * Permission is hereby granted, free of charge, to any person
35 * obtaining a copy of this software and associated documentation
36 * files (the "Software"), to deal in the Software without
37 * restriction, including without limitation the rights to use,
38 * copy, modify, merge, publish, distribute, sublicense, and/or sell
39 * copies of the Software, and to permit persons to whom the
40 * Software is furnished to do so, subject to the following
41 * conditions:
42 *
43 * The above copyright notice and this permission notice shall be
44 * included in all copies or substantial portions of the Software.
45 *
46 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
47 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
48 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
49 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
50 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
51 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
52 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
53 * OTHER DEALINGS IN THE SOFTWARE.
54 */
55
56
57/*********************************************************************************************************************************
58* Header Files *
59*********************************************************************************************************************************/
60#include "the-freebsd-kernel.h"
61
62#include <iprt/timer.h>
63#include <iprt/time.h>
64#include <iprt/spinlock.h>
65#include <iprt/err.h>
66#include <iprt/asm.h>
67#include <iprt/assert.h>
68#include <iprt/alloc.h>
69
70#include "internal/magics.h"
71
72
73/*********************************************************************************************************************************
74* Structures and Typedefs *
75*********************************************************************************************************************************/
76/**
77 * The internal representation of an FreeBSD timer handle.
78 */
79typedef struct RTTIMER
80{
81 /** Magic.
82 * This is RTTIMER_MAGIC, but changes to something else before the timer
83 * is destroyed to indicate clearly that thread should exit. */
84 uint32_t volatile u32Magic;
85 /** Flag indicating that the timer is suspended. */
86 uint8_t volatile fSuspended;
87 /** Whether the timer must run on a specific CPU or not. */
88 uint8_t fSpecificCpu;
89 /** The CPU it must run on if fSpecificCpu is set. */
90 uint32_t iCpu;
91 /** The FreeBSD callout structure. */
92 struct callout Callout;
93 /** Callback. */
94 PFNRTTIMER pfnTimer;
95 /** User argument. */
96 void *pvUser;
97 /** The timer interval. 0 if one-shot. */
98 uint64_t u64NanoInterval;
99 /** The start of the current run.
100 * This is used to calculate when the timer ought to fire the next time. */
101 uint64_t volatile u64StartTS;
102 /** The start of the current run.
103 * This is used to calculate when the timer ought to fire the next time. */
104 uint64_t volatile u64NextTS;
105 /** The current tick number (since u64StartTS). */
106 uint64_t volatile iTick;
107} RTTIMER;
108
109
110/*********************************************************************************************************************************
111* Internal Functions *
112*********************************************************************************************************************************/
113static void rtTimerFreeBSDCallback(void *pvTimer);
114
115
116
117RTDECL(int) RTTimerCreateEx(PRTTIMER *ppTimer, uint64_t u64NanoInterval, uint32_t fFlags, PFNRTTIMER pfnTimer, void *pvUser)
118{
119 *ppTimer = NULL;
120
121 /*
122 * Validate flags.
123 */
124 if (!RTTIMER_FLAGS_ARE_VALID(fFlags))
125 return VERR_INVALID_PARAMETER;
126 if ( (fFlags & RTTIMER_FLAGS_CPU_SPECIFIC)
127 && (fFlags & RTTIMER_FLAGS_CPU_ALL) != RTTIMER_FLAGS_CPU_ALL
128 && (fFlags & RTTIMER_FLAGS_CPU_MASK) > mp_maxid)
129 return VERR_CPU_NOT_FOUND;
130
131 /*
132 * Allocate and initialize the timer handle.
133 */
134 PRTTIMER pTimer = (PRTTIMER)RTMemAlloc(sizeof(*pTimer));
135 if (!pTimer)
136 return VERR_NO_MEMORY;
137
138 pTimer->u32Magic = RTTIMER_MAGIC;
139 pTimer->fSuspended = true;
140 pTimer->fSpecificCpu = !!(fFlags & RTTIMER_FLAGS_CPU_SPECIFIC);
141 pTimer->iCpu = fFlags & RTTIMER_FLAGS_CPU_MASK;
142 pTimer->pfnTimer = pfnTimer;
143 pTimer->pvUser = pvUser;
144 pTimer->u64NanoInterval = u64NanoInterval;
145 pTimer->u64StartTS = 0;
146 callout_init(&pTimer->Callout, CALLOUT_MPSAFE);
147
148 *ppTimer = pTimer;
149 return VINF_SUCCESS;
150}
151
152
153/**
154 * Validates the timer handle.
155 *
156 * @returns true if valid, false if invalid.
157 * @param pTimer The handle.
158 */
159DECLINLINE(bool) rtTimerIsValid(PRTTIMER pTimer)
160{
161 AssertReturn(VALID_PTR(pTimer), false);
162 AssertReturn(pTimer->u32Magic == RTTIMER_MAGIC, false);
163 return true;
164}
165
166
167RTDECL(int) RTTimerDestroy(PRTTIMER pTimer)
168{
169 /* It's ok to pass NULL pointer. */
170 if (pTimer == /*NIL_RTTIMER*/ NULL)
171 return VINF_SUCCESS;
172 if (!rtTimerIsValid(pTimer))
173 return VERR_INVALID_HANDLE;
174
175 /*
176 * Free the associated resources.
177 */
178 pTimer->u32Magic++;
179 callout_stop(&pTimer->Callout);
180 RTMemFree(pTimer);
181 return VINF_SUCCESS;
182}
183
184
185RTDECL(int) RTTimerStart(PRTTIMER pTimer, uint64_t u64First)
186{
187 struct timeval tv;
188
189 if (!rtTimerIsValid(pTimer))
190 return VERR_INVALID_HANDLE;
191 if (!pTimer->fSuspended)
192 return VERR_TIMER_ACTIVE;
193 if ( pTimer->fSpecificCpu
194 && !RTMpIsCpuOnline(RTMpCpuIdFromSetIndex(pTimer->iCpu)))
195 return VERR_CPU_OFFLINE;
196
197 /*
198 * Calc when it should start firing.
199 */
200 u64First += RTTimeNanoTS();
201
202 pTimer->fSuspended = false;
203 pTimer->iTick = 0;
204 pTimer->u64StartTS = u64First;
205 pTimer->u64NextTS = u64First;
206
207 tv.tv_sec = u64First / 1000000000;
208 tv.tv_usec = (u64First % 1000000000) / 1000;
209 callout_reset(&pTimer->Callout, tvtohz(&tv), rtTimerFreeBSDCallback, pTimer);
210
211 return VINF_SUCCESS;
212}
213
214
215RTDECL(int) RTTimerStop(PRTTIMER pTimer)
216{
217 if (!rtTimerIsValid(pTimer))
218 return VERR_INVALID_HANDLE;
219 if (pTimer->fSuspended)
220 return VERR_TIMER_SUSPENDED;
221
222 /*
223 * Suspend the timer.
224 */
225 pTimer->fSuspended = true;
226 callout_stop(&pTimer->Callout);
227
228 return VINF_SUCCESS;
229}
230
231
232RTDECL(int) RTTimerChangeInterval(PRTTIMER pTimer, uint64_t u64NanoInterval)
233{
234 if (!rtTimerIsValid(pTimer))
235 return VERR_INVALID_HANDLE;
236 return VERR_NOT_SUPPORTED;
237}
238
239
240/**
241 * smp_rendezvous action callback.
242 *
243 * This will perform the timer callback if we're on the right CPU.
244 *
245 * @param pvTimer The timer.
246 */
247static void rtTimerFreeBSDIpiAction(void *pvTimer)
248{
249 PRTTIMER pTimer = (PRTTIMER)pvTimer;
250 if ( pTimer->iCpu == RTTIMER_FLAGS_CPU_MASK
251 || (u_int)pTimer->iCpu == curcpu)
252 pTimer->pfnTimer(pTimer, pTimer->pvUser, pTimer->iTick);
253}
254
255
256static void rtTimerFreeBSDCallback(void *pvTimer)
257{
258 PRTTIMER pTimer = (PRTTIMER)pvTimer;
259
260 /* calculate and set the next timeout */
261 pTimer->iTick++;
262 if (!pTimer->u64NanoInterval)
263 {
264 pTimer->fSuspended = true;
265 callout_stop(&pTimer->Callout);
266 }
267 else
268 {
269 struct timeval tv;
270 const uint64_t u64NanoTS = RTTimeNanoTS();
271 pTimer->u64NextTS = pTimer->u64StartTS + pTimer->iTick * pTimer->u64NanoInterval;
272 if (pTimer->u64NextTS < u64NanoTS)
273 pTimer->u64NextTS = u64NanoTS + RTTimerGetSystemGranularity() / 2;
274
275 tv.tv_sec = pTimer->u64NextTS / 1000000000;
276 tv.tv_usec = (pTimer->u64NextTS % 1000000000) / 1000;
277 callout_reset(&pTimer->Callout, tvtohz(&tv), rtTimerFreeBSDCallback, pTimer);
278 }
279
280 /* callback */
281 if ( !pTimer->fSpecificCpu
282 || pTimer->iCpu == curcpu)
283 pTimer->pfnTimer(pTimer, pTimer->pvUser, pTimer->iTick);
284 else
285 smp_rendezvous(NULL, rtTimerFreeBSDIpiAction, NULL, pvTimer);
286}
287
288
289RTDECL(uint32_t) RTTimerGetSystemGranularity(void)
290{
291 return 1000000000 / hz; /* ns */
292}
293
294
295RTDECL(int) RTTimerRequestSystemGranularity(uint32_t u32Request, uint32_t *pu32Granted)
296{
297 return VERR_NOT_SUPPORTED;
298}
299
300
301RTDECL(int) RTTimerReleaseSystemGranularity(uint32_t u32Granted)
302{
303 return VERR_NOT_SUPPORTED;
304}
305
306
307RTDECL(bool) RTTimerCanDoHighResolution(void)
308{
309 return false;
310}
311
Note: See TracBrowser for help on using the repository browser.

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