semevent-r0drv-solaris.c revision dc95659cf2f6c5830e66313b6046e4317881035b
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer/* $Id$ */
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer/** @file
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer * IPRT - Semaphores, Ring-0 Driver, Solaris.
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer */
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer/*
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer * Copyright (C) 2006-2007 Oracle Corporation
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer *
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer * This file is part of VirtualBox Open Source Edition (OSE), as
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer * available from http://www.virtualbox.org. This file is free software;
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer * you can redistribute it and/or modify it under the terms of the GNU
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer * General Public License (GPL) as published by the Free Software
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer * Foundation, in version 2 as it comes in the "COPYING" file of the
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer *
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer * The contents of this file may alternatively be used under the terms
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer * of the Common Development and Distribution License Version 1.0
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer * VirtualBox OSE distribution, in which case the provisions of the
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer * CDDL are applicable instead of those of the GPL.
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer *
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer * You may elect to license modified versions of this file under the
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer * terms and conditions of either the GPL or the CDDL or both.
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer */
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer/*******************************************************************************
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer* Header Files *
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer*******************************************************************************/
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer#include "the-solaris-kernel.h"
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer#include "internal/iprt.h"
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer#include <iprt/semaphore.h>
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer#include <iprt/assert.h>
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer#include <iprt/asm.h>
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer#if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86)
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer# include <iprt/asm-amd64-x86.h>
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer#endif
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer#include <iprt/err.h>
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer#include <iprt/mem.h>
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer#include <iprt/mp.h>
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer#include <iprt/thread.h>
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer#include "internal/magics.h"
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer/*******************************************************************************
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer* Structures and Typedefs *
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer*******************************************************************************/
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer/**
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer * Solaris event semaphore.
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer */
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremertypedef struct RTSEMEVENTINTERNAL
744e50acbaaf22481b25b921b2bc199c8dd4a35cStephen Brooks{
744e50acbaaf22481b25b921b2bc199c8dd4a35cStephen Brooks /** Magic value (RTSEMEVENT_MAGIC). */
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer uint32_t volatile u32Magic;
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer /** The number of threads referencing this object. */
7656b92221e26376547b0dc52b67e7a414ea9775Stephen Brooks uint32_t volatile cRefs;
7656b92221e26376547b0dc52b67e7a414ea9775Stephen Brooks /** Set if the object is signalled when there are no waiters. */
7656b92221e26376547b0dc52b67e7a414ea9775Stephen Brooks bool fSignaled;
7656b92221e26376547b0dc52b67e7a414ea9775Stephen Brooks /** Object generation.
7656b92221e26376547b0dc52b67e7a414ea9775Stephen Brooks * This is incremented every time the object is signalled and used to
7a0878494fd11b7a861d0b3e2034534c10b5fb46Stephen Brooks * check for spurious wake-ups. */
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer uint32_t uSignalGen;
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer /** The number of waiting threads. */
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer uint32_t cWaiters;
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer /** The number of signalled threads. */
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer uint32_t cWakeUp;
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer /** The Solaris mutex protecting this structure and pairing up the with the cv. */
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer kmutex_t Mtx;
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer /** The Solaris condition variable. */
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer kcondvar_t Cnd;
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer} RTSEMEVENTINTERNAL, *PRTSEMEVENTINTERNAL;
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer
e4f5a11d4a234623168c1558fcdf4341e11769e1James KremerRTDECL(int) RTSemEventCreate(PRTSEMEVENT phEventSem)
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer{
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer return RTSemEventCreateEx(phEventSem, 0 /*fFlags*/, NIL_RTLOCKVALCLASS, NULL);
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer}
7656b92221e26376547b0dc52b67e7a414ea9775Stephen Brooks
7656b92221e26376547b0dc52b67e7a414ea9775Stephen Brooks
7656b92221e26376547b0dc52b67e7a414ea9775Stephen BrooksRTDECL(int) RTSemEventCreateEx(PRTSEMEVENT phEventSem, uint32_t fFlags, RTLOCKVALCLASS hClass, const char *pszNameFmt, ...)
7656b92221e26376547b0dc52b67e7a414ea9775Stephen Brooks{
7656b92221e26376547b0dc52b67e7a414ea9775Stephen Brooks AssertCompile(sizeof(RTSEMEVENTINTERNAL) > sizeof(void *));
7656b92221e26376547b0dc52b67e7a414ea9775Stephen Brooks AssertReturn(!(fFlags & ~RTSEMEVENT_FLAGS_NO_LOCK_VAL), VERR_INVALID_PARAMETER);
7656b92221e26376547b0dc52b67e7a414ea9775Stephen Brooks AssertPtrReturn(phEventSem, VERR_INVALID_POINTER);
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer RT_ASSERT_PREEMPTIBLE();
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer PRTSEMEVENTINTERNAL pThis = (PRTSEMEVENTINTERNAL)RTMemAlloc(sizeof(*pThis));
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer if (!pThis)
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer return VERR_NO_MEMORY;
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer pThis->u32Magic = RTSEMEVENT_MAGIC;
7a0878494fd11b7a861d0b3e2034534c10b5fb46Stephen Brooks pThis->cRefs = 1;
7a0878494fd11b7a861d0b3e2034534c10b5fb46Stephen Brooks pThis->fSignaled = false;
7a0878494fd11b7a861d0b3e2034534c10b5fb46Stephen Brooks pThis->uSignalGen = 0;
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer pThis->cWaiters = 0;
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer pThis->cWakeUp = 0;
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer mutex_init(&pThis->Mtx, "IPRT Event Semaphore", MUTEX_DRIVER, (void *)ipltospl(DISP_LEVEL));
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer cv_init(&pThis->Cnd, "IPRT CV", CV_DRIVER, NULL);
7656b92221e26376547b0dc52b67e7a414ea9775Stephen Brooks
7656b92221e26376547b0dc52b67e7a414ea9775Stephen Brooks *phEventSem = pThis;
7656b92221e26376547b0dc52b67e7a414ea9775Stephen Brooks return VINF_SUCCESS;
7656b92221e26376547b0dc52b67e7a414ea9775Stephen Brooks}
7656b92221e26376547b0dc52b67e7a414ea9775Stephen Brooks
7656b92221e26376547b0dc52b67e7a414ea9775Stephen Brooks
7656b92221e26376547b0dc52b67e7a414ea9775Stephen BrooksRTDECL(int) RTSemEventDestroy(RTSEMEVENT hEventSem)
7a0878494fd11b7a861d0b3e2034534c10b5fb46Stephen Brooks{
7656b92221e26376547b0dc52b67e7a414ea9775Stephen Brooks PRTSEMEVENTINTERNAL pThis = hEventSem;
7656b92221e26376547b0dc52b67e7a414ea9775Stephen Brooks if (pThis == NIL_RTSEMEVENT)
7656b92221e26376547b0dc52b67e7a414ea9775Stephen Brooks return VINF_SUCCESS;
7656b92221e26376547b0dc52b67e7a414ea9775Stephen Brooks AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer AssertMsgReturn(pThis->u32Magic == RTSEMEVENT_MAGIC, ("u32Magic=%RX32 pThis=%p\n", pThis->u32Magic, pThis), VERR_INVALID_HANDLE);
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer RT_ASSERT_INTS_ON();
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer mutex_enter(&pThis->Mtx);
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer ASMAtomicDecU32(&pThis->cRefs);
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer pThis->u32Magic = RTSEMEVENT_MAGIC_DEAD; /* make the handle invalid */
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer if (pThis->cWaiters > 0)
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer {
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer /*
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer * Signal all threads to destroy.
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer */
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer cv_broadcast(&pThis->Cnd);
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer mutex_exit(&pThis->Mtx);
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer }
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer else if (pThis->cRefs == 0)
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer {
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer /*
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer * We're the last thread referencing this object, destroy it.
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer */
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer mutex_exit(&pThis->Mtx);
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer cv_destroy(&pThis->Cnd);
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer mutex_destroy(&pThis->Mtx);
7a0878494fd11b7a861d0b3e2034534c10b5fb46Stephen Brooks RTMemFree(pThis);
7656b92221e26376547b0dc52b67e7a414ea9775Stephen Brooks }
7656b92221e26376547b0dc52b67e7a414ea9775Stephen Brooks else
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer {
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer /*
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer * There are other threads still referencing this object, last one cleans up.
7a0878494fd11b7a861d0b3e2034534c10b5fb46Stephen Brooks */
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer mutex_exit(&pThis->Mtx);
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer }
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer return VINF_SUCCESS;
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer}
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer
744e50acbaaf22481b25b921b2bc199c8dd4a35cStephen Brooks
e4f5a11d4a234623168c1558fcdf4341e11769e1James KremerRTDECL(int) RTSemEventSignal(RTSEMEVENT hEventSem)
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer{
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer PRTSEMEVENTINTERNAL pThis = (PRTSEMEVENTINTERNAL)hEventSem;
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer RT_ASSERT_PREEMPT_CPUID_VAR();
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer AssertMsgReturn(pThis->u32Magic == RTSEMEVENT_MAGIC, ("u32Magic=%RX32 pThis=%p\n", pThis->u32Magic, pThis), VERR_INVALID_HANDLE);
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer RT_ASSERT_INTS_ON();
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer /*
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer * If we're in interrupt context we need to unpin the underlying current
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer * thread as this could lead to a deadlock (see #4259 for the full explanation)
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer *
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer * Note! This assumes nobody is using the RTThreadPreemptDisable in an
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer * interrupt context and expects it to work right. The swtch will
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer * result in a voluntary preemption. To fix this, we would have to
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer * do our own counting in RTThreadPreemptDisable/Restore like we do
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer * on systems which doesn't do preemption (OS/2, linux, ...) and
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer * check whether preemption was disabled via RTThreadPreemptDisable
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer * or not and only call swtch if RTThreadPreemptDisable wasn't called.
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer */
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer int fAcquired = mutex_tryenter(&pThis->Mtx);
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer if (!fAcquired)
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer {
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer if (curthread->t_intr && getpil() < DISP_LEVEL)
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer {
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer RTTHREADPREEMPTSTATE PreemptState = RTTHREADPREEMPTSTATE_INITIALIZER;
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer RTThreadPreemptDisable(&PreemptState);
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer preempt();
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer RTThreadPreemptRestore(&PreemptState);
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer }
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer mutex_enter(&pThis->Mtx);
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer }
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer pThis->cWakeUp++;
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer if (pThis->cWakeUp <= pThis->cWaiters)
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer {
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer /*
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer * We decrement waiters here so that we don't keep signalling threads that
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer * have already been signalled but not yet scheduled. So cWaiters might be
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer * 0 even when there are threads actually waiting.
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer */
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer cv_signal(&pThis->Cnd);
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer pThis->uSignalGen++;
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer }
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer else
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer pThis->fSignaled = true;
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer mutex_exit(&pThis->Mtx);
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer RT_ASSERT_PREEMPT_CPUID();
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer return VINF_SUCCESS;
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer}
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremerstatic int rtSemEventWaitWorker(PRTSEMEVENTINTERNAL pThis, RTMSINTERVAL cMillies, bool fInterruptible)
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer{
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer /*
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer * Translate milliseconds into ticks and go to sleep.
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer */
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer int rc = 0;
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer if (cMillies != RT_INDEFINITE_WAIT)
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer {
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer clock_t cTicks = drv_usectohz((clock_t)(cMillies * 1000L));
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer clock_t cTimeout = ddi_get_lbolt();
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer cTimeout += cTicks;
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer if (fInterruptible)
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer rc = cv_timedwait_sig(&pThis->Cnd, &pThis->Mtx, cTimeout);
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer else
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer rc = cv_timedwait(&pThis->Cnd, &pThis->Mtx, cTimeout);
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer }
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer else
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer {
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer if (fInterruptible)
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer rc = cv_wait_sig(&pThis->Cnd, &pThis->Mtx);
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer else
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer {
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer cv_wait(&pThis->Cnd, &pThis->Mtx);
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer rc = 1;
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer }
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer }
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer return rc;
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer}
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremerstatic int rtSemEventWait(RTSEMEVENT hEventSem, RTMSINTERVAL cMillies, bool fInterruptible)
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer{
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer int rc;
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer PRTSEMEVENTINTERNAL pThis = (PRTSEMEVENTINTERNAL)hEventSem;
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer AssertMsgReturn(pThis->u32Magic == RTSEMEVENT_MAGIC, ("u32Magic=%RX32 pThis=%p\n", pThis->u32Magic, pThis), VERR_INVALID_HANDLE);
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer if (cMillies)
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer RT_ASSERT_PREEMPTIBLE();
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer mutex_enter(&pThis->Mtx);
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer ASMAtomicIncU32(&pThis->cRefs);
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer if (pThis->fSignaled)
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer {
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer /*
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer * The last signal occurred without any waiters and now we're the first thread
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer * waiting for the event signal. So no real need to wait for one.
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer */
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer Assert(!pThis->cWaiters);
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer pThis->fSignaled = false;
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer pThis->cWakeUp = 0;
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer rc = VINF_SUCCESS;
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer }
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer else if (!cMillies)
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer rc = VERR_TIMEOUT;
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer else
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer {
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer pThis->cWaiters++;
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer /* This loop is only for continuing after a spurious wake-up. */
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer for (;;)
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer {
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer uint32_t const uSignalGenBeforeWait = pThis->uSignalGen;
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer rc = rtSemEventWaitWorker(pThis, cMillies, fInterruptible);
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer if (rc > 0)
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer {
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer if (pThis->u32Magic == RTSEMEVENT_MAGIC)
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer {
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer if (pThis->uSignalGen != uSignalGenBeforeWait)
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer {
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer /* We've been signaled by cv_signal(), consume the wake up. */
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer --pThis->cWakeUp;
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer rc = VINF_SUCCESS;
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer }
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer else
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer /* Spurious wakeup due to some signal, go back to waiting. */
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer continue;
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer }
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer else
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer /* We're being destroyed. */
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer rc = VERR_SEM_DESTROYED;
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer }
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer else if (rc == -1)
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer /* Timeout reached. */
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer rc = VERR_TIMEOUT;
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer else
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer /* Returned due to pending signal */
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer rc = VERR_INTERRUPTED;
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer --pThis->cWaiters;
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer break;
744e50acbaaf22481b25b921b2bc199c8dd4a35cStephen Brooks }
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer }
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer if (!ASMAtomicDecU32(&pThis->cRefs))
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer {
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer Assert(RT_FAILURE_NP(rc));
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer mutex_exit(&pThis->Mtx);
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer cv_destroy(&pThis->Cnd);
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer mutex_destroy(&pThis->Mtx);
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer RTMemFree(pThis);
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer return rc;
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer }
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer mutex_exit(&pThis->Mtx);
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer return rc;
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer}
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer
e4f5a11d4a234623168c1558fcdf4341e11769e1James KremerRTDECL(int) RTSemEventWait(RTSEMEVENT hEventSem, RTMSINTERVAL cMillies)
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer{
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer return rtSemEventWait(hEventSem, cMillies, false /* not interruptible */);
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer}
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer
e4f5a11d4a234623168c1558fcdf4341e11769e1James KremerRTDECL(int) RTSemEventWaitNoResume(RTSEMEVENT hEventSem, RTMSINTERVAL cMillies)
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer{
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer return rtSemEventWait(hEventSem, cMillies, true /* interruptible */);
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer}
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer
e4f5a11d4a234623168c1558fcdf4341e11769e1James Kremer