VirtualBox

source: vbox/trunk/src/VBox/Runtime/r0drv/freebsd/semeventmulti-r0drv-freebsd.c

Last change on this file was 98103, checked in by vboxsync, 17 months ago

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 12.5 KB
Line 
1/* $Id: semeventmulti-r0drv-freebsd.c 98103 2023-01-17 14:15:46Z vboxsync $ */
2/** @file
3 * IPRT - Multiple Release Event Semaphores, Ring-0 Driver, FreeBSD.
4 */
5
6/*
7 * Contributed by knut st. osmundsen.
8 *
9 * Copyright (C) 2007-2023 Oracle and/or its affiliates.
10 *
11 * This file is part of VirtualBox base platform packages, as
12 * available from https://www.virtualbox.org.
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation, in version 3 of the
17 * License.
18 *
19 * This program is distributed in the hope that it will be useful, but
20 * WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 * General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, see <https://www.gnu.org/licenses>.
26 *
27 * The contents of this file may alternatively be used under the terms
28 * of the Common Development and Distribution License Version 1.0
29 * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
30 * in the VirtualBox distribution, in which case the provisions of the
31 * CDDL are applicable instead of those of the GPL.
32 *
33 * You may elect to license modified versions of this file under the
34 * terms and conditions of either the GPL or the CDDL or both.
35 *
36 * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
37 * --------------------------------------------------------------------
38 *
39 * This code is based on:
40 *
41 * Copyright (c) 2007 knut st. osmundsen <bird-src-spam@anduin.net>
42 *
43 * Permission is hereby granted, free of charge, to any person
44 * obtaining a copy of this software and associated documentation
45 * files (the "Software"), to deal in the Software without
46 * restriction, including without limitation the rights to use,
47 * copy, modify, merge, publish, distribute, sublicense, and/or sell
48 * copies of the Software, and to permit persons to whom the
49 * Software is furnished to do so, subject to the following
50 * conditions:
51 *
52 * The above copyright notice and this permission notice shall be
53 * included in all copies or substantial portions of the Software.
54 *
55 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
56 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
57 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
58 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
59 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
60 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
61 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
62 * OTHER DEALINGS IN THE SOFTWARE.
63 */
64
65
66/*********************************************************************************************************************************
67* Header Files *
68*********************************************************************************************************************************/
69#define RTSEMEVENTMULTI_WITHOUT_REMAPPING
70#include "the-freebsd-kernel.h"
71#include "internal/iprt.h"
72#include <iprt/semaphore.h>
73
74#include <iprt/assert.h>
75#include <iprt/asm.h>
76#include <iprt/err.h>
77#include <iprt/mem.h>
78#include <iprt/lockvalidator.h>
79
80#include "sleepqueue-r0drv-freebsd.h"
81#include "internal/magics.h"
82
83
84/*********************************************************************************************************************************
85* Defined Constants And Macros *
86*********************************************************************************************************************************/
87/** @name fStateAndGen values
88 * @{ */
89/** The state bit number. */
90#define RTSEMEVENTMULTIBSD_STATE_BIT 0
91/** The state mask. */
92#define RTSEMEVENTMULTIBSD_STATE_MASK RT_BIT_32(RTSEMEVENTMULTIBSD_STATE_BIT)
93/** The generation mask. */
94#define RTSEMEVENTMULTIBSD_GEN_MASK ~RTSEMEVENTMULTIBSD_STATE_MASK
95/** The generation shift. */
96#define RTSEMEVENTMULTIBSD_GEN_SHIFT 1
97/** The initial variable value. */
98#define RTSEMEVENTMULTIBSD_STATE_GEN_INIT UINT32_C(0xfffffffc)
99/** @} */
100
101
102/*********************************************************************************************************************************
103* Structures and Typedefs *
104*********************************************************************************************************************************/
105/**
106 * FreeBSD multiple release event semaphore.
107 */
108typedef struct RTSEMEVENTMULTIINTERNAL
109{
110 /** Magic value (RTSEMEVENTMULTI_MAGIC). */
111 uint32_t volatile u32Magic;
112 /** The object state bit and generation counter.
113 * The generation counter is incremented every time the object is
114 * signalled. */
115 uint32_t volatile fStateAndGen;
116 /** Reference counter. */
117 uint32_t volatile cRefs;
118} RTSEMEVENTMULTIINTERNAL, *PRTSEMEVENTMULTIINTERNAL;
119
120
121RTDECL(int) RTSemEventMultiCreate(PRTSEMEVENTMULTI phEventMultiSem)
122{
123 return RTSemEventMultiCreateEx(phEventMultiSem, 0 /*fFlags*/, NIL_RTLOCKVALCLASS, NULL);
124}
125
126
127RTDECL(int) RTSemEventMultiCreateEx(PRTSEMEVENTMULTI phEventMultiSem, uint32_t fFlags, RTLOCKVALCLASS hClass,
128 const char *pszNameFmt, ...)
129{
130 PRTSEMEVENTMULTIINTERNAL pThis;
131
132 AssertReturn(!(fFlags & ~RTSEMEVENTMULTI_FLAGS_NO_LOCK_VAL), VERR_INVALID_PARAMETER);
133 pThis = (PRTSEMEVENTMULTIINTERNAL)RTMemAlloc(sizeof(*pThis));
134 if (pThis)
135 {
136 pThis->u32Magic = RTSEMEVENTMULTI_MAGIC;
137 pThis->fStateAndGen = RTSEMEVENTMULTIBSD_STATE_GEN_INIT;
138 pThis->cRefs = 1;
139
140 *phEventMultiSem = pThis;
141 return VINF_SUCCESS;
142 }
143 return VERR_NO_MEMORY;
144}
145
146
147/**
148 * Retain a reference to the semaphore.
149 *
150 * @param pThis The semaphore.
151 */
152DECLINLINE(void) rtR0SemEventMultiBsdRetain(PRTSEMEVENTMULTIINTERNAL pThis)
153{
154 uint32_t cRefs = ASMAtomicIncU32(&pThis->cRefs);
155 Assert(cRefs && cRefs < 100000);
156}
157
158
159/**
160 * Release a reference, destroy the thing if necessary.
161 *
162 * @param pThis The semaphore.
163 */
164DECLINLINE(void) rtR0SemEventMultiBsdRelease(PRTSEMEVENTMULTIINTERNAL pThis)
165{
166 if (RT_UNLIKELY(ASMAtomicDecU32(&pThis->cRefs) == 0))
167 {
168 Assert(pThis->u32Magic != RTSEMEVENTMULTI_MAGIC);
169 RTMemFree(pThis);
170 }
171}
172
173
174RTDECL(int) RTSemEventMultiDestroy(RTSEMEVENTMULTI hEventMultiSem)
175{
176 /*
177 * Validate input.
178 */
179 PRTSEMEVENTMULTIINTERNAL pThis = (PRTSEMEVENTMULTIINTERNAL)hEventMultiSem;
180 if (pThis == NIL_RTSEMEVENTMULTI)
181 return VINF_SUCCESS;
182 AssertPtrReturn(pThis, VERR_INVALID_PARAMETER);
183 AssertMsgReturn(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC, ("%p u32Magic=%RX32\n", pThis, pThis->u32Magic), VERR_INVALID_PARAMETER);
184 Assert(pThis->cRefs > 0);
185
186 /*
187 * Invalidate it and signal the object just in case.
188 */
189 ASMAtomicWriteU32(&pThis->u32Magic, ~RTSEMEVENTMULTI_MAGIC);
190 ASMAtomicAndU32(&pThis->fStateAndGen, RTSEMEVENTMULTIBSD_GEN_MASK);
191 rtR0SemBsdBroadcast(pThis);
192 rtR0SemEventMultiBsdRelease(pThis);
193 return VINF_SUCCESS;
194}
195
196
197RTDECL(int) RTSemEventMultiSignal(RTSEMEVENTMULTI hEventMultiSem)
198{
199 uint32_t fNew;
200 uint32_t fOld;
201
202 /*
203 * Validate input.
204 */
205 PRTSEMEVENTMULTIINTERNAL pThis = (PRTSEMEVENTMULTIINTERNAL)hEventMultiSem;
206 if (!pThis)
207 return VERR_INVALID_PARAMETER;
208 AssertPtrReturn(pThis, VERR_INVALID_PARAMETER);
209 AssertMsgReturn(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC, ("%p u32Magic=%RX32\n", pThis, pThis->u32Magic), VERR_INVALID_PARAMETER);
210 rtR0SemEventMultiBsdRetain(pThis);
211
212 /*
213 * Signal the event object. The cause of the parnoia here is racing to try
214 * deal with racing RTSemEventMultiSignal calls (should probably be
215 * forbidden, but it's relatively easy to handle).
216 */
217 do
218 {
219 fNew = fOld = ASMAtomicUoReadU32(&pThis->fStateAndGen);
220 fNew += 1 << RTSEMEVENTMULTIBSD_GEN_SHIFT;
221 fNew |= RTSEMEVENTMULTIBSD_STATE_MASK;
222 }
223 while (!ASMAtomicCmpXchgU32(&pThis->fStateAndGen, fNew, fOld));
224
225 rtR0SemBsdBroadcast(pThis);
226 rtR0SemEventMultiBsdRelease(pThis);
227 return VINF_SUCCESS;
228}
229
230
231RTDECL(int) RTSemEventMultiReset(RTSEMEVENTMULTI hEventMultiSem)
232{
233 /*
234 * Validate input.
235 */
236 PRTSEMEVENTMULTIINTERNAL pThis = (PRTSEMEVENTMULTIINTERNAL)hEventMultiSem;
237 if (!pThis)
238 return VERR_INVALID_PARAMETER;
239 AssertPtrReturn(pThis, VERR_INVALID_PARAMETER);
240 AssertMsgReturn(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC, ("%p u32Magic=%RX32\n", pThis, pThis->u32Magic), VERR_INVALID_PARAMETER);
241 rtR0SemEventMultiBsdRetain(pThis);
242
243 /*
244 * Reset it.
245 */
246 ASMAtomicAndU32(&pThis->fStateAndGen, ~RTSEMEVENTMULTIBSD_STATE_MASK);
247
248 rtR0SemEventMultiBsdRelease(pThis);
249 return VINF_SUCCESS;
250}
251
252
253/**
254 * Worker for RTSemEventMultiWaitEx and RTSemEventMultiWaitExDebug.
255 *
256 * @returns VBox status code.
257 * @param pThis The event semaphore.
258 * @param fFlags See RTSemEventMultiWaitEx.
259 * @param uTimeout See RTSemEventMultiWaitEx.
260 * @param pSrcPos The source code position of the wait.
261 */
262static int rtR0SemEventMultiBsdWait(PRTSEMEVENTMULTIINTERNAL pThis, uint32_t fFlags, uint64_t uTimeout,
263 PCRTLOCKVALSRCPOS pSrcPos)
264{
265 uint32_t fOrgStateAndGen;
266 int rc;
267
268 /*
269 * Validate the input.
270 */
271 AssertPtrReturn(pThis, VERR_INVALID_PARAMETER);
272 AssertMsgReturn(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC, ("%p u32Magic=%RX32\n", pThis, pThis->u32Magic), VERR_INVALID_PARAMETER);
273 AssertReturn(RTSEMWAIT_FLAGS_ARE_VALID(fFlags), VERR_INVALID_PARAMETER);
274 rtR0SemEventMultiBsdRetain(pThis);
275
276 /*
277 * Is the event already signalled or do we have to wait?
278 */
279 fOrgStateAndGen = ASMAtomicUoReadU32(&pThis->fStateAndGen);
280 if (fOrgStateAndGen & RTSEMEVENTMULTIBSD_STATE_MASK)
281 rc = VINF_SUCCESS;
282 else
283 {
284 /*
285 * We have to wait.
286 */
287 RTR0SEMBSDSLEEP Wait;
288 rc = rtR0SemBsdWaitInit(&Wait, fFlags, uTimeout, pThis);
289 if (RT_SUCCESS(rc))
290 {
291 for (;;)
292 {
293 /* The destruction test. */
294 if (RT_UNLIKELY(pThis->u32Magic != RTSEMEVENTMULTI_MAGIC))
295 rc = VERR_SEM_DESTROYED;
296 else
297 {
298 rtR0SemBsdWaitPrepare(&Wait);
299
300 /* Check the exit conditions. */
301 if (RT_UNLIKELY(pThis->u32Magic != RTSEMEVENTMULTI_MAGIC))
302 rc = VERR_SEM_DESTROYED;
303 else if (ASMAtomicUoReadU32(&pThis->fStateAndGen) != fOrgStateAndGen)
304 rc = VINF_SUCCESS;
305 else if (rtR0SemBsdWaitHasTimedOut(&Wait))
306 rc = VERR_TIMEOUT;
307 else if (rtR0SemBsdWaitWasInterrupted(&Wait))
308 rc = VERR_INTERRUPTED;
309 else
310 {
311 /* Do the wait and then recheck the conditions. */
312 rtR0SemBsdWaitDoIt(&Wait);
313 continue;
314 }
315 }
316 break;
317 }
318
319 rtR0SemBsdWaitDelete(&Wait);
320 }
321 }
322
323 rtR0SemEventMultiBsdRelease(pThis);
324 return rc;
325}
326
327
328RTDECL(int) RTSemEventMultiWaitEx(RTSEMEVENTMULTI hEventMultiSem, uint32_t fFlags, uint64_t uTimeout)
329{
330#ifndef RTSEMEVENT_STRICT
331 return rtR0SemEventMultiBsdWait(hEventMultiSem, fFlags, uTimeout, NULL);
332#else
333 RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_NORMAL_API();
334 return rtR0SemEventMultiBsdWait(hEventMultiSem, fFlags, uTimeout, &SrcPos);
335#endif
336}
337RT_EXPORT_SYMBOL(RTSemEventMultiWaitEx);
338
339
340RTDECL(int) RTSemEventMultiWaitExDebug(RTSEMEVENTMULTI hEventMultiSem, uint32_t fFlags, uint64_t uTimeout,
341 RTHCUINTPTR uId, RT_SRC_POS_DECL)
342{
343 RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_DEBUG_API();
344 return rtR0SemEventMultiBsdWait(hEventMultiSem, fFlags, uTimeout, &SrcPos);
345}
346RT_EXPORT_SYMBOL(RTSemEventMultiWaitExDebug);
347
348
349RTDECL(uint32_t) RTSemEventMultiGetResolution(void)
350{
351 return rtR0SemBsdWaitGetResolution();
352}
353RT_EXPORT_SYMBOL(RTSemEventMultiGetResolution);
354
355
356RTR0DECL(bool) RTSemEventMultiIsSignalSafe(void)
357{
358 /** @todo check the code... */
359 return false;
360}
361RT_EXPORT_SYMBOL(RTSemEventMultiIsSignalSafe);
362
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use