VirtualBox

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

Last change on this file since 106061 was 106061, checked in by vboxsync, 7 weeks ago

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 8.6 KB
Line 
1/* $Id: sleepqueue-r0drv-netbsd.h 106061 2024-09-16 14:03:52Z vboxsync $ */
2/** @file
3 * IPRT - NetBSD Ring-0 Driver Helpers for Abstracting Sleep Queues,
4 */
5
6/*
7 * Copyright (C) 2006-2024 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * The contents of this file may alternatively be used under the terms
26 * of the Common Development and Distribution License Version 1.0
27 * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
28 * in the VirtualBox distribution, in which case the provisions of the
29 * CDDL are applicable instead of those of the GPL.
30 *
31 * You may elect to license modified versions of this file under the
32 * terms and conditions of either the GPL or the CDDL or both.
33 *
34 * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
35 */
36
37#ifndef IPRT_INCLUDED_SRC_r0drv_netbsd_sleepqueue_r0drv_netbsd_h
38#define IPRT_INCLUDED_SRC_r0drv_netbsd_sleepqueue_r0drv_netbsd_h
39#ifndef RT_WITHOUT_PRAGMA_ONCE
40# pragma once
41#endif
42
43#include "the-netbsd-kernel.h"
44
45#include <iprt/asm-math.h>
46#include <iprt/err.h>
47#include <iprt/time.h>
48
49static syncobj_t vbox_syncobj = {
50#if __NetBSD_Prereq__(10,99,6)
51 "VBox",
52#endif
53 SOBJ_SLEEPQ_SORTED,
54 sleepq_unsleep,
55 sleepq_changepri,
56 sleepq_lendpri,
57 syncobj_noowner,
58};
59
60/**
61 * Kernel mode NetBSD wait state structure.
62 */
63typedef struct RTR0SEMBSDSLEEP
64{
65 /** The absolute timeout given as nano seconds since the start of the
66 * monotonic clock. */
67 uint64_t uNsAbsTimeout;
68 /** The timeout in ticks. Updated after waiting. */
69 int iTimeout;
70 /** Set if it's an indefinite wait. */
71 bool fIndefinite;
72 /** Set if we've already timed out.
73 * Set by rtR0SemBsdWaitDoIt and read by rtR0SemBsdWaitHasTimedOut. */
74 bool fTimedOut;
75 /** Flag whether the wait was interrupted. */
76 bool fInterrupted;
77 /** flag whether the wait is interruptible or not. */
78 bool fInterruptible;
79 /** Opaque wait channel id. */
80 wchan_t wchan;
81 sleepq_t *sq;
82 kmutex_t *sq_lock;
83} RTR0SEMBSDSLEEP;
84/** Pointer to a NetBSD wait state. */
85typedef RTR0SEMBSDSLEEP *PRTR0SEMBSDSLEEP;
86
87
88/**
89 * Updates the timeout of the NetBSD wait.
90 *
91 * @returns RTSEMWAIT_FLAGS_INDEFINITE if the timeout value is too big.
92 * 0 otherwise
93 * @param pWait The wait structure.
94 * @param uTimeout The relative timeout in nanoseconds.
95 */
96DECLINLINE(void) rtR0SemBsdWaitUpdateTimeout(PRTR0SEMBSDSLEEP pWait)
97{
98 /* Convert absolute timeout to ticks */
99 uint64_t now = RTTimeNanoTS();
100 if (now >= pWait->uNsAbsTimeout) {
101 pWait->iTimeout = 0;
102 } else {
103 uint64_t nanos = pWait->uNsAbsTimeout - now;
104 pWait->iTimeout = hz * nanos / 1000000000;
105 /* for 1ms wait, wait at least one tick ?? */
106 if ((pWait->iTimeout == 0) && (nanos >= 1000000)) {
107 pWait->iTimeout = 1;
108 }
109 }
110}
111
112/**
113 * Initializes a wait.
114 *
115 * The caller MUST check the wait condition BEFORE calling this function or the
116 * timeout logic will be flawed.
117 *
118 * @returns VINF_SUCCESS or VERR_TIMEOUT.
119 * @param pWait The wait structure.
120 * @param fFlags The wait flags.
121 * @param uTimeout The timeout.
122 * @param pvWaitChan The opaque wait channel.
123 */
124DECLINLINE(int) rtR0SemBsdWaitInit(PRTR0SEMBSDSLEEP pWait, uint32_t fFlags, uint64_t uTimeout,
125 void *pvWaitChan)
126{
127 if (fFlags & RTSEMWAIT_FLAGS_INDEFINITE) {
128 pWait->fIndefinite = true;
129 pWait->iTimeout = 0;
130 pWait->uNsAbsTimeout = 0;
131 } else {
132 if (fFlags & RTSEMWAIT_FLAGS_RELATIVE) {
133 if (fFlags & RTSEMWAIT_FLAGS_MILLISECS) {
134 pWait->uNsAbsTimeout = uTimeout * 1000000 + RTTimeSystemNanoTS();
135 } else {
136 pWait->uNsAbsTimeout = uTimeout + RTTimeSystemNanoTS();
137 }
138 } else {
139 if (fFlags & RTSEMWAIT_FLAGS_MILLISECS) {
140 pWait->uNsAbsTimeout = uTimeout * 1000000;
141 } else {
142 pWait->uNsAbsTimeout = uTimeout;
143 }
144 }
145 rtR0SemBsdWaitUpdateTimeout(pWait);
146 if (pWait->iTimeout == 0) {
147 return VERR_TIMEOUT;
148 }
149 }
150
151 pWait->fTimedOut = false;
152 /*
153 * Initialize the wait queue related bits.
154 */
155 pWait->fInterruptible = fFlags & RTSEMWAIT_FLAGS_INTERRUPTIBLE
156 ? true : false;
157 pWait->fInterrupted = false;
158 pWait->wchan = pvWaitChan;
159 pWait->sq = NULL;
160 pWait->sq_lock = NULL;
161
162 return VINF_SUCCESS;
163}
164
165/**
166 * Prepares the next wait.
167 *
168 * This must be called before rtR0SemBsdWaitDoIt, and the caller should check
169 * the exit conditions inbetween the two calls.
170 *
171 * @param pWait The wait structure.
172 */
173DECLINLINE(void) rtR0SemBsdWaitPrepare(PRTR0SEMBSDSLEEP pWait)
174{
175 pWait->sq = sleeptab_lookup(&sleeptab, pWait->wchan, &pWait->sq_lock);
176}
177
178/**
179 * Do the actual wait.
180 *
181 * @param pWait The wait structure.
182 */
183DECLINLINE(void) rtR0SemBsdWaitDoIt(PRTR0SEMBSDSLEEP pWait)
184{
185#if __NetBSD_Prereq__(9,99,57)
186#define sleepq_enqueue(sq, wchan, wmesg, sobj) \
187 sleepq_enqueue((sq), (wchan), (wmesg), (sobj), true)
188#endif
189
190 sleepq_enter(pWait->sq, curlwp, pWait->sq_lock);
191 sleepq_enqueue(pWait->sq, pWait->wchan, "VBoxIS", &vbox_syncobj);
192
193 pWait->sq = NULL;
194 pWait->sq_lock = NULL;
195
196 int error = sleepq_block(pWait->iTimeout, pWait->fInterruptible
197#if __NetBSD_Prereq__(9,99,98) /* a bit later, actually... */
198 , &vbox_syncobj
199#endif
200 );
201 if (error == EWOULDBLOCK) {
202 if (!pWait->fIndefinite) {
203 pWait->fTimedOut = true;
204 }
205 } else if (error == ERESTART) {
206 if (pWait->fInterruptible) {
207 pWait->fInterrupted = true;
208 } else if (!pWait->fIndefinite) {
209 rtR0SemBsdWaitUpdateTimeout(pWait);
210 if (pWait->iTimeout == 0) {
211 pWait->fTimedOut = true;
212 }
213 }
214 } else if (error == EINTR) {
215 if (pWait->fInterruptible) {
216 pWait->fInterrupted = true;
217 } else if (!pWait->fIndefinite) {
218 rtR0SemBsdWaitUpdateTimeout(pWait);
219 if (pWait->iTimeout == 0) {
220 pWait->fTimedOut = true;
221 }
222 }
223 } else if (error) {
224 AssertMsgFailed(("sleepq_block -> %d\n", error));
225 }
226}
227
228
229/**
230 * Checks if a NetBSD wait was interrupted.
231 *
232 * @returns true / false
233 * @param pWait The wait structure.
234 * @remarks This shall be called before the first rtR0SemLnxWaitDoIt().
235 */
236DECLINLINE(bool) rtR0SemBsdWaitWasInterrupted(PRTR0SEMBSDSLEEP pWait)
237{
238 return pWait->fInterrupted;
239}
240
241
242/**
243 * Checks if a NetBSD wait has timed out.
244 *
245 * @returns true / false
246 * @param pWait The wait structure.
247 */
248DECLINLINE(bool) rtR0SemBsdWaitHasTimedOut(PRTR0SEMBSDSLEEP pWait)
249{
250 return pWait->fTimedOut;
251}
252
253
254/**
255 * Deletes a NetBSD wait.
256 *
257 * @param pWait The wait structure.
258 */
259DECLINLINE(void) rtR0SemBsdWaitDelete(PRTR0SEMBSDSLEEP pWait)
260{
261 if (pWait->sq_lock != NULL) {
262 mutex_spin_exit(pWait->sq_lock);
263 pWait->sq = NULL;
264 pWait->sq_lock = NULL;
265 }
266}
267
268
269/**
270 * Signals the wait channel.
271 *
272 * @param pvWaitChan The opaque wait channel handle.
273 */
274DECLINLINE(void) rtR0SemBsdSignal(void *pvWaitChan)
275{
276 kmutex_t *mp;
277 sleepq_t *sq = sleeptab_lookup(&sleeptab, pvWaitChan, &mp);
278 sleepq_wake(sq, pvWaitChan, 1, mp);
279}
280
281/**
282 * Wakes up all waiters on the wait channel.
283 *
284 * @param pvWaitChan The opaque wait channel handle.
285 */
286DECLINLINE(void) rtR0SemBsdBroadcast(void *pvWaitChan)
287{
288 kmutex_t *mp;
289 sleepq_t *sq = sleeptab_lookup(&sleeptab, pvWaitChan, &mp);
290 sleepq_wake(sq, pvWaitChan, ~0u, mp);
291}
292
293/**
294 * Gets the max resolution of the timeout machinery.
295 *
296 * @returns Resolution specified in nanoseconds.
297 */
298DECLINLINE(uint32_t) rtR0SemBsdWaitGetResolution(void)
299{
300 return 1000000000 / hz; /* ns */
301}
302
303#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