VirtualBox

source: vbox/trunk/src/VBox/Runtime/r0drv/linux/semeventmulti-r0drv-linux.c@ 33011

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

IPRT,SUPDrv,VBoxGuest: Reimplemented RTSemEventWait* so that it can make use of high resoultion timers when present (2.6.28).

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