VirtualBox

source: vbox/trunk/src/VBox/Runtime/r0drv/linux/semeventmulti-r0drv-linux.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 Id Revision
File size: 11.9 KB
Line 
1/* $Id: semeventmulti-r0drv-linux.c 98103 2023-01-17 14:15:46Z vboxsync $ */
2/** @file
3 * IPRT - Multiple Release Event Semaphores, Ring-0 Driver, Linux.
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-linux-kernel.h"
43#include "internal/iprt.h"
44#include <iprt/semaphore.h>
45
46#include <iprt/assert.h>
47#include <iprt/asm.h>
48#include <iprt/err.h>
49#include <iprt/mem.h>
50#include <iprt/lockvalidator.h>
51
52#include "waitqueue-r0drv-linux.h"
53#include "internal/magics.h"
54
55
56/*********************************************************************************************************************************
57* Defined Constants And Macros *
58*********************************************************************************************************************************/
59/** @name fStateAndGen values
60 * @{ */
61/** The state bit number. */
62#define RTSEMEVENTMULTILNX_STATE_BIT 0
63/** The state mask. */
64#define RTSEMEVENTMULTILNX_STATE_MASK RT_BIT_32(RTSEMEVENTMULTILNX_STATE_BIT)
65/** The generation mask. */
66#define RTSEMEVENTMULTILNX_GEN_MASK ~RTSEMEVENTMULTILNX_STATE_MASK
67/** The generation shift. */
68#define RTSEMEVENTMULTILNX_GEN_SHIFT 1
69/** The initial variable value. */
70#define RTSEMEVENTMULTILNX_STATE_GEN_INIT UINT32_C(0xfffffffc)
71/** @} */
72
73
74/*********************************************************************************************************************************
75* Structures and Typedefs *
76*********************************************************************************************************************************/
77/**
78 * Linux event semaphore.
79 */
80typedef struct RTSEMEVENTMULTIINTERNAL
81{
82 /** Magic value (RTSEMEVENTMULTI_MAGIC). */
83 uint32_t volatile u32Magic;
84 /** The object state bit and generation counter.
85 * The generation counter is incremented every time the object is
86 * signalled. */
87 uint32_t volatile fStateAndGen;
88 /** Reference counter. */
89 uint32_t volatile cRefs;
90 /** The wait queue. */
91 wait_queue_head_t Head;
92} RTSEMEVENTMULTIINTERNAL, *PRTSEMEVENTMULTIINTERNAL;
93
94
95
96
97
98RTDECL(int) RTSemEventMultiCreate(PRTSEMEVENTMULTI phEventMultiSem)
99{
100 return RTSemEventMultiCreateEx(phEventMultiSem, 0 /*fFlags*/, NIL_RTLOCKVALCLASS, NULL);
101}
102
103
104RTDECL(int) RTSemEventMultiCreateEx(PRTSEMEVENTMULTI phEventMultiSem, uint32_t fFlags, RTLOCKVALCLASS hClass,
105 const char *pszNameFmt, ...)
106{
107 PRTSEMEVENTMULTIINTERNAL pThis;
108 IPRT_LINUX_SAVE_EFL_AC();
109 RT_NOREF_PV(hClass); RT_NOREF_PV(pszNameFmt);
110
111 AssertReturn(!(fFlags & ~RTSEMEVENTMULTI_FLAGS_NO_LOCK_VAL), VERR_INVALID_PARAMETER);
112 pThis = (PRTSEMEVENTMULTIINTERNAL)RTMemAlloc(sizeof(*pThis));
113 if (pThis)
114 {
115 pThis->u32Magic = RTSEMEVENTMULTI_MAGIC;
116 pThis->fStateAndGen = RTSEMEVENTMULTILNX_STATE_GEN_INIT;
117 pThis->cRefs = 1;
118 init_waitqueue_head(&pThis->Head);
119
120 *phEventMultiSem = pThis;
121 IPRT_LINUX_RESTORE_EFL_AC();
122 return VINF_SUCCESS;
123 }
124 IPRT_LINUX_RESTORE_EFL_AC();
125 return VERR_NO_MEMORY;
126}
127RT_EXPORT_SYMBOL(RTSemEventMultiCreate);
128
129
130/**
131 * Retain a reference to the semaphore.
132 *
133 * @param pThis The semaphore.
134 */
135DECLINLINE(void) rtR0SemEventMultiLnxRetain(PRTSEMEVENTMULTIINTERNAL pThis)
136{
137 uint32_t cRefs = ASMAtomicIncU32(&pThis->cRefs);
138 NOREF(cRefs);
139 Assert(cRefs && cRefs < 100000);
140}
141
142
143/**
144 * Release a reference, destroy the thing if necessary.
145 *
146 * @param pThis The semaphore.
147 */
148DECLINLINE(void) rtR0SemEventMultiLnxRelease(PRTSEMEVENTMULTIINTERNAL pThis)
149{
150 if (RT_UNLIKELY(ASMAtomicDecU32(&pThis->cRefs) == 0))
151 {
152 Assert(pThis->u32Magic != RTSEMEVENTMULTI_MAGIC);
153 RTMemFree(pThis);
154 }
155}
156
157
158RTDECL(int) RTSemEventMultiDestroy(RTSEMEVENTMULTI hEventMultiSem)
159{
160 IPRT_LINUX_SAVE_EFL_AC();
161
162 /*
163 * Validate input.
164 */
165 PRTSEMEVENTMULTIINTERNAL pThis = (PRTSEMEVENTMULTIINTERNAL)hEventMultiSem;
166 if (pThis == NIL_RTSEMEVENTMULTI)
167 return VINF_SUCCESS;
168 AssertPtrReturn(pThis, VERR_INVALID_PARAMETER);
169 AssertMsgReturn(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC, ("%p u32Magic=%RX32\n", pThis, pThis->u32Magic), VERR_INVALID_PARAMETER);
170 Assert(pThis->cRefs > 0);
171
172 /*
173 * Invalidate it and signal the object just in case.
174 */
175 ASMAtomicWriteU32(&pThis->u32Magic, ~RTSEMEVENTMULTI_MAGIC);
176 ASMAtomicAndU32(&pThis->fStateAndGen, RTSEMEVENTMULTILNX_GEN_MASK);
177 Assert(!waitqueue_active(&pThis->Head));
178 wake_up_all(&pThis->Head);
179 rtR0SemEventMultiLnxRelease(pThis);
180
181 IPRT_LINUX_RESTORE_EFL_AC();
182 return VINF_SUCCESS;
183}
184RT_EXPORT_SYMBOL(RTSemEventMultiDestroy);
185
186
187RTDECL(int) RTSemEventMultiSignal(RTSEMEVENTMULTI hEventMultiSem)
188{
189 IPRT_LINUX_SAVE_EFL_AC();
190 uint32_t fNew;
191 uint32_t fOld;
192
193 /*
194 * Validate input.
195 */
196 PRTSEMEVENTMULTIINTERNAL pThis = (PRTSEMEVENTMULTIINTERNAL)hEventMultiSem;
197 if (!pThis)
198 return VERR_INVALID_PARAMETER;
199 AssertPtrReturn(pThis, VERR_INVALID_PARAMETER);
200 AssertMsgReturn(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC, ("%p u32Magic=%RX32\n", pThis, pThis->u32Magic), VERR_INVALID_PARAMETER);
201 rtR0SemEventMultiLnxRetain(pThis);
202
203 /*
204 * Signal the event object. The cause of the paranoia here is racing to try
205 * deal with racing RTSemEventMultiSignal calls (should probably be
206 * forbidden, but it's relatively easy to handle).
207 */
208 do
209 {
210 fNew = fOld = ASMAtomicUoReadU32(&pThis->fStateAndGen);
211 fNew += 1 << RTSEMEVENTMULTILNX_GEN_SHIFT;
212 fNew |= RTSEMEVENTMULTILNX_STATE_MASK;
213 }
214 while (!ASMAtomicCmpXchgU32(&pThis->fStateAndGen, fNew, fOld));
215
216 wake_up_all(&pThis->Head);
217
218 rtR0SemEventMultiLnxRelease(pThis);
219 IPRT_LINUX_RESTORE_EFL_AC();
220 return VINF_SUCCESS;
221}
222RT_EXPORT_SYMBOL(RTSemEventMultiSignal);
223
224
225RTDECL(int) RTSemEventMultiReset(RTSEMEVENTMULTI hEventMultiSem)
226{
227 /*
228 * Validate input.
229 */
230 PRTSEMEVENTMULTIINTERNAL pThis = (PRTSEMEVENTMULTIINTERNAL)hEventMultiSem;
231 if (!pThis)
232 return VERR_INVALID_PARAMETER;
233 AssertPtrReturn(pThis, VERR_INVALID_PARAMETER);
234 AssertMsgReturn(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC, ("%p u32Magic=%RX32\n", pThis, pThis->u32Magic), VERR_INVALID_PARAMETER);
235 rtR0SemEventMultiLnxRetain(pThis);
236
237 /*
238 * Reset it.
239 */
240 ASMAtomicAndU32(&pThis->fStateAndGen, ~RTSEMEVENTMULTILNX_STATE_MASK);
241
242 rtR0SemEventMultiLnxRelease(pThis);
243 return VINF_SUCCESS;
244}
245RT_EXPORT_SYMBOL(RTSemEventMultiReset);
246
247
248/**
249 * Worker for RTSemEventMultiWaitEx and RTSemEventMultiWaitExDebug.
250 *
251 * @returns VBox status code.
252 * @param pThis The event semaphore.
253 * @param fFlags See RTSemEventMultiWaitEx.
254 * @param uTimeout See RTSemEventMultiWaitEx.
255 * @param pSrcPos The source code position of the wait.
256 */
257static int rtR0SemEventMultiLnxWait(PRTSEMEVENTMULTIINTERNAL pThis, uint32_t fFlags, uint64_t uTimeout,
258 PCRTLOCKVALSRCPOS pSrcPos)
259{
260 uint32_t fOrgStateAndGen;
261 int rc;
262 RT_NOREF_PV(pSrcPos);
263
264 /*
265 * Validate the input.
266 */
267 AssertPtrReturn(pThis, VERR_INVALID_PARAMETER);
268 AssertMsgReturn(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC, ("%p u32Magic=%RX32\n", pThis, pThis->u32Magic), VERR_INVALID_PARAMETER);
269 AssertReturn(RTSEMWAIT_FLAGS_ARE_VALID(fFlags), VERR_INVALID_PARAMETER);
270 rtR0SemEventMultiLnxRetain(pThis);
271
272 /*
273 * Is the event already signalled or do we have to wait?
274 */
275 fOrgStateAndGen = ASMAtomicUoReadU32(&pThis->fStateAndGen);
276 if (fOrgStateAndGen & RTSEMEVENTMULTILNX_STATE_MASK)
277 rc = VINF_SUCCESS;
278 else
279 {
280 /*
281 * We have to wait.
282 */
283 RTR0SEMLNXWAIT Wait;
284 IPRT_LINUX_SAVE_EFL_AC();
285 rc = rtR0SemLnxWaitInit(&Wait, fFlags, uTimeout, &pThis->Head);
286 if (RT_SUCCESS(rc))
287 {
288 IPRT_DEBUG_SEMS_STATE(pThis, 'E');
289 for (;;)
290 {
291 /* The destruction test. */
292 if (RT_UNLIKELY(pThis->u32Magic != RTSEMEVENTMULTI_MAGIC))
293 rc = VERR_SEM_DESTROYED;
294 else
295 {
296 rtR0SemLnxWaitPrepare(&Wait);
297
298 /* Check the exit conditions. */
299 if (RT_UNLIKELY(pThis->u32Magic != RTSEMEVENTMULTI_MAGIC))
300 rc = VERR_SEM_DESTROYED;
301 else if (ASMAtomicUoReadU32(&pThis->fStateAndGen) != fOrgStateAndGen)
302 rc = VINF_SUCCESS;
303 else if (rtR0SemLnxWaitHasTimedOut(&Wait))
304 rc = VERR_TIMEOUT;
305 else if (rtR0SemLnxWaitWasInterrupted(&Wait))
306 rc = VERR_INTERRUPTED;
307 else
308 {
309 /* Do the wait and then recheck the conditions. */
310 rtR0SemLnxWaitDoIt(&Wait);
311 continue;
312 }
313 }
314 break;
315 }
316
317 rtR0SemLnxWaitDelete(&Wait);
318 IPRT_DEBUG_SEMS_STATE_RC(pThis, 'E', rc);
319 }
320 IPRT_LINUX_RESTORE_EFL_AC();
321 }
322
323 rtR0SemEventMultiLnxRelease(pThis);
324 return rc;
325}
326
327
328RTDECL(int) RTSemEventMultiWaitEx(RTSEMEVENTMULTI hEventMultiSem, uint32_t fFlags, uint64_t uTimeout)
329{
330#ifndef RTSEMEVENT_STRICT
331 return rtR0SemEventMultiLnxWait(hEventMultiSem, fFlags, uTimeout, NULL);
332#else
333 RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_NORMAL_API();
334 return rtR0SemEventMultiLnxWait(hEventMultiSem, fFlags, uTimeout, &SrcPos);
335#endif
336}
337RT_EXPORT_SYMBOL(RTSemEventMultiWaitEx);
338
339
340RTDECL(int) RTSemEventMultiWaitExDebug(RTSEMEVENTMULTI hEventMultiSem, uint32_t fFlags, uint64_t uTimeout,
341 RTHCUINTPTR uId, RT_SRC_POS_DECL)
342{
343 RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_DEBUG_API();
344 return rtR0SemEventMultiLnxWait(hEventMultiSem, fFlags, uTimeout, &SrcPos);
345}
346RT_EXPORT_SYMBOL(RTSemEventMultiWaitExDebug);
347
348
349RTDECL(uint32_t) RTSemEventMultiGetResolution(void)
350{
351 return rtR0SemLnxWaitGetResolution();
352}
353RT_EXPORT_SYMBOL(RTSemEventMultiGetResolution);
354
355
356RTR0DECL(bool) RTSemEventMultiIsSignalSafe(void)
357{
358 return true;
359}
360RT_EXPORT_SYMBOL(RTSemEventMultiIsSignalSafe);
361
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use