VirtualBox

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

Last change on this file since 73907 was 72889, checked in by vboxsync, 7 years ago

r0drv/linux: adjust kernel header file for an openSUSE 15.0 kernel back-port.
Linux 4.13.0 changed wait_queue_t to wait_queue_entry_t. openSUSE 15.0 back-
ported this change to their 4.12.14 kernel. Fortunately there was never an
official 4.12.14 (4.12.9 was the last), so we test for that instead of 4.13.0
and hope that no one else did this.

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