VirtualBox

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

Last change on this file since 57984 was 57358, checked in by vboxsync, 9 years ago

*: scm cleanup run.

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