VirtualBox

source: vbox/trunk/src/VBox/Runtime/r0drv/linux/semeventmulti-r0drv-linux.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 Id
File size: 10.7 KB
Line 
1/* $Id: semeventmulti-r0drv-linux.c 36190 2011-03-07 16:28:50Z vboxsync $ */
2/** @file
3 * IPRT - Multiple Release Event Semaphores, Ring-0 Driver, Linux.
4 */
5
6/*
7 * Copyright (C) 2006-2010 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * The contents of this file may alternatively be used under the terms
18 * of the Common Development and Distribution License Version 1.0
19 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20 * VirtualBox OSE distribution, in which case the provisions of the
21 * CDDL are applicable instead of those of the GPL.
22 *
23 * You may elect to license modified versions of this file under the
24 * terms and conditions of either the GPL or the CDDL or both.
25 */
26
27
28/*******************************************************************************
29* Header Files *
30*******************************************************************************/
31#define RTSEMEVENTMULTI_WITHOUT_REMAPPING
32#include "the-linux-kernel.h"
33#include "internal/iprt.h"
34#include <iprt/semaphore.h>
35
36#include <iprt/assert.h>
37#include <iprt/asm.h>
38#include <iprt/err.h>
39#include <iprt/mem.h>
40#include <iprt/lockvalidator.h>
41
42#include "waitqueue-r0drv-linux.h"
43#include "internal/magics.h"
44
45
46/*******************************************************************************
47* Defined Constants And Macros *
48*******************************************************************************/
49/** @name fStateAndGen values
50 * @{ */
51/** The state bit number. */
52#define RTSEMEVENTMULTILNX_STATE_BIT 0
53/** The state mask. */
54#define RTSEMEVENTMULTILNX_STATE_MASK RT_BIT_32(RTSEMEVENTMULTILNX_STATE_BIT)
55/** The generation mask. */
56#define RTSEMEVENTMULTILNX_GEN_MASK ~RTSEMEVENTMULTILNX_STATE_MASK
57/** The generation shift. */
58#define RTSEMEVENTMULTILNX_GEN_SHIFT 1
59/** The initial variable value. */
60#define RTSEMEVENTMULTILNX_STATE_GEN_INIT UINT32_C(0xfffffffc)
61/** @} */
62
63
64/*******************************************************************************
65* Structures and Typedefs *
66*******************************************************************************/
67/**
68 * Linux event semaphore.
69 */
70typedef struct RTSEMEVENTMULTIINTERNAL
71{
72 /** Magic value (RTSEMEVENTMULTI_MAGIC). */
73 uint32_t volatile u32Magic;
74 /** The object state bit and generation counter.
75 * The generation counter is incremented every time the object is
76 * signalled. */
77 uint32_t volatile fStateAndGen;
78 /** Reference counter. */
79 uint32_t volatile cRefs;
80 /** The wait queue. */
81 wait_queue_head_t Head;
82} RTSEMEVENTMULTIINTERNAL, *PRTSEMEVENTMULTIINTERNAL;
83
84
85
86
87
88RTDECL(int) RTSemEventMultiCreate(PRTSEMEVENTMULTI phEventMultiSem)
89{
90 return RTSemEventMultiCreateEx(phEventMultiSem, 0 /*fFlags*/, NIL_RTLOCKVALCLASS, NULL);
91}
92
93
94RTDECL(int) RTSemEventMultiCreateEx(PRTSEMEVENTMULTI phEventMultiSem, uint32_t fFlags, RTLOCKVALCLASS hClass,
95 const char *pszNameFmt, ...)
96{
97 PRTSEMEVENTMULTIINTERNAL pThis;
98
99 AssertReturn(!(fFlags & ~RTSEMEVENTMULTI_FLAGS_NO_LOCK_VAL), VERR_INVALID_PARAMETER);
100 pThis = (PRTSEMEVENTMULTIINTERNAL)RTMemAlloc(sizeof(*pThis));
101 if (pThis)
102 {
103 pThis->u32Magic = RTSEMEVENTMULTI_MAGIC;
104 pThis->fStateAndGen = RTSEMEVENTMULTILNX_STATE_GEN_INIT;
105 pThis->cRefs = 1;
106 init_waitqueue_head(&pThis->Head);
107
108 *phEventMultiSem = pThis;
109 return VINF_SUCCESS;
110 }
111 return VERR_NO_MEMORY;
112}
113RT_EXPORT_SYMBOL(RTSemEventMultiCreate);
114
115
116/**
117 * Retain a reference to the semaphore.
118 *
119 * @param pThis The semaphore.
120 */
121DECLINLINE(void) rtR0SemEventMultiLnxRetain(PRTSEMEVENTMULTIINTERNAL pThis)
122{
123 uint32_t cRefs = ASMAtomicIncU32(&pThis->cRefs);
124 NOREF(cRefs);
125 Assert(cRefs && cRefs < 100000);
126}
127
128
129/**
130 * Release a reference, destroy the thing if necessary.
131 *
132 * @param pThis The semaphore.
133 */
134DECLINLINE(void) rtR0SemEventMultiLnxRelease(PRTSEMEVENTMULTIINTERNAL pThis)
135{
136 if (RT_UNLIKELY(ASMAtomicDecU32(&pThis->cRefs) == 0))
137 {
138 Assert(pThis->u32Magic != RTSEMEVENTMULTI_MAGIC);
139 RTMemFree(pThis);
140 }
141}
142
143
144RTDECL(int) RTSemEventMultiDestroy(RTSEMEVENTMULTI hEventMultiSem)
145{
146 /*
147 * Validate input.
148 */
149 PRTSEMEVENTMULTIINTERNAL pThis = (PRTSEMEVENTMULTIINTERNAL)hEventMultiSem;
150 if (pThis == NIL_RTSEMEVENTMULTI)
151 return VINF_SUCCESS;
152 AssertPtrReturn(pThis, VERR_INVALID_PARAMETER);
153 AssertMsgReturn(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC, ("%p u32Magic=%RX32\n", pThis, pThis->u32Magic), VERR_INVALID_PARAMETER);
154 Assert(pThis->cRefs > 0);
155
156 /*
157 * Invalidate it and signal the object just in case.
158 */
159 ASMAtomicWriteU32(&pThis->u32Magic, ~RTSEMEVENTMULTI_MAGIC);
160 ASMAtomicAndU32(&pThis->fStateAndGen, RTSEMEVENTMULTILNX_GEN_MASK);
161 Assert(!waitqueue_active(&pThis->Head));
162 wake_up_all(&pThis->Head);
163 rtR0SemEventMultiLnxRelease(pThis);
164 return VINF_SUCCESS;
165}
166RT_EXPORT_SYMBOL(RTSemEventMultiDestroy);
167
168
169RTDECL(int) RTSemEventMultiSignal(RTSEMEVENTMULTI hEventMultiSem)
170{
171 uint32_t fNew;
172 uint32_t fOld;
173
174 /*
175 * Validate input.
176 */
177 PRTSEMEVENTMULTIINTERNAL pThis = (PRTSEMEVENTMULTIINTERNAL)hEventMultiSem;
178 if (!pThis)
179 return VERR_INVALID_PARAMETER;
180 AssertPtrReturn(pThis, VERR_INVALID_PARAMETER);
181 AssertMsgReturn(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC, ("%p u32Magic=%RX32\n", pThis, pThis->u32Magic), VERR_INVALID_PARAMETER);
182 rtR0SemEventMultiLnxRetain(pThis);
183
184 /*
185 * Signal the event object. The cause of the paranoia here is racing to try
186 * deal with racing RTSemEventMultiSignal calls (should probably be
187 * forbidden, but it's relatively easy to handle).
188 */
189 do
190 {
191 fNew = fOld = ASMAtomicUoReadU32(&pThis->fStateAndGen);
192 fNew += 1 << RTSEMEVENTMULTILNX_GEN_SHIFT;
193 fNew |= RTSEMEVENTMULTILNX_STATE_MASK;
194 }
195 while (!ASMAtomicCmpXchgU32(&pThis->fStateAndGen, fNew, fOld));
196
197 wake_up_all(&pThis->Head);
198
199 rtR0SemEventMultiLnxRelease(pThis);
200 return VINF_SUCCESS;
201}
202RT_EXPORT_SYMBOL(RTSemEventMultiSignal);
203
204
205RTDECL(int) RTSemEventMultiReset(RTSEMEVENTMULTI hEventMultiSem)
206{
207 /*
208 * Validate input.
209 */
210 PRTSEMEVENTMULTIINTERNAL pThis = (PRTSEMEVENTMULTIINTERNAL)hEventMultiSem;
211 if (!pThis)
212 return VERR_INVALID_PARAMETER;
213 AssertPtrReturn(pThis, VERR_INVALID_PARAMETER);
214 AssertMsgReturn(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC, ("%p u32Magic=%RX32\n", pThis, pThis->u32Magic), VERR_INVALID_PARAMETER);
215 rtR0SemEventMultiLnxRetain(pThis);
216
217 /*
218 * Reset it.
219 */
220 ASMAtomicAndU32(&pThis->fStateAndGen, ~RTSEMEVENTMULTILNX_STATE_MASK);
221
222 rtR0SemEventMultiLnxRelease(pThis);
223 return VINF_SUCCESS;
224}
225RT_EXPORT_SYMBOL(RTSemEventMultiReset);
226
227
228/**
229 * Worker for RTSemEventMultiWaitEx and RTSemEventMultiWaitExDebug.
230 *
231 * @returns VBox status code.
232 * @param pThis The event semaphore.
233 * @param fFlags See RTSemEventMultiWaitEx.
234 * @param uTimeout See RTSemEventMultiWaitEx.
235 * @param pSrcPos The source code position of the wait.
236 */
237static int rtR0SemEventMultiLnxWait(PRTSEMEVENTMULTIINTERNAL pThis, uint32_t fFlags, uint64_t uTimeout,
238 PCRTLOCKVALSRCPOS pSrcPos)
239{
240 uint32_t fOrgStateAndGen;
241 int rc;
242
243 /*
244 * Validate the input.
245 */
246 AssertPtrReturn(pThis, VERR_INVALID_PARAMETER);
247 AssertMsgReturn(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC, ("%p u32Magic=%RX32\n", pThis, pThis->u32Magic), VERR_INVALID_PARAMETER);
248 AssertReturn(RTSEMWAIT_FLAGS_ARE_VALID(fFlags), VERR_INVALID_PARAMETER);
249 rtR0SemEventMultiLnxRetain(pThis);
250
251 /*
252 * Is the event already signalled or do we have to wait?
253 */
254 fOrgStateAndGen = ASMAtomicUoReadU32(&pThis->fStateAndGen);
255 if (fOrgStateAndGen & RTSEMEVENTMULTILNX_STATE_MASK)
256 rc = VINF_SUCCESS;
257 else
258 {
259 /*
260 * We have to wait.
261 */
262 RTR0SEMLNXWAIT Wait;
263 rc = rtR0SemLnxWaitInit(&Wait, fFlags, uTimeout, &pThis->Head);
264 if (RT_SUCCESS(rc))
265 {
266 IPRT_DEBUG_SEMS_STATE(pThis, 'E');
267 for (;;)
268 {
269 /* The destruction test. */
270 if (RT_UNLIKELY(pThis->u32Magic != RTSEMEVENTMULTI_MAGIC))
271 rc = VERR_SEM_DESTROYED;
272 else
273 {
274 rtR0SemLnxWaitPrepare(&Wait);
275
276 /* Check the exit conditions. */
277 if (RT_UNLIKELY(pThis->u32Magic != RTSEMEVENTMULTI_MAGIC))
278 rc = VERR_SEM_DESTROYED;
279 else if (ASMAtomicUoReadU32(&pThis->fStateAndGen) != fOrgStateAndGen)
280 rc = VINF_SUCCESS;
281 else if (rtR0SemLnxWaitHasTimedOut(&Wait))
282 rc = VERR_TIMEOUT;
283 else if (rtR0SemLnxWaitWasInterrupted(&Wait))
284 rc = VERR_INTERRUPTED;
285 else
286 {
287 /* Do the wait and then recheck the conditions. */
288 rtR0SemLnxWaitDoIt(&Wait);
289 continue;
290 }
291 }
292 break;
293 }
294
295 rtR0SemLnxWaitDelete(&Wait);
296 IPRT_DEBUG_SEMS_STATE_RC(pThis, 'E', rc);
297 }
298 }
299
300 rtR0SemEventMultiLnxRelease(pThis);
301 return rc;
302}
303
304
305RTDECL(int) RTSemEventMultiWaitEx(RTSEMEVENTMULTI hEventMultiSem, uint32_t fFlags, uint64_t uTimeout)
306{
307#ifndef RTSEMEVENT_STRICT
308 return rtR0SemEventMultiLnxWait(hEventMultiSem, fFlags, uTimeout, NULL);
309#else
310 RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_NORMAL_API();
311 return rtR0SemEventMultiLnxWait(hEventMultiSem, fFlags, uTimeout, &SrcPos);
312#endif
313}
314RT_EXPORT_SYMBOL(RTSemEventMultiWaitEx);
315
316
317RTDECL(int) RTSemEventMultiWaitExDebug(RTSEMEVENTMULTI hEventMultiSem, uint32_t fFlags, uint64_t uTimeout,
318 RTHCUINTPTR uId, RT_SRC_POS_DECL)
319{
320 RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_DEBUG_API();
321 return rtR0SemEventMultiLnxWait(hEventMultiSem, fFlags, uTimeout, &SrcPos);
322}
323RT_EXPORT_SYMBOL(RTSemEventMultiWaitExDebug);
324
325
326RTDECL(uint32_t) RTSemEventMultiGetResolution(void)
327{
328 return rtR0SemLnxWaitGetResolution();
329}
330RT_EXPORT_SYMBOL(RTSemEventMultiGetResolution);
331
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