VirtualBox

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

Last change on this file since 95685 was 93115, checked in by vboxsync, 3 years ago

scm --update-copyright-year

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 8.2 KB
Line 
1/* $Id: sleepqueue-r0drv-netbsd.h 93115 2022-01-01 11:31:46Z vboxsync $ */
2/** @file
3 * IPRT - NetBSD Ring-0 Driver Helpers for Abstracting Sleep Queues,
4 */
5
6/*
7 * Copyright (C) 2006-2022 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#if __NetBSD_Prereq__(9,99,57)
173#define sleepq_enqueue(sq, wchan, wmesg, sobj) \
174 sleepq_enqueue((sq), (wchan), (wmesg), (sobj), true)
175#endif
176
177 sleepq_enter(pWait->sq, curlwp, pWait->sq_lock);
178 sleepq_enqueue(pWait->sq, pWait->wchan, "VBoxIS", &vbox_syncobj);
179
180 pWait->sq = NULL;
181 pWait->sq_lock = NULL;
182
183 int error = sleepq_block(pWait->iTimeout, pWait->fInterruptible);
184 if (error == EWOULDBLOCK) {
185 if (!pWait->fIndefinite) {
186 pWait->fTimedOut = true;
187 }
188 } else if (error == ERESTART) {
189 if (pWait->fInterruptible) {
190 pWait->fInterrupted = true;
191 } else if (!pWait->fIndefinite) {
192 rtR0SemBsdWaitUpdateTimeout(pWait);
193 if (pWait->iTimeout == 0) {
194 pWait->fTimedOut = true;
195 }
196 }
197 } else if (error == EINTR) {
198 if (pWait->fInterruptible) {
199 pWait->fInterrupted = true;
200 } else if (!pWait->fIndefinite) {
201 rtR0SemBsdWaitUpdateTimeout(pWait);
202 if (pWait->iTimeout == 0) {
203 pWait->fTimedOut = true;
204 }
205 }
206 } else if (error) {
207 AssertMsgFailed(("sleepq_block -> %d\n", error));
208 }
209}
210
211
212/**
213 * Checks if a NetBSD wait was interrupted.
214 *
215 * @returns true / false
216 * @param pWait The wait structure.
217 * @remarks This shall be called before the first rtR0SemLnxWaitDoIt().
218 */
219DECLINLINE(bool) rtR0SemBsdWaitWasInterrupted(PRTR0SEMBSDSLEEP pWait)
220{
221 return pWait->fInterrupted;
222}
223
224
225/**
226 * Checks if a NetBSD wait has timed out.
227 *
228 * @returns true / false
229 * @param pWait The wait structure.
230 */
231DECLINLINE(bool) rtR0SemBsdWaitHasTimedOut(PRTR0SEMBSDSLEEP pWait)
232{
233 return pWait->fTimedOut;
234}
235
236
237/**
238 * Deletes a NetBSD wait.
239 *
240 * @param pWait The wait structure.
241 */
242DECLINLINE(void) rtR0SemBsdWaitDelete(PRTR0SEMBSDSLEEP pWait)
243{
244 if (pWait->sq_lock != NULL) {
245 mutex_spin_exit(pWait->sq_lock);
246 pWait->sq = NULL;
247 pWait->sq_lock = NULL;
248 }
249}
250
251
252/**
253 * Signals the wait channel.
254 *
255 * @param pvWaitChan The opaque wait channel handle.
256 */
257DECLINLINE(void) rtR0SemBsdSignal(void *pvWaitChan)
258{
259 kmutex_t *mp;
260 sleepq_t *sq = sleeptab_lookup(&sleeptab, pvWaitChan, &mp);
261 sleepq_wake(sq, pvWaitChan, 1, mp);
262}
263
264/**
265 * Wakes up all waiters on the wait channel.
266 *
267 * @param pvWaitChan The opaque wait channel handle.
268 */
269DECLINLINE(void) rtR0SemBsdBroadcast(void *pvWaitChan)
270{
271 kmutex_t *mp;
272 sleepq_t *sq = sleeptab_lookup(&sleeptab, pvWaitChan, &mp);
273 sleepq_wake(sq, pvWaitChan, ~0u, mp);
274}
275
276/**
277 * Gets the max resolution of the timeout machinery.
278 *
279 * @returns Resolution specified in nanoseconds.
280 */
281DECLINLINE(uint32_t) rtR0SemBsdWaitGetResolution(void)
282{
283 return 1000000000 / hz; /* ns */
284}
285
286#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