~ubuntu-branches/ubuntu/raring/virtualbox-ose/raring

« back to all changes in this revision

Viewing changes to src/VBox/Runtime/r0drv/freebsd/sleepqueue-r0drv-freebsd.h

  • Committer: Bazaar Package Importer
  • Author(s): Felix Geyer
  • Date: 2011-01-30 23:27:25 UTC
  • mfrom: (0.3.12 upstream)
  • Revision ID: james.westby@ubuntu.com-20110130232725-2ouajjd2ggdet0zd
Tags: 4.0.2-dfsg-1ubuntu1
* Merge from Debian unstable, remaining changes:
  - Add Apport hook.
    - debian/virtualbox-ose.files/source_virtualbox-ose.py
    - debian/virtualbox-ose.install
  - Drop *-source packages.
* Drop ubuntu-01-fix-build-gcc45.patch, fixed upstream.
* Drop ubuntu-02-as-needed.patch, added to the Debian package.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* $Id: sleepqueue-r0drv-freebsd.h 33527 2010-10-27 17:09:25Z 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
 */
 
41
typedef 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. */
 
61
typedef 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
 */
 
72
DECLINLINE(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
 */
 
104
DECLINLINE(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
 */
 
182
DECLINLINE(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
 */
 
193
DECLINLINE(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
 */
 
264
DECLINLINE(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
 */
 
276
DECLINLINE(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
 */
 
287
DECLINLINE(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
 */
 
298
DECLINLINE(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
 */
 
312
DECLINLINE(void) rtR0SemBsdBroadcast(void *pvWaitChan)
 
313
{
 
314
    sleepq_lock(pvWaitChan);
 
315
    sleepq_broadcast(pvWaitChan, SLEEPQ_CONDVAR, 0, 0);
 
316
    sleepq_release(pvWaitChan);
 
317
}
 
318
 
 
319
/**
 
320
 * Gets the max resolution of the timeout machinery.
 
321
 *
 
322
 * @returns Resolution specified in nanoseconds.
 
323
 */
 
324
DECLINLINE(uint32_t) rtR0SemBsdWaitGetResolution(void)
 
325
{
 
326
    return 1000000000 / hz; /* ns */
 
327
}
 
328
 
 
329
#endif
 
330