VirtualBox

source: vbox/trunk/src/VBox/Runtime/r0drv/netbsd/semeventmulti-r0drv-netbsd.c@ 86669

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