VirtualBox

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

Last change on this file was 98103, checked in by vboxsync, 17 months ago

Copyright year updates by scm.

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

© 2023 Oracle
ContactPrivacy policyTerms of Use