VirtualBox

source: vbox/trunk/src/VBox/Runtime/r0drv/linux/waitqueue-r0drv-linux.h@ 33019

Last change on this file since 33019 was 33019, checked in by vboxsync, 15 years ago

waitqueue-r0drv-linux.h: 2.4.x build fix

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 7.8 KB
Line 
1/* $Id: waitqueue-r0drv-linux.h 33019 2010-10-08 20:21:03Z vboxsync $ */
2/** @file
3 * IPRT - Linux Ring-0 Driver Helpers for Abstracting Wait 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_linux_waitqueue_r0drv_linux_h
29#define ___r0drv_linux_waitqueue_r0drv_linux_h
30
31#include "the-linux-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/**
40 * Kernel mode Linux wait state structure.
41 */
42typedef struct RTR0SEMLNXWAIT
43{
44 /** The wait queue entry. */
45 wait_queue_t WaitQE;
46 /** The absolute timeout given as nano seconds since the start of the
47 * monotonic clock. */
48 uint64_t uNsAbsTimeout;
49 /** The timeout in nano seconds relative to the start of the wait. */
50 uint64_t cNsRelTimeout;
51 /** The native timeout value. */
52 union
53 {
54#ifdef IPRT_LINUX_HAS_HRTIMER
55 /** The timeout when fHighRes is true. Absolute, so no updateing. */
56 ktime_t KtTimeout;
57#endif
58 /** The timeout when fHighRes is false. Updated after waiting. */
59 long lTimeout;
60 } u;
61 /** Set if we use high resolution timeouts. */
62 bool fHighRes;
63 /** Set if it's an indefinite wait. */
64 bool fIndefinite;
65 /** Set if we've already timed out.
66 * Set by rtR0SemLnxWaitDoIt and read by rtR0SemLnxWaitHasTimedOut. */
67 bool fTimedOut;
68 /** TASK_INTERRUPTIBLE or TASK_UNINTERRUPTIBLE. */
69 int iWaitState;
70 /** The wait queue. */
71 wait_queue_head_t *pWaitQueue;
72} RTR0SEMLNXWAIT;
73/** Pointer to a linux wait state. */
74typedef RTR0SEMLNXWAIT *PRTR0SEMLNXWAIT;
75
76
77/**
78 * Initializes a wait.
79 *
80 * The caller MUST check the wait condition BEFORE calling this function or the
81 * timeout logic will be flawed.
82 *
83 * @returns VINF_SUCCESS or VERR_TIMEOUT.
84 * @param pWait The wait structure.
85 * @param fFlags The wait flags.
86 * @param uTimeout The timeout.
87 * @param pWaitQueue The wait queue head.
88 */
89DECLINLINE(int) rtR0SemLnxWaitInit(PRTR0SEMLNXWAIT pWait, uint32_t fFlags, uint64_t uTimeout,
90 wait_queue_head_t *pWaitQueue)
91{
92 /*
93 * Process the flags and timeout.
94 */
95 if (!(fFlags & RTSEMWAIT_FLAGS_INDEFINITE))
96 {
97/** @todo optimize: millisecs -> nanosecs -> millisec -> jiffies */
98 if (fFlags & RTSEMWAIT_FLAGS_MILLISECS)
99 uTimeout = uTimeout < UINT64_MAX / UINT32_C(1000000) * UINT32_C(1000000)
100 ? uTimeout * UINT32_C(1000000)
101 : UINT64_MAX;
102 if (uTimeout == UINT64_MAX)
103 fFlags |= RTSEMWAIT_FLAGS_INDEFINITE;
104 else
105 {
106 uint64_t u64Now;
107 if (fFlags & RTSEMWAIT_FLAGS_RELATIVE)
108 {
109 if (uTimeout == 0)
110 return VERR_TIMEOUT;
111
112 u64Now = RTTimeSystemNanoTS();
113 pWait->cNsRelTimeout = uTimeout;
114 pWait->uNsAbsTimeout = u64Now + uTimeout;
115 if (pWait->uNsAbsTimeout < u64Now) /* overflow */
116 fFlags |= RTSEMWAIT_FLAGS_INDEFINITE;
117 }
118 else
119 {
120 u64Now = RTTimeSystemNanoTS();
121 if (u64Now >= uTimeout)
122 return VERR_TIMEOUT;
123
124 pWait->cNsRelTimeout = uTimeout - u64Now;
125 pWait->uNsAbsTimeout = uTimeout;
126 }
127 }
128 }
129
130 if (!(fFlags & RTSEMWAIT_FLAGS_INDEFINITE))
131 {
132 pWait->fIndefinite = false;
133#ifdef IPRT_LINUX_HAS_HRTIMER
134 if ( (fFlags & (RTSEMWAIT_FLAGS_NANOSECS | RTSEMWAIT_FLAGS_ABSOLUTE))
135 || pWait->cNsRelTimeout < UINT32_C(1000000000) / HZ * 4)
136 {
137 pWait->fHighRes = true;
138# if BITS_PER_LONG < 64
139 if ( KTIME_SEC_MAX <= LONG_MAX
140 && pWait->uNsAbsTimeout >= KTIME_SEC_MAX * UINT64_C(1000000000) + UINT64_C(999999999))
141 fFlags |= RTSEMWAIT_FLAGS_INDEFINITE;
142 else
143# endif
144 pWait->u.KtTimeout = ns_to_ktime(pWait->uNsAbsTimeout);
145 }
146 else
147#endif
148 {
149 uint64_t cJiffies = ASMMultU64ByU32DivByU32(uTimeout, HZ, UINT32_C(1000000000));
150 if (cJiffies >= MAX_JIFFY_OFFSET)
151 fFlags |= RTSEMWAIT_FLAGS_INDEFINITE;
152 else
153 {
154 pWait->u.lTimeout = (long)cJiffies;
155 pWait->fHighRes = false;
156 }
157 }
158 }
159
160 if (fFlags & RTSEMWAIT_FLAGS_INDEFINITE)
161 {
162 pWait->fIndefinite = true;
163 pWait->fHighRes = false;
164 pWait->uNsAbsTimeout = UINT64_MAX;
165 pWait->cNsRelTimeout = UINT64_MAX;
166 pWait->u.lTimeout = LONG_MAX;
167 }
168
169 pWait->fTimedOut = false;
170
171 /*
172 * Initialize the wait queue related bits.
173 */
174#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 39)
175 init_wait((&pWait->WaitQE));
176#else
177 RT_ZERO(pWait->WaitQE);
178 init_waitqueue_entry((&pWait->WaitQE), current);
179#endif
180 pWait->pWaitQueue = pWaitQueue;
181 pWait->iWaitState = fFlags & RTSEMWAIT_FLAGS_INTERRUPTIBLE
182 ? TASK_INTERRUPTIBLE : TASK_UNINTERRUPTIBLE;
183
184 return VINF_SUCCESS;
185}
186
187
188/**
189 * Prepares the next wait.
190 *
191 * This must be called before rtR0SemLnxWaitDoIt, and the caller should check
192 * the exit conditions inbetween the two calls.
193 *
194 * @param pWait The wait structure.
195 */
196DECLINLINE(void) rtR0SemLnxWaitPrepare(PRTR0SEMLNXWAIT pWait)
197{
198 /* Make everything thru schedule*() atomic scheduling wise. (Is this correct?) */
199 prepare_to_wait(pWait->pWaitQueue, &pWait->WaitQE, pWait->iWaitState);
200}
201
202
203/**
204 * Do the actual wait.
205 *
206 * @param pWait The wait structure.
207 */
208DECLINLINE(void) rtR0SemLnxWaitDoIt(PRTR0SEMLNXWAIT pWait)
209{
210 if (pWait->fIndefinite)
211 schedule();
212#ifdef IPRT_LINUX_HAS_HRTIMER
213 else if (pWait->fHighRes)
214 {
215 int rc = schedule_hrtimeout(&pWait->u.KtTimeout, HRTIMER_MODE_ABS);
216 if (!rc)
217 pWait->fTimedOut = true;
218 }
219#endif
220 else
221 {
222 pWait->u.lTimeout = schedule_timeout(pWait->u.lTimeout);
223 if (pWait->u.lTimeout <= 0)
224 pWait->fTimedOut = true;
225 }
226 after_wait((&pWait->WaitQE));
227}
228
229
230/**
231 * Checks if a linux wait was interrupted.
232 *
233 * @returns true / false
234 * @param pWait The wait structure.
235 * @remarks This shall be called before the first rtR0SemLnxWaitDoIt().
236 */
237DECLINLINE(bool) rtR0SemLnxWaitWasInterrupted(PRTR0SEMLNXWAIT pWait)
238{
239 return pWait->iWaitState == TASK_INTERRUPTIBLE
240 && signal_pending(current);
241}
242
243
244/**
245 * Checks if a linux wait has timed out.
246 *
247 * @returns true / false
248 * @param pWait The wait structure.
249 */
250DECLINLINE(bool) rtR0SemLnxWaitHasTimedOut(PRTR0SEMLNXWAIT pWait)
251{
252 return pWait->fTimedOut;
253}
254
255
256/**
257 * Deletes a linux wait.
258 *
259 * @param pWait The wait structure.
260 */
261DECLINLINE(void) rtR0SemLnxWaitDelete(PRTR0SEMLNXWAIT pWait)
262{
263 finish_wait(pWait->pWaitQueue, &pWait->WaitQE);
264}
265
266
267#endif
268
Note: See TracBrowser for help on using the repository browser.

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