VirtualBox

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

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

IPRT: Added RTSemEventGetResolution and RTSemEventMultiGetResolution to r0drv.

  • 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 33155 2010-10-15 12:07:44Z 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
36#include <iprt/semaphore.h>
37#include <iprt/alloc.h>
38#include <iprt/asm.h>
39#include <iprt/assert.h>
40#include <iprt/err.h>
41#include <iprt/spinlock.h>
42
43#include "internal/magics.h"
44
45/*******************************************************************************
46* Structures and Typedefs *
47*******************************************************************************/
48/**
49 * FreeBSD multiple release event semaphore.
50 */
51typedef struct RTSEMEVENTMULTIINTERNAL
52{
53 /** Magic value (RTSEMEVENTMULTI_MAGIC). */
54 uint32_t volatile u32Magic;
55 /** The number of waiting threads. */
56 uint32_t volatile cWaiters;
57 /** Set if the event object is signaled. */
58 uint8_t volatile fSignaled;
59 /** The number of threads in the process of waking up. */
60 uint32_t volatile cWaking;
61 /** Spinlock protecting this structure. */
62 RTSPINLOCK hSpinLock;
63} RTSEMEVENTMULTIINTERNAL, *PRTSEMEVENTMULTIINTERNAL;
64
65
66RTDECL(int) RTSemEventMultiCreate(PRTSEMEVENTMULTI phEventMultiSem)
67{
68 return RTSemEventMultiCreateEx(phEventMultiSem, 0 /*fFlags*/, NIL_RTLOCKVALCLASS, NULL);
69}
70
71
72RTDECL(int) RTSemEventMultiCreateEx(PRTSEMEVENTMULTI phEventMultiSem, uint32_t fFlags, RTLOCKVALCLASS hClass,
73 const char *pszNameFmt, ...)
74{
75 AssertCompile(sizeof(RTSEMEVENTMULTIINTERNAL) > sizeof(void *));
76 AssertReturn(!(fFlags & ~RTSEMEVENTMULTI_FLAGS_NO_LOCK_VAL), VERR_INVALID_PARAMETER);
77 AssertPtrReturn(phEventMultiSem, VERR_INVALID_POINTER);
78
79 PRTSEMEVENTMULTIINTERNAL pThis = (PRTSEMEVENTMULTIINTERNAL)RTMemAllocZ(sizeof(*pThis));
80 if (pThis)
81 {
82 pThis->u32Magic = RTSEMEVENTMULTI_MAGIC;
83 pThis->cWaiters = 0;
84 pThis->cWaking = 0;
85 pThis->fSignaled = 0;
86 int rc = RTSpinlockCreate(&pThis->hSpinLock);
87 if (RT_SUCCESS(rc))
88 {
89 *phEventMultiSem = pThis;
90 return VINF_SUCCESS;
91 }
92
93 RTMemFree(pThis);
94 return rc;
95 }
96 return VERR_NO_MEMORY;
97}
98
99
100RTDECL(int) RTSemEventMultiDestroy(RTSEMEVENTMULTI hEventMultiSem)
101{
102 PRTSEMEVENTMULTIINTERNAL pThis = (PRTSEMEVENTMULTIINTERNAL)hEventMultiSem;
103 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
104
105 if (pThis == NIL_RTSEMEVENTMULTI)
106 return VINF_SUCCESS;
107 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
108 AssertMsgReturn(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC, ("pThis=%p u32Magic=%#x\n", pThis, pThis->u32Magic), VERR_INVALID_HANDLE);
109
110 RTSpinlockAcquire(pThis->hSpinLock, &Tmp);
111 ASMAtomicIncU32(&pThis->u32Magic); /* make the handle invalid */
112 if (pThis->cWaiters > 0)
113 {
114 /* abort waiting thread, last man cleans up. */
115 ASMAtomicXchgU32(&pThis->cWaking, pThis->cWaking + pThis->cWaiters);
116 sleepq_lock(pThis);
117 sleepq_broadcast(pThis, SLEEPQ_CONDVAR, 0, 0);
118 sleepq_release(pThis);
119 RTSpinlockRelease(pThis->hSpinLock, &Tmp);
120 }
121 else if (pThis->cWaking)
122 /* the last waking thread is gonna do the cleanup */
123 RTSpinlockRelease(pThis->hSpinLock, &Tmp);
124 else
125 {
126 RTSpinlockRelease(pThis->hSpinLock, &Tmp);
127 RTSpinlockDestroy(pThis->hSpinLock);
128 RTMemFree(pThis);
129 }
130
131 return VINF_SUCCESS;
132}
133
134
135RTDECL(int) RTSemEventMultiSignal(RTSEMEVENTMULTI hEventMultiSem)
136{
137 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
138 PRTSEMEVENTMULTIINTERNAL pThis = (PRTSEMEVENTMULTIINTERNAL)hEventMultiSem;
139 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
140 AssertMsgReturn(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC,
141 ("pThis=%p u32Magic=%#x\n", pThis, pThis->u32Magic),
142 VERR_INVALID_HANDLE);
143
144 RTSpinlockAcquire(pThis->hSpinLock, &Tmp);
145
146 ASMAtomicXchgU8(&pThis->fSignaled, true);
147 if (pThis->cWaiters > 0)
148 {
149 ASMAtomicXchgU32(&pThis->cWaking, pThis->cWaking + pThis->cWaiters);
150 ASMAtomicXchgU32(&pThis->cWaiters, 0);
151 sleepq_lock(pThis);
152 int fWakeupSwapProc = sleepq_signal(pThis, SLEEPQ_CONDVAR, 0, 0);
153 sleepq_release(pThis);
154 if (fWakeupSwapProc)
155 kick_proc0();
156 }
157
158 RTSpinlockRelease(pThis->hSpinLock, &Tmp);
159 return VINF_SUCCESS;
160}
161
162
163RTDECL(int) RTSemEventMultiReset(RTSEMEVENTMULTI hEventMultiSem)
164{
165 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
166 PRTSEMEVENTMULTIINTERNAL pThis = (PRTSEMEVENTMULTIINTERNAL)hEventMultiSem;
167 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
168 AssertMsgReturn(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC,
169 ("pThis=%p u32Magic=%#x\n", pThis, pThis->u32Magic),
170 VERR_INVALID_HANDLE);
171
172 RTSpinlockAcquire(pThis->hSpinLock, &Tmp);
173 ASMAtomicXchgU8(&pThis->fSignaled, false);
174 RTSpinlockRelease(pThis->hSpinLock, &Tmp);
175 return VINF_SUCCESS;
176}
177
178
179static int rtSemEventMultiWait(RTSEMEVENTMULTI hEventMultiSem, RTMSINTERVAL cMillies, bool fInterruptible)
180{
181 int rc;
182 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
183 PRTSEMEVENTMULTIINTERNAL pThis = (PRTSEMEVENTMULTIINTERNAL)hEventMultiSem;
184 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
185 AssertMsgReturn(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC,
186 ("pThis=%p u32Magic=%#x\n", pThis, pThis->u32Magic),
187 VERR_INVALID_HANDLE);
188
189 RTSpinlockAcquire(pThis->hSpinLock, &Tmp);
190
191 if (pThis->fSignaled)
192 rc = VINF_SUCCESS;
193 else
194 {
195 if (cMillies == 0)
196 rc = VERR_TIMEOUT;
197 else
198 {
199 ASMAtomicIncU32(&pThis->cWaiters);
200
201 int fFlags = SLEEPQ_CONDVAR;
202
203 if (fInterruptible)
204 fFlags |= SLEEPQ_INTERRUPTIBLE;
205
206 sleepq_lock(pThis);
207 sleepq_add(pThis, NULL, "IPRT Event Semaphore", fFlags, 0);
208
209 if (cMillies != RT_INDEFINITE_WAIT)
210 {
211 /*
212 * Translate milliseconds into ticks and go to sleep.
213 */
214 struct timeval tv;
215
216 tv.tv_sec = cMillies / 1000;
217 tv.tv_usec = (cMillies % 1000) * 1000;
218
219 sleepq_set_timeout(pThis, tvtohz(&tv));
220
221 RTSpinlockRelease(pThis->hSpinLock, &Tmp);
222
223 if (fInterruptible)
224 rc = SLEEPQ_TIMEDWAIT_SIG(pThis);
225 else
226 rc = SLEEPQ_TIMEDWAIT(pThis);
227 }
228 else
229 {
230 RTSpinlockRelease(pThis->hSpinLock, &Tmp);
231
232 if (fInterruptible)
233 rc = SLEEPQ_WAIT_SIG(pThis);
234 else
235 {
236 rc = 0;
237 SLEEPQ_WAIT(pThis);
238 }
239 }
240
241 RTSpinlockAcquire(pThis->hSpinLock, &Tmp);
242
243 switch (rc)
244 {
245 case 0:
246 if (pThis->u32Magic == RTSEMEVENTMULTI_MAGIC)
247 {
248 ASMAtomicDecU32(&pThis->cWaking);
249 rc = VINF_SUCCESS;
250 }
251 else
252 {
253 rc = VERR_SEM_DESTROYED; /** @todo this isn't necessarily correct, we've
254 * could've woken up just before destruction... */
255 if (!ASMAtomicDecU32(&pThis->cWaking))
256 {
257 /* The event was destroyed, as the last thread do the cleanup.
258 we don't actually know whether */
259 RTSpinlockRelease(pThis->hSpinLock, &Tmp);
260 RTSpinlockDestroy(pThis->hSpinLock);
261 RTMemFree(pThis);
262 return rc;
263 }
264 }
265 break;
266
267 case EWOULDBLOCK:
268 Assert(cMillies != RT_INDEFINITE_WAIT);
269 if (pThis->cWaiters > 0)
270 ASMAtomicDecU32(&pThis->cWaiters);
271 rc = VERR_TIMEOUT;
272 break;
273
274 case EINTR:
275 case ERESTART:
276 Assert(fInterruptible);
277 if (pThis->cWaiters > 0)
278 ASMAtomicDecU32(&pThis->cWaiters);
279 rc = VERR_INTERRUPTED;
280 break;
281
282 default:
283 AssertMsgFailed(("sleepq_* -> %d\n", rc));
284 rc = VERR_GENERAL_FAILURE;
285 break;
286 }
287 }
288 }
289
290 RTSpinlockRelease(pThis->hSpinLock, &Tmp);
291 return rc;
292}
293
294
295RTDECL(int) RTSemEventMultiWait(RTSEMEVENTMULTI hEventMultiSem, RTMSINTERVAL cMillies)
296{
297 return rtSemEventMultiWait(hEventMultiSem, cMillies, false /* not interruptible */);
298}
299
300
301RTDECL(int) RTSemEventMultiWaitNoResume(RTSEMEVENTMULTI hEventMultiSem, RTMSINTERVAL cMillies)
302{
303 return rtSemEventMultiWait(hEventMultiSem, cMillies, true /* interruptible */);
304}
305
306
307RTDECL(uint32_t) RTSemEventMultiGetResolution(void)
308{
309 return 1000000000 / hz;
310}
311
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