VirtualBox

source: vbox/trunk/src/VBox/Runtime/r0drv/freebsd/sleepqueue-r0drv-freebsd.h@ 78401

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

*: scm --fix-header-guard-endif

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 9.2 KB
Line 
1/* $Id: sleepqueue-r0drv-freebsd.h 76585 2019-01-01 06:31:29Z vboxsync $ */
2/** @file
3 * IPRT - FreeBSD Ring-0 Driver Helpers for Abstracting Sleep Queues,
4 */
5
6/*
7 * Copyright (C) 2006-2019 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * The contents of this file may alternatively be used under the terms
18 * of the Common Development and Distribution License Version 1.0
19 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20 * VirtualBox OSE distribution, in which case the provisions of the
21 * CDDL are applicable instead of those of the GPL.
22 *
23 * You may elect to license modified versions of this file under the
24 * terms and conditions of either the GPL or the CDDL or both.
25 */
26
27#ifndef IPRT_INCLUDED_SRC_r0drv_freebsd_sleepqueue_r0drv_freebsd_h
28#define IPRT_INCLUDED_SRC_r0drv_freebsd_sleepqueue_r0drv_freebsd_h
29#ifndef RT_WITHOUT_PRAGMA_ONCE
30# pragma once
31#endif
32
33#include "the-freebsd-kernel.h"
34
35#include <iprt/asm-math.h>
36#include <iprt/err.h>
37#include <iprt/string.h>
38#include <iprt/time.h>
39
40/**
41 * Kernel mode FreeBSD wait state structure.
42 */
43typedef struct RTR0SEMBSDSLEEP
44{
45 /** The absolute timeout given as nano seconds since the start of the
46 * monotonic clock. */
47 uint64_t uNsAbsTimeout;
48 /** The timeout in ticks. Updated after waiting. */
49 int iTimeout;
50 /** Set if it's an indefinite wait. */
51 bool fIndefinite;
52 /** Set if we've already timed out.
53 * Set by rtR0SemBsdWaitDoIt and read by rtR0SemBsdWaitHasTimedOut. */
54 bool fTimedOut;
55 /** Flag whether the wait was interrupted. */
56 bool fInterrupted;
57 /** flag whether the wait is interruptible or not. */
58 bool fInterruptible;
59 /** Opaque wait channel id. */
60 void *pvWaitChan;
61} RTR0SEMBSDSLEEP;
62/** Pointer to a FreeBSD wait state. */
63typedef RTR0SEMBSDSLEEP *PRTR0SEMBSDSLEEP;
64
65
66/**
67 * Updates the timeout of the FreeBSD wait.
68 *
69 * @returns RTSEMWAIT_FLAGS_INDEFINITE if the timeout value is too big.
70 * 0 otherwise
71 * @param pWait The wait structure.
72 * @param uTimeout The relative timeout in nanoseconds.
73 */
74DECLINLINE(uint32_t) rtR0SemBsdWaitUpdateTimeout(PRTR0SEMBSDSLEEP pWait, uint64_t uTimeout)
75{
76#if 0
77 struct timeval tv;
78
79 tv.tv_sec = uTimeout / UINT64_C(1000000000);
80 tv.tv_usec = (uTimeout % UINT64_C(1000000000)) / UINT64_C(1000);
81
82 pWait->iTimeout = tvtohz(&tv);
83#else
84 uint64_t cTicks = ASMMultU64ByU32DivByU32(uTimeout, hz, UINT32_C(1000000000));
85 if (cTicks >= INT_MAX)
86 return RTSEMWAIT_FLAGS_INDEFINITE;
87 else
88 pWait->iTimeout = (int)cTicks;
89#endif
90
91 return 0;
92}
93
94/**
95 * Initializes a wait.
96 *
97 * The caller MUST check the wait condition BEFORE calling this function or the
98 * timeout logic will be flawed.
99 *
100 * @returns VINF_SUCCESS or VERR_TIMEOUT.
101 * @param pWait The wait structure.
102 * @param fFlags The wait flags.
103 * @param uTimeout The timeout.
104 * @param pvWaitChan The opaque wait channel.
105 */
106DECLINLINE(int) rtR0SemBsdWaitInit(PRTR0SEMBSDSLEEP pWait, uint32_t fFlags, uint64_t uTimeout,
107 void *pvWaitChan)
108{
109 pWait->iTimeout = 0;
110 pWait->uNsAbsTimeout = 0; /* shut up gcc */
111
112 /*
113 * Process the flags and timeout.
114 */
115 if (!(fFlags & RTSEMWAIT_FLAGS_INDEFINITE))
116 {
117/** @todo optimize: millisecs -> nanosecs -> millisec -> jiffies */
118 if (fFlags & RTSEMWAIT_FLAGS_MILLISECS)
119 uTimeout = uTimeout < UINT64_MAX / UINT32_C(1000000) * UINT32_C(1000000)
120 ? uTimeout * UINT32_C(1000000)
121 : UINT64_MAX;
122 if (uTimeout == UINT64_MAX)
123 fFlags |= RTSEMWAIT_FLAGS_INDEFINITE;
124 else
125 {
126 uint64_t u64Now;
127 if (fFlags & RTSEMWAIT_FLAGS_RELATIVE)
128 {
129 if (uTimeout == 0)
130 return VERR_TIMEOUT;
131
132 u64Now = RTTimeSystemNanoTS();
133 if (u64Now + uTimeout < u64Now) /* overflow */
134 fFlags |= RTSEMWAIT_FLAGS_INDEFINITE;
135 else
136 pWait->uNsAbsTimeout = u64Now + uTimeout;
137 }
138 else
139 {
140 u64Now = RTTimeSystemNanoTS();
141 if (u64Now >= uTimeout)
142 return VERR_TIMEOUT;
143
144 pWait->uNsAbsTimeout = uTimeout;
145 uTimeout -= u64Now; /* Get a relative value. */
146 }
147 }
148 }
149
150 if (!(fFlags & RTSEMWAIT_FLAGS_INDEFINITE))
151 {
152 pWait->fIndefinite = false;
153 fFlags |= rtR0SemBsdWaitUpdateTimeout(pWait, uTimeout);
154 }
155
156 if (fFlags & RTSEMWAIT_FLAGS_INDEFINITE)
157 {
158 pWait->fIndefinite = true;
159 pWait->iTimeout = INT_MAX;
160 pWait->uNsAbsTimeout = UINT64_MAX;
161 }
162
163 pWait->fTimedOut = false;
164
165 /*
166 * Initialize the wait queue related bits.
167 */
168 pWait->fInterruptible = fFlags & RTSEMWAIT_FLAGS_INTERRUPTIBLE
169 ? true : false;
170 pWait->pvWaitChan = pvWaitChan;
171 pWait->fInterrupted = false;
172
173 return VINF_SUCCESS;
174}
175
176/**
177 * Prepares the next wait.
178 *
179 * This must be called before rtR0SemBsdWaitDoIt, and the caller should check
180 * the exit conditions inbetween the two calls.
181 *
182 * @param pWait The wait structure.
183 */
184DECLINLINE(void) rtR0SemBsdWaitPrepare(PRTR0SEMBSDSLEEP pWait)
185{
186 /* Lock the queues. */
187 sleepq_lock(pWait->pvWaitChan);
188}
189
190/**
191 * Do the actual wait.
192 *
193 * @param pWait The wait structure.
194 */
195DECLINLINE(void) rtR0SemBsdWaitDoIt(PRTR0SEMBSDSLEEP pWait)
196{
197 int rcBsd;
198 int fSleepqFlags = SLEEPQ_CONDVAR;
199
200 if (pWait->fInterruptible)
201 fSleepqFlags |= SLEEPQ_INTERRUPTIBLE;
202
203 sleepq_add(pWait->pvWaitChan, NULL, "VBoxIS", fSleepqFlags, 0);
204
205 if (!pWait->fIndefinite)
206 {
207 sleepq_set_timeout(pWait->pvWaitChan, pWait->iTimeout);
208
209 if (pWait->fInterruptible)
210 rcBsd = SLEEPQ_TIMEDWAIT_SIG(pWait->pvWaitChan);
211 else
212 rcBsd = SLEEPQ_TIMEDWAIT(pWait->pvWaitChan);
213 }
214 else
215 {
216 if (pWait->fInterruptible)
217 rcBsd = SLEEPQ_WAIT_SIG(pWait->pvWaitChan);
218 else
219 {
220 rcBsd = 0;
221 SLEEPQ_WAIT(pWait->pvWaitChan);
222 }
223 }
224
225 switch (rcBsd)
226 {
227 case 0:
228 break;
229 case ERESTART:
230 {
231 if (!pWait->fIndefinite)
232 {
233 /* Recalc timeout. */
234 uint64_t u64Now = RTTimeSystemNanoTS();
235 if (u64Now >= pWait->uNsAbsTimeout)
236 pWait->fTimedOut = true;
237 else
238 {
239 u64Now = pWait->uNsAbsTimeout - u64Now;
240 rtR0SemBsdWaitUpdateTimeout(pWait, u64Now);
241 }
242 }
243 break;
244 }
245 case EWOULDBLOCK:
246 pWait->fTimedOut = true;
247 break;
248 case EINTR:
249 Assert(pWait->fInterruptible);
250 pWait->fInterrupted = true;
251 break;
252 default:
253 AssertMsgFailed(("sleepq_* -> %d\n", rcBsd));
254 break;
255 }
256}
257
258
259/**
260 * Checks if a FreeBSD wait was interrupted.
261 *
262 * @returns true / false
263 * @param pWait The wait structure.
264 * @remarks This shall be called before the first rtR0SemBsdWaitDoIt().
265 */
266DECLINLINE(bool) rtR0SemBsdWaitWasInterrupted(PRTR0SEMBSDSLEEP pWait)
267{
268 return pWait->fInterrupted;
269}
270
271
272/**
273 * Checks if a FreeBSD wait has timed out.
274 *
275 * @returns true / false
276 * @param pWait The wait structure.
277 */
278DECLINLINE(bool) rtR0SemBsdWaitHasTimedOut(PRTR0SEMBSDSLEEP pWait)
279{
280 return pWait->fTimedOut;
281}
282
283
284/**
285 * Deletes a FreeBSD wait.
286 *
287 * @param pWait The wait structure.
288 */
289DECLINLINE(void) rtR0SemBsdWaitDelete(PRTR0SEMBSDSLEEP pWait)
290{
291 sleepq_release(pWait->pvWaitChan);
292}
293
294
295/**
296 * Signals the wait channel.
297 *
298 * @param pvWaitChan The opaque wait channel handle.
299 */
300DECLINLINE(void) rtR0SemBsdSignal(void *pvWaitChan)
301{
302 sleepq_lock(pvWaitChan);
303 int fWakeupSwapProc = sleepq_signal(pvWaitChan, SLEEPQ_CONDVAR, 0, 0);
304 sleepq_release(pvWaitChan);
305 if (fWakeupSwapProc)
306 kick_proc0();
307}
308
309/**
310 * Wakes up all waiters on the wait channel.
311 *
312 * @param pvWaitChan The opaque wait channel handle.
313 */
314DECLINLINE(void) rtR0SemBsdBroadcast(void *pvWaitChan)
315{
316 sleepq_lock(pvWaitChan);
317 sleepq_broadcast(pvWaitChan, SLEEPQ_CONDVAR, 0, 0);
318#if __FreeBSD_version >= 800000 /* Broadcast releases the sleep queue lock on FreeBSD 7.x */
319 sleepq_release(pvWaitChan);
320#endif
321}
322
323/**
324 * Gets the max resolution of the timeout machinery.
325 *
326 * @returns Resolution specified in nanoseconds.
327 */
328DECLINLINE(uint32_t) rtR0SemBsdWaitGetResolution(void)
329{
330 return 1000000000 / hz; /* ns */
331}
332
333#endif /* !IPRT_INCLUDED_SRC_r0drv_freebsd_sleepqueue_r0drv_freebsd_h */
334
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