diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-11 08:17:27 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-11 08:17:27 +0000 |
commit | f215e02bf85f68d3a6106c2a1f4f7f063f819064 (patch) | |
tree | 6bb5b92c046312c4e95ac2620b10ddf482d3fa8b /src/VBox/Runtime/r0drv/netbsd/semeventmulti-r0drv-netbsd.c | |
parent | Initial commit. (diff) | |
download | virtualbox-f215e02bf85f68d3a6106c2a1f4f7f063f819064.tar.xz virtualbox-f215e02bf85f68d3a6106c2a1f4f7f063f819064.zip |
Adding upstream version 7.0.14-dfsg.upstream/7.0.14-dfsg
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/VBox/Runtime/r0drv/netbsd/semeventmulti-r0drv-netbsd.c')
-rw-r--r-- | src/VBox/Runtime/r0drv/netbsd/semeventmulti-r0drv-netbsd.c | 360 |
1 files changed, 360 insertions, 0 deletions
diff --git a/src/VBox/Runtime/r0drv/netbsd/semeventmulti-r0drv-netbsd.c b/src/VBox/Runtime/r0drv/netbsd/semeventmulti-r0drv-netbsd.c new file mode 100644 index 00000000..84c2e726 --- /dev/null +++ b/src/VBox/Runtime/r0drv/netbsd/semeventmulti-r0drv-netbsd.c @@ -0,0 +1,360 @@ +/* $Id: semeventmulti-r0drv-netbsd.c $ */ +/** @file + * IPRT - Multiple Release Event Semaphores, Ring-0 Driver, NetBSD. + */ + +/* + * Contributed by knut st. osmundsen. + * + * Copyright (C) 2007-2023 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + * -------------------------------------------------------------------- + * + * Copyright (c) 2007 knut st. osmundsen <bird-src-spam@anduin.net> + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#define RTSEMEVENTMULTI_WITHOUT_REMAPPING +#include "the-netbsd-kernel.h" +#include "internal/iprt.h" +#include <iprt/semaphore.h> + +#include <iprt/assert.h> +#include <iprt/asm.h> +#include <iprt/err.h> +#include <iprt/mem.h> +#include <iprt/lockvalidator.h> + +#include "sleepqueue-r0drv-netbsd.h" +#include "internal/magics.h" + + +/********************************************************************************************************************************* +* Defined Constants And Macros * +*********************************************************************************************************************************/ +/** @name fStateAndGen values + * @{ */ +/** The state bit number. */ +#define RTSEMEVENTMULTIBSD_STATE_BIT 0 +/** The state mask. */ +#define RTSEMEVENTMULTIBSD_STATE_MASK RT_BIT_32(RTSEMEVENTMULTIBSD_STATE_BIT) +/** The generation mask. */ +#define RTSEMEVENTMULTIBSD_GEN_MASK ~RTSEMEVENTMULTIBSD_STATE_MASK +/** The generation shift. */ +#define RTSEMEVENTMULTIBSD_GEN_SHIFT 1 +/** The initial variable value. */ +#define RTSEMEVENTMULTIBSD_STATE_GEN_INIT UINT32_C(0xfffffffc) +/** @} */ + + +/********************************************************************************************************************************* +* Structures and Typedefs * +*********************************************************************************************************************************/ +/** + * NetBSD multiple release event semaphore. + */ +typedef struct RTSEMEVENTMULTIINTERNAL +{ + /** Magic value (RTSEMEVENTMULTI_MAGIC). */ + uint32_t volatile u32Magic; + /** The object state bit and generation counter. + * The generation counter is incremented every time the object is + * signalled. */ + uint32_t volatile fStateAndGen; + /** Reference counter. */ + uint32_t volatile cRefs; +} RTSEMEVENTMULTIINTERNAL, *PRTSEMEVENTMULTIINTERNAL; + + +RTDECL(int) RTSemEventMultiCreate(PRTSEMEVENTMULTI phEventMultiSem) +{ + return RTSemEventMultiCreateEx(phEventMultiSem, 0 /*fFlags*/, NIL_RTLOCKVALCLASS, NULL); +} + + +RTDECL(int) RTSemEventMultiCreateEx(PRTSEMEVENTMULTI phEventMultiSem, uint32_t fFlags, RTLOCKVALCLASS hClass, + const char *pszNameFmt, ...) +{ + PRTSEMEVENTMULTIINTERNAL pThis; + + AssertReturn(!(fFlags & ~RTSEMEVENTMULTI_FLAGS_NO_LOCK_VAL), VERR_INVALID_PARAMETER); + pThis = (PRTSEMEVENTMULTIINTERNAL)RTMemAlloc(sizeof(*pThis)); + if (pThis) + { + pThis->u32Magic = RTSEMEVENTMULTI_MAGIC; + pThis->fStateAndGen = RTSEMEVENTMULTIBSD_STATE_GEN_INIT; + pThis->cRefs = 1; + + *phEventMultiSem = pThis; + return VINF_SUCCESS; + } + return VERR_NO_MEMORY; +} + + +/** + * Retain a reference to the semaphore. + * + * @param pThis The semaphore. + */ +DECLINLINE(void) rtR0SemEventMultiBsdRetain(PRTSEMEVENTMULTIINTERNAL pThis) +{ + uint32_t cRefs = ASMAtomicIncU32(&pThis->cRefs); + Assert(cRefs && cRefs < 100000); +} + + +/** + * Release a reference, destroy the thing if necessary. + * + * @param pThis The semaphore. + */ +DECLINLINE(void) rtR0SemEventMultiBsdRelease(PRTSEMEVENTMULTIINTERNAL pThis) +{ + if (RT_UNLIKELY(ASMAtomicDecU32(&pThis->cRefs) == 0)) + { + Assert(pThis->u32Magic != RTSEMEVENTMULTI_MAGIC); + RTMemFree(pThis); + } +} + + +RTDECL(int) RTSemEventMultiDestroy(RTSEMEVENTMULTI hEventMultiSem) +{ + /* + * Validate input. + */ + PRTSEMEVENTMULTIINTERNAL pThis = (PRTSEMEVENTMULTIINTERNAL)hEventMultiSem; + if (pThis == NIL_RTSEMEVENTMULTI) + return VINF_SUCCESS; + AssertPtrReturn(pThis, VERR_INVALID_PARAMETER); + AssertMsgReturn(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC, ("%p u32Magic=%RX32\n", pThis, pThis->u32Magic), VERR_INVALID_PARAMETER); + Assert(pThis->cRefs > 0); + + /* + * Invalidate it and signal the object just in case. + */ + ASMAtomicWriteU32(&pThis->u32Magic, ~RTSEMEVENTMULTI_MAGIC); + ASMAtomicAndU32(&pThis->fStateAndGen, RTSEMEVENTMULTIBSD_GEN_MASK); + rtR0SemBsdBroadcast(pThis); + rtR0SemEventMultiBsdRelease(pThis); + return VINF_SUCCESS; +} + + +RTDECL(int) RTSemEventMultiSignal(RTSEMEVENTMULTI hEventMultiSem) +{ + uint32_t fNew; + uint32_t fOld; + + /* + * Validate input. + */ + PRTSEMEVENTMULTIINTERNAL pThis = (PRTSEMEVENTMULTIINTERNAL)hEventMultiSem; + if (!pThis) + return VERR_INVALID_PARAMETER; + AssertPtrReturn(pThis, VERR_INVALID_PARAMETER); + AssertMsgReturn(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC, ("%p u32Magic=%RX32\n", pThis, pThis->u32Magic), VERR_INVALID_PARAMETER); + rtR0SemEventMultiBsdRetain(pThis); + + /* + * Signal the event object. The cause of the parnoia here is racing to try + * deal with racing RTSemEventMultiSignal calls (should probably be + * forbidden, but it's relatively easy to handle). + */ + do + { + fNew = fOld = ASMAtomicUoReadU32(&pThis->fStateAndGen); + fNew += 1 << RTSEMEVENTMULTIBSD_GEN_SHIFT; + fNew |= RTSEMEVENTMULTIBSD_STATE_MASK; + } + while (!ASMAtomicCmpXchgU32(&pThis->fStateAndGen, fNew, fOld)); + + rtR0SemBsdBroadcast(pThis); + rtR0SemEventMultiBsdRelease(pThis); + return VINF_SUCCESS; +} + + +RTDECL(int) RTSemEventMultiReset(RTSEMEVENTMULTI hEventMultiSem) +{ + /* + * Validate input. + */ + PRTSEMEVENTMULTIINTERNAL pThis = (PRTSEMEVENTMULTIINTERNAL)hEventMultiSem; + if (!pThis) + return VERR_INVALID_PARAMETER; + AssertPtrReturn(pThis, VERR_INVALID_PARAMETER); + AssertMsgReturn(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC, ("%p u32Magic=%RX32\n", pThis, pThis->u32Magic), VERR_INVALID_PARAMETER); + rtR0SemEventMultiBsdRetain(pThis); + + /* + * Reset it. + */ + ASMAtomicAndU32(&pThis->fStateAndGen, ~RTSEMEVENTMULTIBSD_STATE_MASK); + + rtR0SemEventMultiBsdRelease(pThis); + return VINF_SUCCESS; +} + + +/** + * Worker for RTSemEventMultiWaitEx and RTSemEventMultiWaitExDebug. + * + * @returns VBox status code. + * @param pThis The event semaphore. + * @param fFlags See RTSemEventMultiWaitEx. + * @param uTimeout See RTSemEventMultiWaitEx. + * @param pSrcPos The source code position of the wait. + */ +static int rtR0SemEventMultiBsdWait(PRTSEMEVENTMULTIINTERNAL pThis, uint32_t fFlags, uint64_t uTimeout, + PCRTLOCKVALSRCPOS pSrcPos) +{ + uint32_t fOrgStateAndGen; + int rc; + + /* + * Validate the input. + */ + AssertPtrReturn(pThis, VERR_INVALID_PARAMETER); + AssertMsgReturn(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC, ("%p u32Magic=%RX32\n", pThis, pThis->u32Magic), VERR_INVALID_PARAMETER); + AssertReturn(RTSEMWAIT_FLAGS_ARE_VALID(fFlags), VERR_INVALID_PARAMETER); + rtR0SemEventMultiBsdRetain(pThis); + + /* + * Is the event already signalled or do we have to wait? + */ + fOrgStateAndGen = ASMAtomicUoReadU32(&pThis->fStateAndGen); + if (fOrgStateAndGen & RTSEMEVENTMULTIBSD_STATE_MASK) + rc = VINF_SUCCESS; + else + { + /* + * We have to wait. + */ + RTR0SEMBSDSLEEP Wait; + rc = rtR0SemBsdWaitInit(&Wait, fFlags, uTimeout, pThis); + if (RT_SUCCESS(rc)) + { + for (;;) + { + /* The destruction test. */ + if (RT_UNLIKELY(pThis->u32Magic != RTSEMEVENTMULTI_MAGIC)) + rc = VERR_SEM_DESTROYED; + else + { + rtR0SemBsdWaitPrepare(&Wait); + + /* Check the exit conditions. */ + if (RT_UNLIKELY(pThis->u32Magic != RTSEMEVENTMULTI_MAGIC)) + rc = VERR_SEM_DESTROYED; + else if (ASMAtomicUoReadU32(&pThis->fStateAndGen) != fOrgStateAndGen) + rc = VINF_SUCCESS; + else if (rtR0SemBsdWaitHasTimedOut(&Wait)) + rc = VERR_TIMEOUT; + else if (rtR0SemBsdWaitWasInterrupted(&Wait)) + rc = VERR_INTERRUPTED; + else + { + /* Do the wait and then recheck the conditions. */ + rtR0SemBsdWaitDoIt(&Wait); + continue; + } + } + break; + } + + rtR0SemBsdWaitDelete(&Wait); + } + } + + rtR0SemEventMultiBsdRelease(pThis); + return rc; +} + + +RTDECL(int) RTSemEventMultiWaitEx(RTSEMEVENTMULTI hEventMultiSem, uint32_t fFlags, uint64_t uTimeout) +{ +#ifndef RTSEMEVENT_STRICT + return rtR0SemEventMultiBsdWait(hEventMultiSem, fFlags, uTimeout, NULL); +#else + RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_NORMAL_API(); + return rtR0SemEventMultiBsdWait(hEventMultiSem, fFlags, uTimeout, &SrcPos); +#endif +} +RT_EXPORT_SYMBOL(RTSemEventMultiWaitEx); + + +RTDECL(int) RTSemEventMultiWaitExDebug(RTSEMEVENTMULTI hEventMultiSem, uint32_t fFlags, uint64_t uTimeout, + RTHCUINTPTR uId, RT_SRC_POS_DECL) +{ + RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_DEBUG_API(); + return rtR0SemEventMultiBsdWait(hEventMultiSem, fFlags, uTimeout, &SrcPos); +} +RT_EXPORT_SYMBOL(RTSemEventMultiWaitExDebug); + + +RTDECL(uint32_t) RTSemEventMultiGetResolution(void) +{ + return rtR0SemBsdWaitGetResolution(); +} +RT_EXPORT_SYMBOL(RTSemEventMultiGetResolution); + + +RTR0DECL(bool) RTSemEventMultiIsSignalSafe(void) +{ + /** @todo check the code... */ + return false; +} +RT_EXPORT_SYMBOL(RTSemEventMultiIsSignalSafe); + |