semeventmulti-r0drv-solaris.c revision 0b7d24ee33cf513ef5a83fc9d6b9ba0a0427b39c
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync/* $Id$ */
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync/** @file
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync * IPRT - Multiple Release Event Semaphores, Ring-0 Driver, Solaris.
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync */
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync/*
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync * Copyright (C) 2006-2010 Oracle Corporation
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync *
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync * available from http://www.virtualbox.org. This file is free software;
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync * you can redistribute it and/or modify it under the terms of the GNU
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync * General Public License (GPL) as published by the Free Software
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync *
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync * The contents of this file may alternatively be used under the terms
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync * of the Common Development and Distribution License Version 1.0
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync * VirtualBox OSE distribution, in which case the provisions of the
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync * CDDL are applicable instead of those of the GPL.
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync *
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync * You may elect to license modified versions of this file under the
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync * terms and conditions of either the GPL or the CDDL or both.
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync */
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync/*******************************************************************************
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync* Header Files *
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync*******************************************************************************/
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync#include "the-solaris-kernel.h"
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync#include "internal/iprt.h"
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync#include <iprt/semaphore.h>
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync#include <iprt/assert.h>
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync#include <iprt/asm.h>
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync#if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86)
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync# include <iprt/asm-amd64-x86.h>
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync#endif
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync#include <iprt/err.h>
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync#include <iprt/lockvalidator.h>
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync#include <iprt/mem.h>
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync#include <iprt/mp.h>
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync#include <iprt/thread.h>
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync#include <iprt/time.h>
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync#include "internal/magics.h"
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync/*******************************************************************************
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync* Defined Constants And Macros *
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync*******************************************************************************/
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync/** @name fStateAndGen values
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync * @{ */
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync/** The state bit number. */
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync#define RTSEMEVENTMULTISOL_STATE_BIT 0
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync/** The state mask. */
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync#define RTSEMEVENTMULTISOL_STATE_MASK RT_BIT_32(RTSEMEVENTMULTISOL_STATE_BIT)
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync/** The generation mask. */
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync#define RTSEMEVENTMULTISOL_GEN_MASK ~RTSEMEVENTMULTISOL_STATE_MASK
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync/** The generation shift. */
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync#define RTSEMEVENTMULTISOL_GEN_SHIFT 1
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync/** The initial variable value. */
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync#define RTSEMEVENTMULTISOL_STATE_GEN_INIT UINT32_C(0xfffffffc)
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync/** @} */
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync/*******************************************************************************
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync* Structures and Typedefs *
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync*******************************************************************************/
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync/**
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync * Solaris multiple release event semaphore.
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync */
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsynctypedef struct RTSEMEVENTMULTIINTERNAL
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync{
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync /** Magic value (RTSEMEVENTMULTI_MAGIC). */
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync uint32_t volatile u32Magic;
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync /** The number of references. */
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync uint32_t volatile cRefs;
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync /** The object state bit and generation counter.
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync * The generation counter is incremented every time the object is
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync * signalled. */
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync uint32_t volatile fStateAndGen;
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync /** The Solaris mutex protecting this structure and pairing up the with the cv. */
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync kmutex_t Mtx;
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync /** The Solaris condition variable. */
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync kcondvar_t Cnd;
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync} RTSEMEVENTMULTIINTERNAL, *PRTSEMEVENTMULTIINTERNAL;
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsyncRTDECL(int) RTSemEventMultiCreate(PRTSEMEVENTMULTI phEventMultiSem)
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync{
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync return RTSemEventMultiCreateEx(phEventMultiSem, 0 /*fFlags*/, NIL_RTLOCKVALCLASS, NULL);
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync}
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsyncRTDECL(int) RTSemEventMultiCreateEx(PRTSEMEVENTMULTI phEventMultiSem, uint32_t fFlags, RTLOCKVALCLASS hClass,
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync const char *pszNameFmt, ...)
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync{
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync AssertReturn(!(fFlags & ~RTSEMEVENTMULTI_FLAGS_NO_LOCK_VAL), VERR_INVALID_PARAMETER);
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync AssertPtrReturn(phEventMultiSem, VERR_INVALID_POINTER);
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync RT_ASSERT_PREEMPTIBLE();
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync AssertCompile(sizeof(RTSEMEVENTMULTIINTERNAL) > sizeof(void *));
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync PRTSEMEVENTMULTIINTERNAL pThis = (PRTSEMEVENTMULTIINTERNAL)RTMemAlloc(sizeof(*pThis));
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync if (pThis)
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync {
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync pThis->u32Magic = RTSEMEVENTMULTI_MAGIC;
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync pThis->cRefs = 1;
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync pThis->fStateAndGen = RTSEMEVENTMULTISOL_STATE_GEN_INIT;
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync mutex_init(&pThis->Mtx, "IPRT Multiple Release Event Semaphore", MUTEX_DRIVER, (void *)ipltospl(DISP_LEVEL));
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync cv_init(&pThis->Cnd, "IPRT CV", CV_DRIVER, NULL);
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync *phEventMultiSem = pThis;
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync return VINF_SUCCESS;
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync }
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync return VERR_NO_MEMORY;
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync}
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync/**
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync * Retain a reference to the semaphore.
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync *
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync * @param pThis The semaphore.
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync */
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsyncDECLINLINE(void) rtR0SemEventMultiSolRetain(PRTSEMEVENTMULTIINTERNAL pThis)
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync{
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync uint32_t cRefs = ASMAtomicIncU32(&pThis->cRefs);
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync Assert(cRefs && cRefs < 100000);
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync}
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync/**
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync * Destructor that is called when cRefs == 0.
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync *
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync * @param pThis The instance to destroy.
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync */
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsyncstatic void rtSemEventMultiDtor(PRTSEMEVENTMULTIINTERNAL pThis)
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync{
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync Assert(pThis->u32Magic != RTSEMEVENTMULTI_MAGIC);
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync cv_destroy(&pThis->Cnd);
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync mutex_destroy(&pThis->Mtx);
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync RTMemFree(pThis);
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync}
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync/**
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync * Release a reference, destroy the thing if necessary.
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync *
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync * @param pThis The semaphore.
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync */
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsyncDECLINLINE(void) rtR0SemEventMultiSolRelease(PRTSEMEVENTMULTIINTERNAL pThis)
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync{
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync if (RT_UNLIKELY(ASMAtomicDecU32(&pThis->cRefs) == 0))
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync rtSemEventMultiDtor(pThis);
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync}
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsyncRTDECL(int) RTSemEventMultiDestroy(RTSEMEVENTMULTI hEventMultiSem)
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync{
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync PRTSEMEVENTMULTIINTERNAL pThis = (PRTSEMEVENTMULTIINTERNAL)hEventMultiSem;
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync if (pThis == NIL_RTSEMEVENTMULTI)
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync return VINF_SUCCESS;
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync AssertMsgReturn(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC, ("pThis=%p u32Magic=%#x\n", pThis, pThis->u32Magic), VERR_INVALID_HANDLE);
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync AssertMsgReturn(pThis->cRefs > 0, ("pThis=%p cRefs=%d\n", pThis, pThis->cRefs), VERR_INVALID_HANDLE);
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync RT_ASSERT_INTS_ON();
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync mutex_enter(&pThis->Mtx);
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync /* Invalidate the handle and wake up all threads that might be waiting on the semaphore. */
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync Assert(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC);
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync ASMAtomicWriteU32(&pThis->u32Magic, RTSEMEVENTMULTI_MAGIC_DEAD);
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync ASMAtomicAndU32(&pThis->fStateAndGen, RTSEMEVENTMULTISOL_GEN_MASK);
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync cv_broadcast(&pThis->Cnd);
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync /* Drop the reference from RTSemEventMultiCreateEx. */
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync mutex_exit(&pThis->Mtx);
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync rtR0SemEventMultiSolRelease(pThis);
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync return VINF_SUCCESS;
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync}
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsyncRTDECL(int) RTSemEventMultiSignal(RTSEMEVENTMULTI hEventMultiSem)
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync{
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync PRTSEMEVENTMULTIINTERNAL pThis = (PRTSEMEVENTMULTIINTERNAL)hEventMultiSem;
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync RT_ASSERT_PREEMPT_CPUID_VAR();
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync AssertMsgReturn(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC,
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync ("pThis=%p u32Magic=%#x\n", pThis, pThis->u32Magic),
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync VERR_INVALID_HANDLE);
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync RT_ASSERT_INTS_ON();
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync rtR0SemEventMultiSolRetain(pThis);
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync /*
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync * If we're in interrupt context we need to unpin the underlying current
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync * thread as this could lead to a deadlock (see #4259 for the full explanation)
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync *
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync * Note! See remarks about preemption in RTSemEventSignal.
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync */
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync int fAcquired = mutex_tryenter(&pThis->Mtx);
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync if (!fAcquired)
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync {
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync if (curthread->t_intr && getpil() < DISP_LEVEL)
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync {
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync RTTHREADPREEMPTSTATE PreemptState = RTTHREADPREEMPTSTATE_INITIALIZER;
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync RTThreadPreemptDisable(&PreemptState);
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync preempt();
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync RTThreadPreemptRestore(&PreemptState);
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync }
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync mutex_enter(&pThis->Mtx);
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync }
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync Assert(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC);
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync /*
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync * Do the job.
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync */
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync uint32_t fNew = ASMAtomicUoReadU32(&pThis->fStateAndGen);
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync fNew += 1 << RTSEMEVENTMULTISOL_GEN_SHIFT;
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync fNew |= RTSEMEVENTMULTISOL_STATE_MASK;
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync ASMAtomicWriteU32(&pThis->fStateAndGen, fNew);
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync cv_broadcast(&pThis->Cnd);
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync mutex_exit(&pThis->Mtx);
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync rtR0SemEventMultiSolRelease(pThis);
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync RT_ASSERT_PREEMPT_CPUID();
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync return VINF_SUCCESS;
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync}
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsyncRTDECL(int) RTSemEventMultiReset(RTSEMEVENTMULTI hEventMultiSem)
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync{
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync PRTSEMEVENTMULTIINTERNAL pThis = (PRTSEMEVENTMULTIINTERNAL)hEventMultiSem;
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync RT_ASSERT_PREEMPT_CPUID_VAR();
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync AssertMsgReturn(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC,
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync ("pThis=%p u32Magic=%#x\n", pThis, pThis->u32Magic),
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync VERR_INVALID_HANDLE);
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync RT_ASSERT_INTS_ON();
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync rtR0SemEventMultiSolRetain(pThis);
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync /*
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync * If we're in interrupt context we need to unpin the underlying current
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync * thread as this could lead to a deadlock (see #4259 for the full explanation)
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync *
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync * Note! See remarks about preemption in RTSemEventSignal.
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync */
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync int fAcquired = mutex_tryenter(&pThis->Mtx);
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync if (!fAcquired)
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync {
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync if (curthread->t_intr && getpil() < DISP_LEVEL)
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync {
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync RTTHREADPREEMPTSTATE PreemptState = RTTHREADPREEMPTSTATE_INITIALIZER;
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync RTThreadPreemptDisable(&PreemptState);
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync preempt();
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync RTThreadPreemptRestore(&PreemptState);
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync }
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync mutex_enter(&pThis->Mtx);
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync }
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync Assert(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC);
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync /*
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync * Do the job (could be done without the lock, but play safe).
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync */
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync ASMAtomicAndU32(&pThis->fStateAndGen, ~RTSEMEVENTMULTISOL_STATE_MASK);
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync mutex_exit(&pThis->Mtx);
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync rtR0SemEventMultiSolRelease(pThis);
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync RT_ASSERT_PREEMPT_CPUID();
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync return VINF_SUCCESS;
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync}
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync/* -------- Move to header ---------- */
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsynctypedef struct RTR0SEMSOLWAIT
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync{
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync /** The absolute timeout given as nano seconds since the start of the
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync * monotonic clock. */
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync uint64_t uNsAbsTimeout;
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync /** The timeout in nano seconds relative to the start of the wait. */
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync uint64_t cNsRelTimeout;
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync /** The native timeout value. */
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync union
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync {
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync /** The timeout (abs lbolt) when fHighRes is false. */
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync clock_t lTimeout;
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync } u;
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync /** Set if we use high resolution timeouts. */
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync bool fHighRes;
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync /** Set if it's an indefinite wait. */
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync bool fIndefinite;
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync /** Set if we've already timed out.
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync * Set by rtR0SemSolWaitDoIt or rtR0SemSolWaitHighResTimeout, read by
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync * rtR0SemSolWaitHasTimedOut. */
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync bool volatile fTimedOut;
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync /** Whether the wait was interrupted. */
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync bool fInterrupted;
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync /** Interruptible or uninterruptible wait. */
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync bool fInterruptible;
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync /** The thread to wake up. */
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync kthread_t *pThread;
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync /** Cylic timer ID (used by the timeout callback). */
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync cyclic_id_t idCy;
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync} RTR0SEMSOLWAIT;
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync/** Pointer to a solaris semaphore wait structure. */
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsynctypedef RTR0SEMSOLWAIT *PRTR0SEMSOLWAIT;
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync/**
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync * Initializes a wait.
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync *
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync * The caller MUST check the wait condition BEFORE calling this function or the
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync * timeout logic will be flawed.
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync *
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync * @returns VINF_SUCCESS or VERR_TIMEOUT.
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync * @param pWait The wait structure.
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync * @param fFlags The wait flags.
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync * @param uTimeout The timeout.
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync * @param pWaitQueue The wait queue head.
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync */
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsyncDECLINLINE(int) rtR0SemSolWaitInit(PRTR0SEMSOLWAIT pWait, uint32_t fFlags, uint64_t uTimeout)
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync{
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync /*
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync * Process the flags and timeout.
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync */
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync if (!(fFlags & RTSEMWAIT_FLAGS_INDEFINITE))
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync {
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync if (fFlags & RTSEMWAIT_FLAGS_MILLISECS)
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync uTimeout = uTimeout < UINT64_MAX / UINT32_C(1000000) * UINT32_C(1000000)
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync ? uTimeout * UINT32_C(1000000)
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync : UINT64_MAX;
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync if (uTimeout == UINT64_MAX)
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync fFlags |= RTSEMWAIT_FLAGS_INDEFINITE;
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync else
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync {
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync uint64_t u64Now;
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync if (fFlags & RTSEMWAIT_FLAGS_RELATIVE)
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync {
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync if (uTimeout == 0)
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync return VERR_TIMEOUT;
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync u64Now = RTTimeSystemNanoTS();
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync pWait->cNsRelTimeout = uTimeout;
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync pWait->uNsAbsTimeout = u64Now + uTimeout;
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync if (pWait->uNsAbsTimeout < u64Now) /* overflow */
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync fFlags |= RTSEMWAIT_FLAGS_INDEFINITE;
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync }
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync else
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync {
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync u64Now = RTTimeSystemNanoTS();
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync if (u64Now >= uTimeout)
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync return VERR_TIMEOUT;
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync pWait->cNsRelTimeout = uTimeout - u64Now;
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync pWait->uNsAbsTimeout = uTimeout;
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync }
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync }
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync }
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync if (!(fFlags & RTSEMWAIT_FLAGS_INDEFINITE))
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync {
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync pWait->fIndefinite = false;
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync if ( (fFlags & (RTSEMWAIT_FLAGS_NANOSECS | RTSEMWAIT_FLAGS_ABSOLUTE))
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync || pWait->cNsRelTimeout < UINT32_C(1000000000) / 100 /*Hz*/ * 4)
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync pWait->fHighRes = true;
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync else
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync {
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync#if 1
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync uint64_t cTicks = NSEC_TO_TICK_ROUNDUP(uTimeout);
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync#else
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync uint64_t cTicks = drv_usectohz((clock_t)(uTimeout / 1000));
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync#endif
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync if (cTicks >= LONG_MAX)
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync fFlags |= RTSEMWAIT_FLAGS_INDEFINITE;
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync else
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync {
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync pWait->u.lTimeout = ddi_get_lbolt() + cTicks;
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync pWait->fHighRes = false;
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync }
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync }
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync }
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync if (fFlags & RTSEMWAIT_FLAGS_INDEFINITE)
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync {
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync pWait->fIndefinite = true;
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync pWait->fHighRes = false;
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync pWait->uNsAbsTimeout = UINT64_MAX;
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync pWait->cNsRelTimeout = UINT64_MAX;
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync pWait->u.lTimeout = LONG_MAX;
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync }
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync pWait->fTimedOut = false;
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync pWait->fInterrupted = false;
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync pWait->fInterruptible = !!(fFlags & RTSEMWAIT_FLAGS_INTERRUPTIBLE);
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync pWait->pThread = curthread;
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync pWait->idCy = CYCLIC_NONE;
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync return VINF_SUCCESS;
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync}
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync/**
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync * Cyclic timeout callback that sets the timeout indicator and wakes up the
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync * waiting thread.
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync *
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync * @param pvUser The wait structure.
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync */
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsyncstatic void rtR0SemSolWaitHighResTimeout(void *pvUser)
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync{
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync PRTR0SEMSOLWAIT pWait = (PRTR0SEMSOLWAIT)pvUser;
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync kthread_t *pThread = pWait->pThread;
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync if (VALID_PTR(pThread)) /* paranoia */
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync {
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync /* Note: Trying to take the cpu_lock here doesn't work. */
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync if (mutex_owner(&cpu_lock) == curthread)
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync {
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync cyclic_remove(pWait->idCy);
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync pWait->idCy = CYCLIC_NONE;
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync }
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync ASMAtomicWriteBool(&pWait->fTimedOut, true);
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync setrun(pThread);
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync }
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync}
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync/**
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync * Do the actual wait.
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync *
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync * @param pWait The wait structure.
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync * @param pCnd The condition variable to wait on.
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync * @param pMtx The mutex related to the condition variable.
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync * The caller has entered this.
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync */
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsyncDECLINLINE(void) rtR0SemSolWaitDoIt(PRTR0SEMSOLWAIT pWait, kcondvar_t *pCnd, kmutex_t *pMtx)
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync{
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync int rc = 1;
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync if (pWait->fIndefinite)
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync {
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync /*
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync * No timeout - easy.
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync */
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync if (pWait->fInterruptible)
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync rc = cv_wait_sig(pCnd, pMtx);
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync else
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync cv_wait(pCnd, pMtx);
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync }
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync else if (pWait->fHighRes)
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync {
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync /*
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync * High resolution timeout - arm a one-shot cyclic for waking up
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync * the thread at the desired time.
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync */
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync cyc_handler_t Cyh;
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync Cyh.cyh_arg = pWait;
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync Cyh.cyh_func = rtR0SemSolWaitHighResTimeout;
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync Cyh.cyh_level = CY_LOW_LEVEL; /// @todo try CY_LOCK_LEVEL and CY_HIGH_LEVEL?
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync cyc_time_t Cyt;
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync Cyt.cyt_when = pWait->uNsAbsTimeout;
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync Cyt.cyt_interval = UINT64_C(1000000000) * 60;
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync mutex_enter(&cpu_lock);
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync pWait->idCy = cyclic_add(&Cyh, &Cyt);
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync mutex_exit(&cpu_lock);
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync if (pWait->fInterruptible)
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync rc = cv_wait_sig(pCnd, pMtx);
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync else
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync cv_wait(pCnd, pMtx);
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync mutex_enter(&cpu_lock);
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync if (pWait->idCy != CYCLIC_NONE)
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync {
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync cyclic_remove(pWait->idCy);
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync pWait->idCy = CYCLIC_NONE;
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync }
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync mutex_exit(&cpu_lock);
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync }
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync else
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync {
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync /*
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync * Normal timeout.
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync */
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync if (pWait->fInterruptible)
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync rc = cv_timedwait_sig(pCnd, pMtx, pWait->u.lTimeout);
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync else
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync rc = cv_timedwait(pCnd, pMtx, pWait->u.lTimeout);
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync }
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync /* Above zero means normal wake-up. */
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync if (rc > 0)
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync return;
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync /* Timeout is signalled by -1. */
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync if (rc == -1)
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync pWait->fTimedOut = true;
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync /* Interruption is signalled by 0. */
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync else
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync {
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync AssertMsg(rc == 0, ("rc=%d\n", rc));
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync pWait->fInterrupted = true;
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync }
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync}
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync/**
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync * Checks if a solaris wait was interrupted.
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync *
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync * @returns true / false
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync * @param pWait The wait structure.
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync * @remarks This shall be called before the first rtR0SemSolWaitDoIt().
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync */
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsyncDECLINLINE(bool) rtR0SemSolWaitWasInterrupted(PRTR0SEMSOLWAIT pWait)
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync{
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync return pWait->fInterrupted;
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync}
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync/**
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync * Checks if a solaris wait has timed out.
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync *
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync * @returns true / false
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync * @param pWait The wait structure.
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync */
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsyncDECLINLINE(bool) rtR0SemSolWaitHasTimedOut(PRTR0SEMSOLWAIT pWait)
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync{
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync return pWait->fTimedOut;
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync}
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync/**
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync * Deletes a solaris wait.
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync *
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync * @param pWait The wait structure.
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync */
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsyncDECLINLINE(void) rtR0SemSolWaitDelete(PRTR0SEMSOLWAIT pWait)
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync{
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync pWait->pThread = NULL;
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync}
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync/* -------- End ---------- */
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync/**
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync * Worker for RTSemEventMultiWaitEx and RTSemEventMultiWaitExDebug.
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync *
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync * @returns VBox status code.
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync * @param pThis The event semaphore.
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync * @param fFlags See RTSemEventMultiWaitEx.
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync * @param uTimeout See RTSemEventMultiWaitEx.
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync * @param pSrcPos The source code position of the wait.
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync */
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsyncstatic int rtR0SemEventMultiSolWait(PRTSEMEVENTMULTIINTERNAL pThis, uint32_t fFlags, uint64_t uTimeout,
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync PCRTLOCKVALSRCPOS pSrcPos)
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync{
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync uint32_t fOrgStateAndGen;
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync int rc;
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync /*
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync * Validate the input.
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync */
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync AssertPtrReturn(pThis, VERR_INVALID_PARAMETER);
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync AssertMsgReturn(pThis->u32Magic == RTSEMEVENTMULTI_MAGIC, ("%p u32Magic=%RX32\n", pThis, pThis->u32Magic), VERR_INVALID_PARAMETER);
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync AssertReturn(RTSEMWAIT_FLAGS_ARE_VALID(fFlags), VERR_INVALID_PARAMETER);
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync rtR0SemEventMultiSolRetain(pThis);
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync mutex_enter(&pThis->Mtx); /* this could be moved down to the else, but play safe for now. */
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync /*
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync * Is the event already signalled or do we have to wait?
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync */
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync fOrgStateAndGen = ASMAtomicUoReadU32(&pThis->fStateAndGen);
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync if (fOrgStateAndGen & RTSEMEVENTMULTISOL_STATE_MASK)
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync rc = VINF_SUCCESS;
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync else
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync {
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync /*
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync * We have to wait.
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync */
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync RTR0SEMSOLWAIT Wait;
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync rc = rtR0SemSolWaitInit(&Wait, fFlags, uTimeout);
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync if (RT_SUCCESS(rc))
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync {
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync for (;;)
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync {
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync /* The destruction test. */
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync if (RT_UNLIKELY(pThis->u32Magic != RTSEMEVENTMULTI_MAGIC))
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync rc = VERR_SEM_DESTROYED;
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync else
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync {
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync /* Check the exit conditions. */
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync if (RT_UNLIKELY(pThis->u32Magic != RTSEMEVENTMULTI_MAGIC))
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync rc = VERR_SEM_DESTROYED;
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync else if (ASMAtomicUoReadU32(&pThis->fStateAndGen) != fOrgStateAndGen)
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync rc = VINF_SUCCESS;
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync else if (rtR0SemSolWaitHasTimedOut(&Wait))
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync rc = VERR_TIMEOUT;
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync else if (rtR0SemSolWaitWasInterrupted(&Wait))
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync rc = VERR_INTERRUPTED;
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync else
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync {
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync /* Do the wait and then recheck the conditions. */
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync rtR0SemSolWaitDoIt(&Wait, &pThis->Cnd, &pThis->Mtx);
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync continue;
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync }
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync }
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync break;
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync }
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync rtR0SemSolWaitDelete(&Wait);
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync }
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync }
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync mutex_exit(&pThis->Mtx);
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync rtR0SemEventMultiSolRelease(pThis);
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync return rc;
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync}
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync#undef RTSemEventMultiWaitEx
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsyncRTDECL(int) RTSemEventMultiWaitEx(RTSEMEVENTMULTI hEventMultiSem, uint32_t fFlags, uint64_t uTimeout)
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync{
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync#ifndef RTSEMEVENT_STRICT
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync return rtR0SemEventMultiSolWait(hEventMultiSem, fFlags, uTimeout, NULL);
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync#else
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_NORMAL_API();
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync return rtR0SemEventMultiSolWait(hEventMultiSem, fFlags, uTimeout, &SrcPos);
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync#endif
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync}
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsyncRTDECL(int) RTSemEventMultiWaitExDebug(RTSEMEVENTMULTI hEventMultiSem, uint32_t fFlags, uint64_t uTimeout,
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync RTHCUINTPTR uId, RT_SRC_POS_DECL)
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync{
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync RTLOCKVALSRCPOS SrcPos = RTLOCKVALSRCPOS_INIT_DEBUG_API();
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync return rtR0SemEventMultiSolWait(hEventMultiSem, fFlags, uTimeout, &SrcPos);
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync}
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync
3194da424708abdd288b28d96892b3a5f3f7df0bvboxsync