VirtualBox

source: vbox/trunk/src/VBox/Runtime/r0drv/solaris/semeventmulti-r0drv-solaris.c@ 33155

Last change on this file since 33155 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: 11.5 KB
Line 
1/* $Id: semeventmulti-r0drv-solaris.c 33155 2010-10-15 12:07:44Z vboxsync $ */
2/** @file
3 * IPRT - Multiple Release Event Semaphores, Ring-0 Driver, Solaris.
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-solaris-kernel.h"
32#include "internal/iprt.h"
33#include <iprt/semaphore.h>
34
35#include <iprt/assert.h>
36#include <iprt/asm.h>
37#if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86)
38# include <iprt/asm-amd64-x86.h>
39#endif
40#include <iprt/err.h>
41#include <iprt/lockvalidator.h>
42#include <iprt/mem.h>
43#include <iprt/mp.h>
44#include <iprt/thread.h>
45#include <iprt/time.h>
46#include "internal/magics.h"
47#include "semeventwait-r0drv-solaris.h"
48
49
50/*******************************************************************************
51* Defined Constants And Macros *
52*******************************************************************************/
53/** @name fStateAndGen values
54 * @{ */
55/** The state bit number. */
56#define RTSEMEVENTMULTISOL_STATE_BIT 0
57/** The state mask. */
58#define RTSEMEVENTMULTISOL_STATE_MASK RT_BIT_32(RTSEMEVENTMULTISOL_STATE_BIT)
59/** The generation mask. */
60#define RTSEMEVENTMULTISOL_GEN_MASK ~RTSEMEVENTMULTISOL_STATE_MASK
61/** The generation shift. */
62#define RTSEMEVENTMULTISOL_GEN_SHIFT 1
63/** The initial variable value. */
64#define RTSEMEVENTMULTISOL_STATE_GEN_INIT UINT32_C(0xfffffffc)
65/** @} */
66
67
68/*******************************************************************************
69* Structures and Typedefs *
70*******************************************************************************/
71/**
72 * Solaris multiple release event semaphore.
73 */
74typedef struct RTSEMEVENTMULTIINTERNAL
75{
76 /** Magic value (RTSEMEVENTMULTI_MAGIC). */
77 uint32_t volatile u32Magic;
78 /** The number of references. */
79 uint32_t volatile cRefs;
80 /** The object state bit and generation counter.
81 * The generation counter is incremented every time the object is
82 * signalled. */
83 uint32_t volatile fStateAndGen;
84 /** The Solaris mutex protecting this structure and pairing up the with the cv. */
85 kmutex_t Mtx;
86 /** The Solaris condition variable. */
87 kcondvar_t Cnd;
88} RTSEMEVENTMULTIINTERNAL, *PRTSEMEVENTMULTIINTERNAL;
89
90
91
92RTDECL(int) RTSemEventMultiCreate(PRTSEMEVENTMULTI phEventMultiSem)
93{
94 return RTSemEventMultiCreateEx(phEventMultiSem, 0 /*fFlags*/, NIL_RTLOCKVALCLASS, NULL);
95}
96
97
98RTDECL(int) RTSemEventMultiCreateEx(PRTSEMEVENTMULTI phEventMultiSem, uint32_t fFlags, RTLOCKVALCLASS hClass,
99 const char *pszNameFmt, ...)
100{
101 AssertReturn(!(fFlags & ~RTSEMEVENTMULTI_FLAGS_NO_LOCK_VAL), VERR_INVALID_PARAMETER);
102 AssertPtrReturn(phEventMultiSem, VERR_INVALID_POINTER);
103 RT_ASSERT_PREEMPTIBLE();
104
105 AssertCompile(sizeof(RTSEMEVENTMULTIINTERNAL) > sizeof(void *));
106 PRTSEMEVENTMULTIINTERNAL pThis = (PRTSEMEVENTMULTIINTERNAL)RTMemAlloc(sizeof(*pThis));
107 if (pThis)
108 {
109 pThis->u32Magic = RTSEMEVENTMULTI_MAGIC;
110 pThis->cRefs = 1;
111 pThis->fStateAndGen = RTSEMEVENTMULTISOL_STATE_GEN_INIT;
112 mutex_init(&pThis->Mtx, "IPRT Multiple Release Event Semaphore", MUTEX_DRIVER, (void *)ipltospl(DISP_LEVEL));
113 cv_init(&pThis->Cnd, "IPRT CV", CV_DRIVER, NULL);
114
115 *phEventMultiSem = pThis;
116 return VINF_SUCCESS;
117 }
118 return VERR_NO_MEMORY;
119}
120
121
122/**
123 * Retain a reference to the semaphore.
124 *
125 * @param pThis The semaphore.
126 */
127DECLINLINE(void) rtR0SemEventMultiSolRetain(PRTSEMEVENTMULTIINTERNAL pThis)
128{
129 uint32_t cRefs = ASMAtomicIncU32(&pThis->cRefs);
130 Assert(cRefs && cRefs < 100000);
131}
132
133
134/**
135 * Destructor that is called when cRefs == 0.
136 *
137 * @param pThis The instance to destroy.
138 */
139static void rtSemEventMultiDtor(PRTSEMEVENTMULTIINTERNAL pThis)
140{
141 Assert(pThis->u32Magic != RTSEMEVENTMULTI_MAGIC);
142 cv_destroy(&pThis->Cnd);
143 mutex_destroy(&pThis->Mtx);
144 RTMemFree(pThis);
145}
146
147
148/**
149 * Release a reference, destroy the thing if necessary.
150 *
151 * @param pThis The semaphore.
152 */
153DECLINLINE(void) rtR0SemEventMultiSolRelease(PRTSEMEVENTMULTIINTERNAL pThis)
154{
155 if (RT_UNLIKELY(ASMAtomicDecU32(&pThis->cRefs) == 0))
156 rtSemEventMultiDtor(pThis);
157}
158
159
160
161RTDECL(int) RTSemEventMultiDestroy(RTSEMEVENTMULTI hEventMultiSem)
162{
163 PRTSEMEVENTMULTIINTERNAL pThis = (PRTSEMEVENTMULTIINTERNAL)hEventMultiSem;
164 if (pThis == NIL_RTSEMEVENTMULTI)
165 return VINF_SUCCESS;
166 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
167 AssertMsgReturn(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC, ("pThis=%p u32Magic=%#x\n", pThis, pThis->u32Magic), VERR_INVALID_HANDLE);
168 AssertMsgReturn(pThis->cRefs > 0, ("pThis=%p cRefs=%d\n", pThis, pThis->cRefs), VERR_INVALID_HANDLE);
169 RT_ASSERT_INTS_ON();
170
171 mutex_enter(&pThis->Mtx);
172
173 /* Invalidate the handle and wake up all threads that might be waiting on the semaphore. */
174 Assert(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC);
175 ASMAtomicWriteU32(&pThis->u32Magic, RTSEMEVENTMULTI_MAGIC_DEAD);
176 ASMAtomicAndU32(&pThis->fStateAndGen, RTSEMEVENTMULTISOL_GEN_MASK);
177 cv_broadcast(&pThis->Cnd);
178
179 /* Drop the reference from RTSemEventMultiCreateEx. */
180 mutex_exit(&pThis->Mtx);
181 rtR0SemEventMultiSolRelease(pThis);
182
183 return VINF_SUCCESS;
184}
185
186
187RTDECL(int) RTSemEventMultiSignal(RTSEMEVENTMULTI hEventMultiSem)
188{
189 PRTSEMEVENTMULTIINTERNAL pThis = (PRTSEMEVENTMULTIINTERNAL)hEventMultiSem;
190 RT_ASSERT_PREEMPT_CPUID_VAR();
191
192 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
193 AssertMsgReturn(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC,
194 ("pThis=%p u32Magic=%#x\n", pThis, pThis->u32Magic),
195 VERR_INVALID_HANDLE);
196 RT_ASSERT_INTS_ON();
197 rtR0SemEventMultiSolRetain(pThis);
198 rtR0SemSolWaitEnterMutexWithUnpinningHack(&pThis->Mtx);
199 Assert(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC);
200
201 /*
202 * Do the job.
203 */
204 uint32_t fNew = ASMAtomicUoReadU32(&pThis->fStateAndGen);
205 fNew += 1 << RTSEMEVENTMULTISOL_GEN_SHIFT;
206 fNew |= RTSEMEVENTMULTISOL_STATE_MASK;
207 ASMAtomicWriteU32(&pThis->fStateAndGen, fNew);
208
209 cv_broadcast(&pThis->Cnd);
210
211 mutex_exit(&pThis->Mtx);
212
213 rtR0SemEventMultiSolRelease(pThis);
214 RT_ASSERT_PREEMPT_CPUID();
215 return VINF_SUCCESS;
216}
217
218
219RTDECL(int) RTSemEventMultiReset(RTSEMEVENTMULTI hEventMultiSem)
220{
221 PRTSEMEVENTMULTIINTERNAL pThis = (PRTSEMEVENTMULTIINTERNAL)hEventMultiSem;
222 RT_ASSERT_PREEMPT_CPUID_VAR();
223
224 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
225 AssertMsgReturn(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC,
226 ("pThis=%p u32Magic=%#x\n", pThis, pThis->u32Magic),
227 VERR_INVALID_HANDLE);
228 RT_ASSERT_INTS_ON();
229
230 rtR0SemEventMultiSolRetain(pThis);
231 rtR0SemSolWaitEnterMutexWithUnpinningHack(&pThis->Mtx);
232 Assert(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC);
233
234 /*
235 * Do the job (could be done without the lock, but play safe).
236 */
237 ASMAtomicAndU32(&pThis->fStateAndGen, ~RTSEMEVENTMULTISOL_STATE_MASK);
238
239 mutex_exit(&pThis->Mtx);
240 rtR0SemEventMultiSolRelease(pThis);
241
242 RT_ASSERT_PREEMPT_CPUID();
243 return VINF_SUCCESS;
244}
245
246
247/**
248 * Worker for RTSemEventMultiWaitEx and RTSemEventMultiWaitExDebug.
249 *
250 * @returns VBox status code.
251 * @param pThis The event semaphore.
252 * @param fFlags See RTSemEventMultiWaitEx.
253 * @param uTimeout See RTSemEventMultiWaitEx.
254 * @param pSrcPos The source code position of the wait.
255 */
256static int rtR0SemEventMultiSolWait(PRTSEMEVENTMULTIINTERNAL pThis, uint32_t fFlags, uint64_t uTimeout,
257 PCRTLOCKVALSRCPOS pSrcPos)
258{
259 uint32_t fOrgStateAndGen;
260 int rc;
261
262 /*
263 * Validate the input.
264 */
265 AssertPtrReturn(pThis, VERR_INVALID_PARAMETER);
266 AssertMsgReturn(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC, ("%p u32Magic=%RX32\n", pThis, pThis->u32Magic), VERR_INVALID_PARAMETER);
267 AssertReturn(RTSEMWAIT_FLAGS_ARE_VALID(fFlags), VERR_INVALID_PARAMETER);
268 rtR0SemEventMultiSolRetain(pThis);
269 mutex_enter(&pThis->Mtx); /* this could be moved down to the else, but play safe for now. */
270
271 /*
272 * Is the event already signalled or do we have to wait?
273 */
274 fOrgStateAndGen = ASMAtomicUoReadU32(&pThis->fStateAndGen);
275 if (fOrgStateAndGen & RTSEMEVENTMULTISOL_STATE_MASK)
276 rc = VINF_SUCCESS;
277 else
278 {
279 /*
280 * We have to wait.
281 */
282 RTR0SEMSOLWAIT Wait;
283 rc = rtR0SemSolWaitInit(&Wait, fFlags, uTimeout);
284 if (RT_SUCCESS(rc))
285 {
286 for (;;)
287 {
288 /* The destruction test. */
289 if (RT_UNLIKELY(pThis->u32Magic != RTSEMEVENTMULTI_MAGIC))
290 rc = VERR_SEM_DESTROYED;
291 else
292 {
293 /* Check the exit conditions. */
294 if (RT_UNLIKELY(pThis->u32Magic != RTSEMEVENTMULTI_MAGIC))
295 rc = VERR_SEM_DESTROYED;
296 else if (ASMAtomicUoReadU32(&pThis->fStateAndGen) != fOrgStateAndGen)
297 rc = VINF_SUCCESS;
298 else if (rtR0SemSolWaitHasTimedOut(&Wait))
299 rc = VERR_TIMEOUT;
300 else if (rtR0SemSolWaitWasInterrupted(&Wait))
301 rc = VERR_INTERRUPTED;
302 else
303 {
304 /* Do the wait and then recheck the conditions. */
305 rtR0SemSolWaitDoIt(&Wait, &pThis->Cnd, &pThis->Mtx);
306 continue;
307 }
308 }
309 break;
310 }
311 rtR0SemSolWaitDelete(&Wait);
312 }
313 }
314
315 mutex_exit(&pThis->Mtx);
316 rtR0SemEventMultiSolRelease(pThis);
317 return rc;
318}
319
320
321
322#undef RTSemEventMultiWaitEx
323RTDECL(int) RTSemEventMultiWaitEx(RTSEMEVENTMULTI hEventMultiSem, uint32_t fFlags, uint64_t uTimeout)
324{
325#ifndef RTSEMEVENT_STRICT
326 return rtR0SemEventMultiSolWait(hEventMultiSem, fFlags, uTimeout, NULL);
327#else
328 RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_NORMAL_API();
329 return rtR0SemEventMultiSolWait(hEventMultiSem, fFlags, uTimeout, &SrcPos);
330#endif
331}
332
333
334RTDECL(int) RTSemEventMultiWaitExDebug(RTSEMEVENTMULTI hEventMultiSem, uint32_t fFlags, uint64_t uTimeout,
335 RTHCUINTPTR uId, RT_SRC_POS_DECL)
336{
337 RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_DEBUG_API();
338 return rtR0SemEventMultiSolWait(hEventMultiSem, fFlags, uTimeout, &SrcPos);
339}
340
341
342RTDECL(uint32_t) RTSemEventMultiGetResolution(void)
343{
344 return rtR0SemSolWaitGetResolution();
345}
346
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