VirtualBox

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

Last change on this file since 42586 was 37305, checked in by vboxsync, 14 years ago

IPRT/FreeBSD: Fix running VMs on 7.4, the sleep queue lock is released for broadcasts there already

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