VirtualBox

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

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

FreeBSD: Implement RTSemEvent{|Multi}WaitEx

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