VirtualBox

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

Last change on this file since 36190 was 36190, checked in by vboxsync, 14 years ago

IPRT,Drivers: Committed a modified version of the diff_linux_guest_host patch. This mangles the IPRT symbols in kernel space on linux and later other platforms.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 10.5 KB
Line 
1/* $Id: semeventmulti-r0drv-freebsd.c 36190 2011-03-07 16:28:50Z 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* Header Files *
33*******************************************************************************/
34#define RTSEMEVENTMULTI_WITHOUT_REMAPPING
35#include "the-freebsd-kernel.h"
36#include "internal/iprt.h"
37#include <iprt/semaphore.h>
38
39#include <iprt/assert.h>
40#include <iprt/asm.h>
41#include <iprt/err.h>
42#include <iprt/mem.h>
43#include <iprt/lockvalidator.h>
44
45#include "sleepqueue-r0drv-freebsd.h"
46#include "internal/magics.h"
47
48
49/*******************************************************************************
50* Defined Constants And Macros *
51*******************************************************************************/
52/** @name fStateAndGen values
53 * @{ */
54/** The state bit number. */
55#define RTSEMEVENTMULTIBSD_STATE_BIT 0
56/** The state mask. */
57#define RTSEMEVENTMULTIBSD_STATE_MASK RT_BIT_32(RTSEMEVENTMULTIBSD_STATE_BIT)
58/** The generation mask. */
59#define RTSEMEVENTMULTIBSD_GEN_MASK ~RTSEMEVENTMULTIBSD_STATE_MASK
60/** The generation shift. */
61#define RTSEMEVENTMULTIBSD_GEN_SHIFT 1
62/** The initial variable value. */
63#define RTSEMEVENTMULTIBSD_STATE_GEN_INIT UINT32_C(0xfffffffc)
64/** @} */
65
66/*******************************************************************************
67* Structures and Typedefs *
68*******************************************************************************/
69/**
70 * FreeBSD multiple release event semaphore.
71 */
72typedef struct RTSEMEVENTMULTIINTERNAL
73{
74 /** Magic value (RTSEMEVENTMULTI_MAGIC). */
75 uint32_t volatile u32Magic;
76 /** The object state bit and generation counter.
77 * The generation counter is incremented every time the object is
78 * signalled. */
79 uint32_t volatile fStateAndGen;
80 /** Reference counter. */
81 uint32_t volatile cRefs;
82} RTSEMEVENTMULTIINTERNAL, *PRTSEMEVENTMULTIINTERNAL;
83
84
85RTDECL(int) RTSemEventMultiCreate(PRTSEMEVENTMULTI phEventMultiSem)
86{
87 return RTSemEventMultiCreateEx(phEventMultiSem, 0 /*fFlags*/, NIL_RTLOCKVALCLASS, NULL);
88}
89
90
91RTDECL(int) RTSemEventMultiCreateEx(PRTSEMEVENTMULTI phEventMultiSem, uint32_t fFlags, RTLOCKVALCLASS hClass,
92 const char *pszNameFmt, ...)
93{
94 PRTSEMEVENTMULTIINTERNAL pThis;
95
96 AssertReturn(!(fFlags & ~RTSEMEVENTMULTI_FLAGS_NO_LOCK_VAL), VERR_INVALID_PARAMETER);
97 pThis = (PRTSEMEVENTMULTIINTERNAL)RTMemAlloc(sizeof(*pThis));
98 if (pThis)
99 {
100 pThis->u32Magic = RTSEMEVENTMULTI_MAGIC;
101 pThis->fStateAndGen = RTSEMEVENTMULTIBSD_STATE_GEN_INIT;
102 pThis->cRefs = 1;
103
104 *phEventMultiSem = pThis;
105 return VINF_SUCCESS;
106 }
107 return VERR_NO_MEMORY;
108}
109
110
111/**
112 * Retain a reference to the semaphore.
113 *
114 * @param pThis The semaphore.
115 */
116DECLINLINE(void) rtR0SemEventMultiBsdRetain(PRTSEMEVENTMULTIINTERNAL pThis)
117{
118 uint32_t cRefs = ASMAtomicIncU32(&pThis->cRefs);
119 Assert(cRefs && cRefs < 100000);
120}
121
122
123/**
124 * Release a reference, destroy the thing if necessary.
125 *
126 * @param pThis The semaphore.
127 */
128DECLINLINE(void) rtR0SemEventMultiBsdRelease(PRTSEMEVENTMULTIINTERNAL pThis)
129{
130 if (RT_UNLIKELY(ASMAtomicDecU32(&pThis->cRefs) == 0))
131 {
132 Assert(pThis->u32Magic != RTSEMEVENTMULTI_MAGIC);
133 RTMemFree(pThis);
134 }
135}
136
137
138RTDECL(int) RTSemEventMultiDestroy(RTSEMEVENTMULTI hEventMultiSem)
139{
140 /*
141 * Validate input.
142 */
143 PRTSEMEVENTMULTIINTERNAL pThis = (PRTSEMEVENTMULTIINTERNAL)hEventMultiSem;
144 if (pThis == NIL_RTSEMEVENTMULTI)
145 return VINF_SUCCESS;
146 AssertPtrReturn(pThis, VERR_INVALID_PARAMETER);
147 AssertMsgReturn(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC, ("%p u32Magic=%RX32\n", pThis, pThis->u32Magic), VERR_INVALID_PARAMETER);
148 Assert(pThis->cRefs > 0);
149
150 /*
151 * Invalidate it and signal the object just in case.
152 */
153 ASMAtomicWriteU32(&pThis->u32Magic, ~RTSEMEVENTMULTI_MAGIC);
154 ASMAtomicAndU32(&pThis->fStateAndGen, RTSEMEVENTMULTIBSD_GEN_MASK);
155 rtR0SemBsdBroadcast(pThis);
156 rtR0SemEventMultiBsdRelease(pThis);
157 return VINF_SUCCESS;
158}
159
160
161RTDECL(int) RTSemEventMultiSignal(RTSEMEVENTMULTI hEventMultiSem)
162{
163 uint32_t fNew;
164 uint32_t fOld;
165
166 /*
167 * Validate input.
168 */
169 PRTSEMEVENTMULTIINTERNAL pThis = (PRTSEMEVENTMULTIINTERNAL)hEventMultiSem;
170 if (!pThis)
171 return VERR_INVALID_PARAMETER;
172 AssertPtrReturn(pThis, VERR_INVALID_PARAMETER);
173 AssertMsgReturn(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC, ("%p u32Magic=%RX32\n", pThis, pThis->u32Magic), VERR_INVALID_PARAMETER);
174 rtR0SemEventMultiBsdRetain(pThis);
175
176 /*
177 * Signal the event object. The cause of the parnoia here is racing to try
178 * deal with racing RTSemEventMultiSignal calls (should probably be
179 * forbidden, but it's relatively easy to handle).
180 */
181 do
182 {
183 fNew = fOld = ASMAtomicUoReadU32(&pThis->fStateAndGen);
184 fNew += 1 << RTSEMEVENTMULTIBSD_GEN_SHIFT;
185 fNew |= RTSEMEVENTMULTIBSD_STATE_MASK;
186 }
187 while (!ASMAtomicCmpXchgU32(&pThis->fStateAndGen, fNew, fOld));
188
189 rtR0SemBsdBroadcast(pThis);
190 rtR0SemEventMultiBsdRelease(pThis);
191 return VINF_SUCCESS;
192}
193
194
195RTDECL(int) RTSemEventMultiReset(RTSEMEVENTMULTI hEventMultiSem)
196{
197 /*
198 * Validate input.
199 */
200 PRTSEMEVENTMULTIINTERNAL pThis = (PRTSEMEVENTMULTIINTERNAL)hEventMultiSem;
201 if (!pThis)
202 return VERR_INVALID_PARAMETER;
203 AssertPtrReturn(pThis, VERR_INVALID_PARAMETER);
204 AssertMsgReturn(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC, ("%p u32Magic=%RX32\n", pThis, pThis->u32Magic), VERR_INVALID_PARAMETER);
205 rtR0SemEventMultiBsdRetain(pThis);
206
207 /*
208 * Reset it.
209 */
210 ASMAtomicAndU32(&pThis->fStateAndGen, ~RTSEMEVENTMULTIBSD_STATE_MASK);
211
212 rtR0SemEventMultiBsdRelease(pThis);
213 return VINF_SUCCESS;
214}
215
216
217/**
218 * Worker for RTSemEventMultiWaitEx and RTSemEventMultiWaitExDebug.
219 *
220 * @returns VBox status code.
221 * @param pThis The event semaphore.
222 * @param fFlags See RTSemEventMultiWaitEx.
223 * @param uTimeout See RTSemEventMultiWaitEx.
224 * @param pSrcPos The source code position of the wait.
225 */
226static int rtR0SemEventMultiBsdWait(PRTSEMEVENTMULTIINTERNAL pThis, uint32_t fFlags, uint64_t uTimeout,
227 PCRTLOCKVALSRCPOS pSrcPos)
228{
229 uint32_t fOrgStateAndGen;
230 int rc;
231
232 /*
233 * Validate the input.
234 */
235 AssertPtrReturn(pThis, VERR_INVALID_PARAMETER);
236 AssertMsgReturn(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC, ("%p u32Magic=%RX32\n", pThis, pThis->u32Magic), VERR_INVALID_PARAMETER);
237 AssertReturn(RTSEMWAIT_FLAGS_ARE_VALID(fFlags), VERR_INVALID_PARAMETER);
238 rtR0SemEventMultiBsdRetain(pThis);
239
240 /*
241 * Is the event already signalled or do we have to wait?
242 */
243 fOrgStateAndGen = ASMAtomicUoReadU32(&pThis->fStateAndGen);
244 if (fOrgStateAndGen & RTSEMEVENTMULTIBSD_STATE_MASK)
245 rc = VINF_SUCCESS;
246 else
247 {
248 /*
249 * We have to wait.
250 */
251 RTR0SEMBSDSLEEP Wait;
252 rc = rtR0SemBsdWaitInit(&Wait, fFlags, uTimeout, pThis);
253 if (RT_SUCCESS(rc))
254 {
255 for (;;)
256 {
257 /* The destruction test. */
258 if (RT_UNLIKELY(pThis->u32Magic != RTSEMEVENTMULTI_MAGIC))
259 rc = VERR_SEM_DESTROYED;
260 else
261 {
262 rtR0SemBsdWaitPrepare(&Wait);
263
264 /* Check the exit conditions. */
265 if (RT_UNLIKELY(pThis->u32Magic != RTSEMEVENTMULTI_MAGIC))
266 rc = VERR_SEM_DESTROYED;
267 else if (ASMAtomicUoReadU32(&pThis->fStateAndGen) != fOrgStateAndGen)
268 rc = VINF_SUCCESS;
269 else if (rtR0SemBsdWaitHasTimedOut(&Wait))
270 rc = VERR_TIMEOUT;
271 else if (rtR0SemBsdWaitWasInterrupted(&Wait))
272 rc = VERR_INTERRUPTED;
273 else
274 {
275 /* Do the wait and then recheck the conditions. */
276 rtR0SemBsdWaitDoIt(&Wait);
277 continue;
278 }
279 }
280 break;
281 }
282
283 rtR0SemBsdWaitDelete(&Wait);
284 }
285 }
286
287 rtR0SemEventMultiBsdRelease(pThis);
288 return rc;
289}
290
291
292RTDECL(int) RTSemEventMultiWaitEx(RTSEMEVENTMULTI hEventMultiSem, uint32_t fFlags, uint64_t uTimeout)
293{
294#ifndef RTSEMEVENT_STRICT
295 return rtR0SemEventMultiBsdWait(hEventMultiSem, fFlags, uTimeout, NULL);
296#else
297 RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_NORMAL_API();
298 return rtR0SemEventMultiBsdWait(hEventMultiSem, fFlags, uTimeout, &SrcPos);
299#endif
300}
301RT_EXPORT_SYMBOL(RTSemEventMultiWaitEx);
302
303
304RTDECL(int) RTSemEventMultiWaitExDebug(RTSEMEVENTMULTI hEventMultiSem, uint32_t fFlags, uint64_t uTimeout,
305 RTHCUINTPTR uId, RT_SRC_POS_DECL)
306{
307 RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_DEBUG_API();
308 return rtR0SemEventMultiBsdWait(hEventMultiSem, fFlags, uTimeout, &SrcPos);
309}
310RT_EXPORT_SYMBOL(RTSemEventMultiWaitExDebug);
311
312
313RTDECL(uint32_t) RTSemEventMultiGetResolution(void)
314{
315 return rtR0SemBsdWaitGetResolution();
316}
317RT_EXPORT_SYMBOL(RTSemEventMultiGetResolution);
318
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