VirtualBox

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

Last change on this file was 98103, checked in by vboxsync, 17 months ago

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 12.7 KB
Line 
1/* $Id: semeventmulti-r0drv-solaris.c 98103 2023-01-17 14:15:46Z vboxsync $ */
2/** @file
3 * IPRT - Multiple Release Event Semaphores, Ring-0 Driver, Solaris.
4 */
5
6/*
7 * Copyright (C) 2006-2023 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * The contents of this file may alternatively be used under the terms
26 * of the Common Development and Distribution License Version 1.0
27 * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
28 * in the VirtualBox distribution, in which case the provisions of the
29 * CDDL are applicable instead of those of the GPL.
30 *
31 * You may elect to license modified versions of this file under the
32 * terms and conditions of either the GPL or the CDDL or both.
33 *
34 * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
35 */
36
37
38/*********************************************************************************************************************************
39* Header Files *
40*********************************************************************************************************************************/
41#define RTSEMEVENTMULTI_WITHOUT_REMAPPING
42#include "the-solaris-kernel.h"
43#include "internal/iprt.h"
44#include <iprt/semaphore.h>
45
46#include <iprt/assert.h>
47#include <iprt/asm.h>
48#if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86)
49# include <iprt/asm-amd64-x86.h>
50#endif
51#include <iprt/err.h>
52#include <iprt/lockvalidator.h>
53#include <iprt/mem.h>
54#include <iprt/mp.h>
55#include <iprt/thread.h>
56#include <iprt/time.h>
57#include "internal/magics.h"
58#include "semeventwait-r0drv-solaris.h"
59
60
61/*********************************************************************************************************************************
62* Defined Constants And Macros *
63*********************************************************************************************************************************/
64/** @name fStateAndGen values
65 * @{ */
66/** The state bit number. */
67#define RTSEMEVENTMULTISOL_STATE_BIT 0
68/** The state mask. */
69#define RTSEMEVENTMULTISOL_STATE_MASK RT_BIT_32(RTSEMEVENTMULTISOL_STATE_BIT)
70/** The generation mask. */
71#define RTSEMEVENTMULTISOL_GEN_MASK ~RTSEMEVENTMULTISOL_STATE_MASK
72/** The generation shift. */
73#define RTSEMEVENTMULTISOL_GEN_SHIFT 1
74/** The initial variable value. */
75#define RTSEMEVENTMULTISOL_STATE_GEN_INIT UINT32_C(0xfffffffc)
76/** @} */
77
78
79/*********************************************************************************************************************************
80* Structures and Typedefs *
81*********************************************************************************************************************************/
82/**
83 * Solaris multiple release event semaphore.
84 */
85typedef struct RTSEMEVENTMULTIINTERNAL
86{
87 /** Magic value (RTSEMEVENTMULTI_MAGIC). */
88 uint32_t volatile u32Magic;
89 /** The number of references. */
90 uint32_t volatile cRefs;
91 /** The object state bit and generation counter.
92 * The generation counter is incremented every time the object is
93 * signalled. */
94 uint32_t volatile fStateAndGen;
95 /** The Solaris mutex protecting this structure and pairing up the with the cv. */
96 kmutex_t Mtx;
97 /** The Solaris condition variable. */
98 kcondvar_t Cnd;
99} RTSEMEVENTMULTIINTERNAL, *PRTSEMEVENTMULTIINTERNAL;
100
101
102
103RTDECL(int) RTSemEventMultiCreate(PRTSEMEVENTMULTI phEventMultiSem)
104{
105 return RTSemEventMultiCreateEx(phEventMultiSem, 0 /*fFlags*/, NIL_RTLOCKVALCLASS, NULL);
106}
107
108
109RTDECL(int) RTSemEventMultiCreateEx(PRTSEMEVENTMULTI phEventMultiSem, uint32_t fFlags, RTLOCKVALCLASS hClass,
110 const char *pszNameFmt, ...)
111{
112 AssertReturn(!(fFlags & ~RTSEMEVENTMULTI_FLAGS_NO_LOCK_VAL), VERR_INVALID_PARAMETER);
113 AssertPtrReturn(phEventMultiSem, VERR_INVALID_POINTER);
114 RT_ASSERT_PREEMPTIBLE();
115
116 AssertCompile(sizeof(RTSEMEVENTMULTIINTERNAL) > sizeof(void *));
117 PRTSEMEVENTMULTIINTERNAL pThis = (PRTSEMEVENTMULTIINTERNAL)RTMemAlloc(sizeof(*pThis));
118 if (pThis)
119 {
120 pThis->u32Magic = RTSEMEVENTMULTI_MAGIC;
121 pThis->cRefs = 1;
122 pThis->fStateAndGen = RTSEMEVENTMULTISOL_STATE_GEN_INIT;
123 mutex_init(&pThis->Mtx, "IPRT Multiple Release Event Semaphore", MUTEX_DRIVER, (void *)ipltospl(DISP_LEVEL));
124 cv_init(&pThis->Cnd, "IPRT CV", CV_DRIVER, NULL);
125
126 *phEventMultiSem = pThis;
127 return VINF_SUCCESS;
128 }
129 return VERR_NO_MEMORY;
130}
131
132
133/**
134 * Retain a reference to the semaphore.
135 *
136 * @param pThis The semaphore.
137 */
138DECLINLINE(void) rtR0SemEventMultiSolRetain(PRTSEMEVENTMULTIINTERNAL pThis)
139{
140 uint32_t cRefs = ASMAtomicIncU32(&pThis->cRefs);
141 Assert(cRefs && cRefs < 100000);
142 NOREF(cRefs);
143}
144
145
146/**
147 * Destructor that is called when cRefs == 0.
148 *
149 * @param pThis The instance to destroy.
150 */
151static void rtSemEventMultiDtor(PRTSEMEVENTMULTIINTERNAL pThis)
152{
153 Assert(pThis->u32Magic != RTSEMEVENTMULTI_MAGIC);
154 cv_destroy(&pThis->Cnd);
155 mutex_destroy(&pThis->Mtx);
156 RTMemFree(pThis);
157}
158
159
160/**
161 * Release a reference, destroy the thing if necessary.
162 *
163 * @param pThis The semaphore.
164 */
165DECLINLINE(void) rtR0SemEventMultiSolRelease(PRTSEMEVENTMULTIINTERNAL pThis)
166{
167 if (RT_UNLIKELY(ASMAtomicDecU32(&pThis->cRefs) == 0))
168 rtSemEventMultiDtor(pThis);
169}
170
171
172
173RTDECL(int) RTSemEventMultiDestroy(RTSEMEVENTMULTI hEventMultiSem)
174{
175 PRTSEMEVENTMULTIINTERNAL pThis = (PRTSEMEVENTMULTIINTERNAL)hEventMultiSem;
176 if (pThis == NIL_RTSEMEVENTMULTI)
177 return VINF_SUCCESS;
178 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
179 AssertMsgReturn(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC, ("pThis=%p u32Magic=%#x\n", pThis, pThis->u32Magic), VERR_INVALID_HANDLE);
180 AssertMsgReturn(pThis->cRefs > 0, ("pThis=%p cRefs=%d\n", pThis, pThis->cRefs), VERR_INVALID_HANDLE);
181 RT_ASSERT_INTS_ON();
182
183 mutex_enter(&pThis->Mtx);
184
185 /* Invalidate the handle and wake up all threads that might be waiting on the semaphore. */
186 Assert(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC);
187 ASMAtomicWriteU32(&pThis->u32Magic, RTSEMEVENTMULTI_MAGIC_DEAD);
188 ASMAtomicAndU32(&pThis->fStateAndGen, RTSEMEVENTMULTISOL_GEN_MASK);
189 cv_broadcast(&pThis->Cnd);
190
191 /* Drop the reference from RTSemEventMultiCreateEx. */
192 mutex_exit(&pThis->Mtx);
193 rtR0SemEventMultiSolRelease(pThis);
194
195 return VINF_SUCCESS;
196}
197
198
199RTDECL(int) RTSemEventMultiSignal(RTSEMEVENTMULTI hEventMultiSem)
200{
201 PRTSEMEVENTMULTIINTERNAL pThis = (PRTSEMEVENTMULTIINTERNAL)hEventMultiSem;
202 RT_ASSERT_PREEMPT_CPUID_VAR();
203
204 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
205 AssertMsgReturn(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC,
206 ("pThis=%p u32Magic=%#x\n", pThis, pThis->u32Magic),
207 VERR_INVALID_HANDLE);
208 RT_ASSERT_INTS_ON();
209 rtR0SemEventMultiSolRetain(pThis);
210 rtR0SemSolWaitEnterMutexWithUnpinningHack(&pThis->Mtx);
211 Assert(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC);
212
213 /*
214 * Do the job.
215 */
216 uint32_t fNew = ASMAtomicUoReadU32(&pThis->fStateAndGen);
217 fNew += 1 << RTSEMEVENTMULTISOL_GEN_SHIFT;
218 fNew |= RTSEMEVENTMULTISOL_STATE_MASK;
219 ASMAtomicWriteU32(&pThis->fStateAndGen, fNew);
220
221 cv_broadcast(&pThis->Cnd);
222
223 mutex_exit(&pThis->Mtx);
224
225 rtR0SemEventMultiSolRelease(pThis);
226#ifdef DEBUG_ramshankar
227 /** See @bugref{6318#c11}. */
228 return VINF_SUCCESS;
229#endif
230 RT_ASSERT_PREEMPT_CPUID();
231 return VINF_SUCCESS;
232}
233
234
235RTDECL(int) RTSemEventMultiReset(RTSEMEVENTMULTI hEventMultiSem)
236{
237 PRTSEMEVENTMULTIINTERNAL pThis = (PRTSEMEVENTMULTIINTERNAL)hEventMultiSem;
238 RT_ASSERT_PREEMPT_CPUID_VAR();
239
240 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
241 AssertMsgReturn(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC,
242 ("pThis=%p u32Magic=%#x\n", pThis, pThis->u32Magic),
243 VERR_INVALID_HANDLE);
244 RT_ASSERT_INTS_ON();
245
246 rtR0SemEventMultiSolRetain(pThis);
247 rtR0SemSolWaitEnterMutexWithUnpinningHack(&pThis->Mtx);
248 Assert(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC);
249
250 /*
251 * Do the job (could be done without the lock, but play safe).
252 */
253 ASMAtomicAndU32(&pThis->fStateAndGen, ~RTSEMEVENTMULTISOL_STATE_MASK);
254
255 mutex_exit(&pThis->Mtx);
256 rtR0SemEventMultiSolRelease(pThis);
257
258#ifdef DEBUG_ramshankar
259 /** See @bugref{6318#c11}. */
260 return VINF_SUCCESS;
261#endif
262 RT_ASSERT_PREEMPT_CPUID();
263 return VINF_SUCCESS;
264}
265
266
267/**
268 * Worker for RTSemEventMultiWaitEx and RTSemEventMultiWaitExDebug.
269 *
270 * @returns VBox status code.
271 * @param pThis The event semaphore.
272 * @param fFlags See RTSemEventMultiWaitEx.
273 * @param uTimeout See RTSemEventMultiWaitEx.
274 * @param pSrcPos The source code position of the wait.
275 */
276static int rtR0SemEventMultiSolWait(PRTSEMEVENTMULTIINTERNAL pThis, uint32_t fFlags, uint64_t uTimeout,
277 PCRTLOCKVALSRCPOS pSrcPos)
278{
279 uint32_t fOrgStateAndGen;
280 int rc;
281
282 /*
283 * Validate the input.
284 */
285 AssertPtrReturn(pThis, VERR_INVALID_PARAMETER);
286 AssertMsgReturn(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC, ("%p u32Magic=%RX32\n", pThis, pThis->u32Magic), VERR_INVALID_PARAMETER);
287 AssertReturn(RTSEMWAIT_FLAGS_ARE_VALID(fFlags), VERR_INVALID_PARAMETER);
288 rtR0SemEventMultiSolRetain(pThis);
289 mutex_enter(&pThis->Mtx); /* this could be moved down to the else, but play safe for now. */
290
291 /*
292 * Is the event already signalled or do we have to wait?
293 */
294 fOrgStateAndGen = ASMAtomicUoReadU32(&pThis->fStateAndGen);
295 if (fOrgStateAndGen & RTSEMEVENTMULTISOL_STATE_MASK)
296 rc = VINF_SUCCESS;
297 else
298 {
299 /*
300 * We have to wait.
301 */
302 RTR0SEMSOLWAIT Wait;
303 rc = rtR0SemSolWaitInit(&Wait, fFlags, uTimeout);
304 if (RT_SUCCESS(rc))
305 {
306 for (;;)
307 {
308 /* The destruction test. */
309 if (RT_UNLIKELY(pThis->u32Magic != RTSEMEVENTMULTI_MAGIC))
310 rc = VERR_SEM_DESTROYED;
311 else
312 {
313 /* Check the exit conditions. */
314 if (RT_UNLIKELY(pThis->u32Magic != RTSEMEVENTMULTI_MAGIC))
315 rc = VERR_SEM_DESTROYED;
316 else if (ASMAtomicUoReadU32(&pThis->fStateAndGen) != fOrgStateAndGen)
317 rc = VINF_SUCCESS;
318 else if (rtR0SemSolWaitHasTimedOut(&Wait))
319 rc = VERR_TIMEOUT;
320 else if (rtR0SemSolWaitWasInterrupted(&Wait))
321 rc = VERR_INTERRUPTED;
322 else
323 {
324 /* Do the wait and then recheck the conditions. */
325 rtR0SemSolWaitDoIt(&Wait, &pThis->Cnd, &pThis->Mtx, &pThis->fStateAndGen, fOrgStateAndGen);
326 continue;
327 }
328 }
329 break;
330 }
331 rtR0SemSolWaitDelete(&Wait);
332 }
333 }
334
335 mutex_exit(&pThis->Mtx);
336 rtR0SemEventMultiSolRelease(pThis);
337 return rc;
338}
339
340
341
342RTDECL(int) RTSemEventMultiWaitEx(RTSEMEVENTMULTI hEventMultiSem, uint32_t fFlags, uint64_t uTimeout)
343{
344#ifndef RTSEMEVENT_STRICT
345 return rtR0SemEventMultiSolWait(hEventMultiSem, fFlags, uTimeout, NULL);
346#else
347 RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_NORMAL_API();
348 return rtR0SemEventMultiSolWait(hEventMultiSem, fFlags, uTimeout, &SrcPos);
349#endif
350}
351
352
353RTDECL(int) RTSemEventMultiWaitExDebug(RTSEMEVENTMULTI hEventMultiSem, uint32_t fFlags, uint64_t uTimeout,
354 RTHCUINTPTR uId, RT_SRC_POS_DECL)
355{
356 RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_DEBUG_API();
357 return rtR0SemEventMultiSolWait(hEventMultiSem, fFlags, uTimeout, &SrcPos);
358}
359
360
361RTDECL(uint32_t) RTSemEventMultiGetResolution(void)
362{
363 return rtR0SemSolWaitGetResolution();
364}
365
366
367RTR0DECL(bool) RTSemEventMultiIsSignalSafe(void)
368{
369 /* Don't trust solaris not to preempt us. */
370 return false;
371}
372
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use