VirtualBox

source: vbox/trunk/src/VBox/Runtime/r0drv/netbsd/sleepqueue-r0drv-netbsd.h@ 86669

Last change on this file since 86669 was 83614, checked in by vboxsync, 5 years ago

r0drv/netbsd: use SOBJ_SLEEPQ_SORTED as advised by <ad@…>.
SOBJ_SLEEPQ_FIFO is no more in NetBSD-current.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 8.0 KB
Line 
1/* $Id: sleepqueue-r0drv-netbsd.h 83614 2020-04-07 21:31:08Z vboxsync $ */
2/** @file
3 * IPRT - NetBSD Ring-0 Driver Helpers for Abstracting Sleep Queues,
4 */
5
6/*
7 * Copyright (C) 2006-2020 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_netbsd_sleepqueue_r0drv_netbsd_h
28#define IPRT_INCLUDED_SRC_r0drv_netbsd_sleepqueue_r0drv_netbsd_h
29#ifndef RT_WITHOUT_PRAGMA_ONCE
30# pragma once
31#endif
32
33#include "the-netbsd-kernel.h"
34
35#include <iprt/asm-math.h>
36#include <iprt/err.h>
37#include <iprt/time.h>
38
39static syncobj_t vbox_syncobj = {
40 SOBJ_SLEEPQ_SORTED,
41 sleepq_unsleep,
42 sleepq_changepri,
43 sleepq_lendpri,
44 syncobj_noowner,
45};
46
47/**
48 * Kernel mode NetBSD wait state structure.
49 */
50typedef struct RTR0SEMBSDSLEEP
51{
52 /** The absolute timeout given as nano seconds since the start of the
53 * monotonic clock. */
54 uint64_t uNsAbsTimeout;
55 /** The timeout in ticks. Updated after waiting. */
56 int iTimeout;
57 /** Set if it's an indefinite wait. */
58 bool fIndefinite;
59 /** Set if we've already timed out.
60 * Set by rtR0SemBsdWaitDoIt and read by rtR0SemBsdWaitHasTimedOut. */
61 bool fTimedOut;
62 /** Flag whether the wait was interrupted. */
63 bool fInterrupted;
64 /** flag whether the wait is interruptible or not. */
65 bool fInterruptible;
66 /** Opaque wait channel id. */
67 wchan_t wchan;
68 sleepq_t *sq;
69 kmutex_t *sq_lock;
70} RTR0SEMBSDSLEEP;
71/** Pointer to a NetBSD wait state. */
72typedef RTR0SEMBSDSLEEP *PRTR0SEMBSDSLEEP;
73
74
75/**
76 * Updates the timeout of the NetBSD wait.
77 *
78 * @returns RTSEMWAIT_FLAGS_INDEFINITE if the timeout value is too big.
79 * 0 otherwise
80 * @param pWait The wait structure.
81 * @param uTimeout The relative timeout in nanoseconds.
82 */
83DECLINLINE(void) rtR0SemBsdWaitUpdateTimeout(PRTR0SEMBSDSLEEP pWait)
84{
85 /* Convert absolute timeout to ticks */
86 uint64_t now = RTTimeNanoTS();
87 if (now >= pWait->uNsAbsTimeout) {
88 pWait->iTimeout = 0;
89 } else {
90 uint64_t nanos = pWait->uNsAbsTimeout - now;
91 pWait->iTimeout = hz * nanos / 1000000000;
92 /* for 1ms wait, wait at least one tick ?? */
93 if ((pWait->iTimeout == 0) && (nanos >= 1000000)) {
94 pWait->iTimeout = 1;
95 }
96 }
97}
98
99/**
100 * Initializes a wait.
101 *
102 * The caller MUST check the wait condition BEFORE calling this function or the
103 * timeout logic will be flawed.
104 *
105 * @returns VINF_SUCCESS or VERR_TIMEOUT.
106 * @param pWait The wait structure.
107 * @param fFlags The wait flags.
108 * @param uTimeout The timeout.
109 * @param pvWaitChan The opaque wait channel.
110 */
111DECLINLINE(int) rtR0SemBsdWaitInit(PRTR0SEMBSDSLEEP pWait, uint32_t fFlags, uint64_t uTimeout,
112 void *pvWaitChan)
113{
114 if (fFlags & RTSEMWAIT_FLAGS_INDEFINITE) {
115 pWait->fIndefinite = true;
116 pWait->iTimeout = 0;
117 pWait->uNsAbsTimeout = 0;
118 } else {
119 if (fFlags & RTSEMWAIT_FLAGS_RELATIVE) {
120 if (fFlags & RTSEMWAIT_FLAGS_MILLISECS) {
121 pWait->uNsAbsTimeout = uTimeout * 1000000 + RTTimeSystemNanoTS();
122 } else {
123 pWait->uNsAbsTimeout = uTimeout + RTTimeSystemNanoTS();
124 }
125 } else {
126 if (fFlags & RTSEMWAIT_FLAGS_MILLISECS) {
127 pWait->uNsAbsTimeout = uTimeout * 1000000;
128 } else {
129 pWait->uNsAbsTimeout = uTimeout;
130 }
131 }
132 rtR0SemBsdWaitUpdateTimeout(pWait);
133 if (pWait->iTimeout == 0) {
134 return VERR_TIMEOUT;
135 }
136 }
137
138 pWait->fTimedOut = false;
139 /*
140 * Initialize the wait queue related bits.
141 */
142 pWait->fInterruptible = fFlags & RTSEMWAIT_FLAGS_INTERRUPTIBLE
143 ? true : false;
144 pWait->fInterrupted = false;
145 pWait->wchan = pvWaitChan;
146 pWait->sq = NULL;
147 pWait->sq_lock = NULL;
148
149 return VINF_SUCCESS;
150}
151
152/**
153 * Prepares the next wait.
154 *
155 * This must be called before rtR0SemBsdWaitDoIt, and the caller should check
156 * the exit conditions inbetween the two calls.
157 *
158 * @param pWait The wait structure.
159 */
160DECLINLINE(void) rtR0SemBsdWaitPrepare(PRTR0SEMBSDSLEEP pWait)
161{
162 pWait->sq = sleeptab_lookup(&sleeptab, pWait->wchan, &pWait->sq_lock);
163}
164
165/**
166 * Do the actual wait.
167 *
168 * @param pWait The wait structure.
169 */
170DECLINLINE(void) rtR0SemBsdWaitDoIt(PRTR0SEMBSDSLEEP pWait)
171{
172 sleepq_enter(pWait->sq, curlwp, pWait->sq_lock);
173 sleepq_enqueue(pWait->sq, pWait->wchan, "VBoxIS", &vbox_syncobj);
174
175 pWait->sq = NULL;
176 pWait->sq_lock = NULL;
177
178 int error = sleepq_block(pWait->iTimeout, pWait->fInterruptible);
179 if (error == EWOULDBLOCK) {
180 if (!pWait->fIndefinite) {
181 pWait->fTimedOut = true;
182 }
183 } else if (error == ERESTART) {
184 if (pWait->fInterruptible) {
185 pWait->fInterrupted = true;
186 } else if (!pWait->fIndefinite) {
187 rtR0SemBsdWaitUpdateTimeout(pWait);
188 if (pWait->iTimeout == 0) {
189 pWait->fTimedOut = true;
190 }
191 }
192 } else if (error == EINTR) {
193 if (pWait->fInterruptible) {
194 pWait->fInterrupted = true;
195 } else if (!pWait->fIndefinite) {
196 rtR0SemBsdWaitUpdateTimeout(pWait);
197 if (pWait->iTimeout == 0) {
198 pWait->fTimedOut = true;
199 }
200 }
201 } else if (error) {
202 AssertMsgFailed(("sleepq_block -> %d\n", error));
203 }
204}
205
206
207/**
208 * Checks if a NetBSD wait was interrupted.
209 *
210 * @returns true / false
211 * @param pWait The wait structure.
212 * @remarks This shall be called before the first rtR0SemLnxWaitDoIt().
213 */
214DECLINLINE(bool) rtR0SemBsdWaitWasInterrupted(PRTR0SEMBSDSLEEP pWait)
215{
216 return pWait->fInterrupted;
217}
218
219
220/**
221 * Checks if a NetBSD wait has timed out.
222 *
223 * @returns true / false
224 * @param pWait The wait structure.
225 */
226DECLINLINE(bool) rtR0SemBsdWaitHasTimedOut(PRTR0SEMBSDSLEEP pWait)
227{
228 return pWait->fTimedOut;
229}
230
231
232/**
233 * Deletes a NetBSD wait.
234 *
235 * @param pWait The wait structure.
236 */
237DECLINLINE(void) rtR0SemBsdWaitDelete(PRTR0SEMBSDSLEEP pWait)
238{
239 if (pWait->sq_lock != NULL) {
240 mutex_spin_exit(pWait->sq_lock);
241 pWait->sq = NULL;
242 pWait->sq_lock = NULL;
243 }
244}
245
246
247/**
248 * Signals the wait channel.
249 *
250 * @param pvWaitChan The opaque wait channel handle.
251 */
252DECLINLINE(void) rtR0SemBsdSignal(void *pvWaitChan)
253{
254 kmutex_t *mp;
255 sleepq_t *sq = sleeptab_lookup(&sleeptab, pvWaitChan, &mp);
256 sleepq_wake(sq, pvWaitChan, 1, mp);
257}
258
259/**
260 * Wakes up all waiters on the wait channel.
261 *
262 * @param pvWaitChan The opaque wait channel handle.
263 */
264DECLINLINE(void) rtR0SemBsdBroadcast(void *pvWaitChan)
265{
266 kmutex_t *mp;
267 sleepq_t *sq = sleeptab_lookup(&sleeptab, pvWaitChan, &mp);
268 sleepq_wake(sq, pvWaitChan, ~0u, mp);
269}
270
271/**
272 * Gets the max resolution of the timeout machinery.
273 *
274 * @returns Resolution specified in nanoseconds.
275 */
276DECLINLINE(uint32_t) rtR0SemBsdWaitGetResolution(void)
277{
278 return 1000000000 / hz; /* ns */
279}
280
281#endif /* !IPRT_INCLUDED_SRC_r0drv_netbsd_sleepqueue_r0drv_netbsd_h */
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