VirtualBox

source: vbox/trunk/src/VBox/Runtime/r0drv/freebsd/semevent-r0drv-freebsd.c@ 24873

Last change on this file since 24873 was 22819, checked in by vboxsync, 15 years ago

FreeBSD: Fix R0 semevent implementation for FreeBSD 7.x

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 9.5 KB
Line 
1/* $Id: semevent-r0drv-freebsd.c 22819 2009-09-07 19:10:55Z vboxsync $ */
2/** @file
3 * IPRT - Single 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/*******************************************************************************
47* Structures and Typedefs *
48*******************************************************************************/
49/**
50 * FreeBSD event semaphore.
51 */
52typedef struct RTSEMEVENTINTERNAL
53{
54 /** Magic value (RTSEMEVENT_MAGIC). */
55 uint32_t volatile u32Magic;
56 /** The number of waiting threads. */
57 uint32_t volatile cWaiters;
58 /** Set if the event object is signaled. */
59 uint8_t volatile fSignaled;
60 /** The number of threads in the process of waking up. */
61 uint32_t volatile cWaking;
62 /** Spinlock protecting this structure. */
63 RTSPINLOCK hSpinLock;
64} RTSEMEVENTINTERNAL, *PRTSEMEVENTINTERNAL;
65
66
67RTDECL(int) RTSemEventCreate(PRTSEMEVENT pEventSem)
68{
69 Assert(sizeof(RTSEMEVENTINTERNAL) > sizeof(void *));
70 AssertPtrReturn(pEventSem, VERR_INVALID_POINTER);
71
72 PRTSEMEVENTINTERNAL pEventInt = (PRTSEMEVENTINTERNAL)RTMemAllocZ(sizeof(*pEventInt));
73 if (pEventInt)
74 {
75 pEventInt->u32Magic = RTSEMEVENT_MAGIC;
76 pEventInt->cWaiters = 0;
77 pEventInt->cWaking = 0;
78 pEventInt->fSignaled = 0;
79 int rc = RTSpinlockCreate(&pEventInt->hSpinLock);
80 if (RT_SUCCESS(rc))
81 {
82 *pEventSem = pEventInt;
83 return VINF_SUCCESS;
84 }
85
86 RTMemFree(pEventInt);
87 return rc;
88 }
89 return VERR_NO_MEMORY;
90}
91
92
93RTDECL(int) RTSemEventDestroy(RTSEMEVENT EventSem)
94{
95 if (EventSem == NIL_RTSEMEVENT) /* don't bitch */
96 return VERR_INVALID_HANDLE;
97 PRTSEMEVENTINTERNAL pEventInt = (PRTSEMEVENTINTERNAL)EventSem;
98 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
99
100 AssertPtrReturn(pEventInt, VERR_INVALID_HANDLE);
101 AssertMsgReturn(pEventInt->u32Magic == RTSEMEVENT_MAGIC,
102 ("pEventInt=%p u32Magic=%#x\n", pEventInt, pEventInt->u32Magic),
103 VERR_INVALID_HANDLE);
104
105 RTSpinlockAcquire(pEventInt->hSpinLock, &Tmp);
106
107 ASMAtomicIncU32(&pEventInt->u32Magic); /* make the handle invalid */
108 if (pEventInt->cWaiters > 0)
109 {
110 /* abort waiting thread, last man cleans up. */
111 ASMAtomicXchgU32(&pEventInt->cWaking, pEventInt->cWaking + pEventInt->cWaiters);
112 sleepq_lock(pEventInt);
113 sleepq_broadcast(pEventInt, SLEEPQ_CONDVAR, 0, 0);
114 sleepq_release(pEventInt);
115 RTSpinlockRelease(pEventInt->hSpinLock, &Tmp);
116 }
117 else if (pEventInt->cWaking)
118 /* the last waking thread is gonna do the cleanup */
119 RTSpinlockRelease(pEventInt->hSpinLock, &Tmp);
120 else
121 {
122 RTSpinlockRelease(pEventInt->hSpinLock, &Tmp);
123 RTSpinlockDestroy(pEventInt->hSpinLock);
124 RTMemFree(pEventInt);
125 }
126
127 return VINF_SUCCESS;
128}
129
130
131RTDECL(int) RTSemEventSignal(RTSEMEVENT EventSem)
132{
133 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
134 PRTSEMEVENTINTERNAL pEventInt = (PRTSEMEVENTINTERNAL)EventSem;
135 AssertPtrReturn(pEventInt, VERR_INVALID_HANDLE);
136 AssertMsgReturn(pEventInt->u32Magic == RTSEMEVENT_MAGIC,
137 ("pEventInt=%p u32Magic=%#x\n", pEventInt, pEventInt->u32Magic),
138 VERR_INVALID_HANDLE);
139
140 RTSpinlockAcquire(pEventInt->hSpinLock, &Tmp);
141
142 if (pEventInt->cWaiters > 0)
143 {
144 ASMAtomicDecU32(&pEventInt->cWaiters);
145 ASMAtomicIncU32(&pEventInt->cWaking);
146 sleepq_lock(pEventInt);
147 int fWakeupSwapProc = sleepq_signal(pEventInt, SLEEPQ_CONDVAR, 0, 0);
148 sleepq_release(pEventInt);
149 if (fWakeupSwapProc)
150 kick_proc0();
151 }
152 else
153 ASMAtomicXchgU8(&pEventInt->fSignaled, true);
154
155 RTSpinlockRelease(pEventInt->hSpinLock, &Tmp);
156 return VINF_SUCCESS;
157}
158
159
160static int rtSemEventWait(RTSEMEVENT EventSem, unsigned cMillies, bool fInterruptible)
161{
162 int rc;
163 RTSPINLOCKTMP Tmp = RTSPINLOCKTMP_INITIALIZER;
164 PRTSEMEVENTINTERNAL pEventInt = (PRTSEMEVENTINTERNAL)EventSem;
165 AssertPtrReturn(pEventInt, VERR_INVALID_HANDLE);
166 AssertMsgReturn(pEventInt->u32Magic == RTSEMEVENT_MAGIC,
167 ("pEventInt=%p u32Magic=%#x\n", pEventInt, pEventInt->u32Magic),
168 VERR_INVALID_HANDLE);
169
170 RTSpinlockAcquire(pEventInt->hSpinLock, &Tmp);
171
172 if (pEventInt->fSignaled)
173 {
174 Assert(!pEventInt->cWaiters);
175 ASMAtomicXchgU8(&pEventInt->fSignaled, false);
176 rc = VINF_SUCCESS;
177 }
178 else
179 {
180 if (cMillies == 0)
181 rc = VERR_TIMEOUT;
182 else
183 {
184 ASMAtomicIncU32(&pEventInt->cWaiters);
185
186 int fFlags = SLEEPQ_CONDVAR;
187
188 if (fInterruptible)
189 fFlags |= SLEEPQ_INTERRUPTIBLE;
190
191 sleepq_lock(pEventInt);
192 sleepq_add(pEventInt, NULL, "IPRT Event Semaphore", fFlags, 0);
193
194 if (cMillies != RT_INDEFINITE_WAIT)
195 {
196 /*
197 * Translate milliseconds into ticks and go to sleep.
198 */
199 struct timeval tv;
200
201 tv.tv_sec = cMillies / 1000;
202 tv.tv_usec = (cMillies % 1000) * 1000;
203
204 sleepq_set_timeout(pEventInt, tvtohz(&tv));
205
206 RTSpinlockRelease(pEventInt->hSpinLock, &Tmp);
207
208 if (fInterruptible)
209 rc = SLEEPQ_TIMEDWAIT_SIG(pEventInt);
210 else
211 rc = SLEEPQ_TIMEDWAIT(pEventInt);
212 }
213 else
214 {
215 RTSpinlockRelease(pEventInt->hSpinLock, &Tmp);
216
217 if (fInterruptible)
218 rc = SLEEPQ_WAIT_SIG(pEventInt);
219 else
220 {
221 rc = 0;
222 SLEEPQ_WAIT(pEventInt);
223 }
224 }
225
226 RTSpinlockAcquire(pEventInt->hSpinLock, &Tmp);
227
228 switch (rc)
229 {
230 case 0:
231 if (pEventInt->u32Magic == RTSEMEVENT_MAGIC)
232 {
233 ASMAtomicDecU32(&pEventInt->cWaking);
234 rc = VINF_SUCCESS;
235 }
236 else
237 {
238 rc = VERR_SEM_DESTROYED; /** @todo this isn't necessarily correct, we've
239 * could've woken up just before destruction... */
240 if (!ASMAtomicDecU32(&pEventInt->cWaking))
241 {
242 /* The event was destroyed, as the last thread do the cleanup.
243 we don't actually know whether */
244 RTSpinlockRelease(pEventInt->hSpinLock, &Tmp);
245 RTSpinlockDestroy(pEventInt->hSpinLock);
246 RTMemFree(pEventInt);
247 return rc;
248 }
249 }
250 break;
251
252 case EWOULDBLOCK:
253 Assert(cMillies != RT_INDEFINITE_WAIT);
254 if (pEventInt->cWaiters > 0)
255 ASMAtomicDecU32(&pEventInt->cWaiters);
256 rc = VERR_TIMEOUT;
257 break;
258
259 case EINTR:
260 case ERESTART:
261 Assert(fInterruptible);
262 if (pEventInt->cWaiters > 0)
263 ASMAtomicDecU32(&pEventInt->cWaiters);
264 rc = VERR_INTERRUPTED;
265 break;
266
267 default:
268 AssertMsgFailed(("sleepq_* -> %d\n", rc));
269 rc = VERR_GENERAL_FAILURE;
270 break;
271 }
272 }
273 }
274
275 RTSpinlockRelease(pEventInt->hSpinLock, &Tmp);
276
277 return rc;
278}
279
280
281RTDECL(int) RTSemEventWait(RTSEMEVENT EventSem, unsigned cMillies)
282{
283 return rtSemEventWait(EventSem, cMillies, false /* not interruptible */);
284}
285
286
287RTDECL(int) RTSemEventWaitNoResume(RTSEMEVENT EventSem, unsigned cMillies)
288{
289 return rtSemEventWait(EventSem, cMillies, true /* interruptible */);
290}
291
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