semeventwait-r0drv-solaris.h revision 3bad884471a4755d52abffc98cc326f153750ca1
3bad884471a4755d52abffc98cc326f153750ca1vboxsync * IPRT - Linux Ring-0 Driver Helpers for Abstracting Wait Queues,
3bad884471a4755d52abffc98cc326f153750ca1vboxsync * Copyright (C) 2006-2010 Oracle Corporation
3bad884471a4755d52abffc98cc326f153750ca1vboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
3bad884471a4755d52abffc98cc326f153750ca1vboxsync * available from http://www.virtualbox.org. This file is free software;
3bad884471a4755d52abffc98cc326f153750ca1vboxsync * you can redistribute it and/or modify it under the terms of the GNU
3bad884471a4755d52abffc98cc326f153750ca1vboxsync * General Public License (GPL) as published by the Free Software
3bad884471a4755d52abffc98cc326f153750ca1vboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
3bad884471a4755d52abffc98cc326f153750ca1vboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
3bad884471a4755d52abffc98cc326f153750ca1vboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
3bad884471a4755d52abffc98cc326f153750ca1vboxsync * The contents of this file may alternatively be used under the terms
3bad884471a4755d52abffc98cc326f153750ca1vboxsync * of the Common Development and Distribution License Version 1.0
3bad884471a4755d52abffc98cc326f153750ca1vboxsync * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
3bad884471a4755d52abffc98cc326f153750ca1vboxsync * VirtualBox OSE distribution, in which case the provisions of the
3bad884471a4755d52abffc98cc326f153750ca1vboxsync * CDDL are applicable instead of those of the GPL.
3bad884471a4755d52abffc98cc326f153750ca1vboxsync * You may elect to license modified versions of this file under the
3bad884471a4755d52abffc98cc326f153750ca1vboxsync * terms and conditions of either the GPL or the CDDL or both.
3bad884471a4755d52abffc98cc326f153750ca1vboxsync#ifndef ___r0drv_solaris_semeventwait_r0drv_solaris_h
3bad884471a4755d52abffc98cc326f153750ca1vboxsync#define ___r0drv_solaris_semeventwait_r0drv_solaris_h
3bad884471a4755d52abffc98cc326f153750ca1vboxsync * Solaris semaphore wait structure.
3bad884471a4755d52abffc98cc326f153750ca1vboxsync /** The absolute timeout given as nano seconds since the start of the
3bad884471a4755d52abffc98cc326f153750ca1vboxsync * monotonic clock. */
3bad884471a4755d52abffc98cc326f153750ca1vboxsync /** The timeout in nano seconds relative to the start of the wait. */
3bad884471a4755d52abffc98cc326f153750ca1vboxsync /** The native timeout value. */
3bad884471a4755d52abffc98cc326f153750ca1vboxsync /** The timeout (abs lbolt) when fHighRes is false. */
3bad884471a4755d52abffc98cc326f153750ca1vboxsync /** Set if we use high resolution timeouts. */
3bad884471a4755d52abffc98cc326f153750ca1vboxsync /** Set if it's an indefinite wait. */
3bad884471a4755d52abffc98cc326f153750ca1vboxsync /** Set if we've already timed out.
3bad884471a4755d52abffc98cc326f153750ca1vboxsync * Set by rtR0SemSolWaitDoIt or rtR0SemSolWaitHighResTimeout, read by
3bad884471a4755d52abffc98cc326f153750ca1vboxsync * rtR0SemSolWaitHasTimedOut. */
3bad884471a4755d52abffc98cc326f153750ca1vboxsync bool volatile fTimedOut;
3bad884471a4755d52abffc98cc326f153750ca1vboxsync /** Whether the wait was interrupted. */
3bad884471a4755d52abffc98cc326f153750ca1vboxsync /** Interruptible or uninterruptible wait. */
3bad884471a4755d52abffc98cc326f153750ca1vboxsync /** The thread to wake up. */
3bad884471a4755d52abffc98cc326f153750ca1vboxsync /** Cylic timer ID (used by the timeout callback). */
3bad884471a4755d52abffc98cc326f153750ca1vboxsync/** Pointer to a solaris semaphore wait structure. */
3bad884471a4755d52abffc98cc326f153750ca1vboxsync * Initializes a wait.
3bad884471a4755d52abffc98cc326f153750ca1vboxsync * The caller MUST check the wait condition BEFORE calling this function or the
3bad884471a4755d52abffc98cc326f153750ca1vboxsync * timeout logic will be flawed.
3bad884471a4755d52abffc98cc326f153750ca1vboxsync * @returns VINF_SUCCESS or VERR_TIMEOUT.
3bad884471a4755d52abffc98cc326f153750ca1vboxsync * @param pWait The wait structure.
3bad884471a4755d52abffc98cc326f153750ca1vboxsync * @param fFlags The wait flags.
3bad884471a4755d52abffc98cc326f153750ca1vboxsync * @param uTimeout The timeout.
3bad884471a4755d52abffc98cc326f153750ca1vboxsync * @param pWaitQueue The wait queue head.
3bad884471a4755d52abffc98cc326f153750ca1vboxsyncDECLINLINE(int) rtR0SemSolWaitInit(PRTR0SEMSOLWAIT pWait, uint32_t fFlags, uint64_t uTimeout)
3bad884471a4755d52abffc98cc326f153750ca1vboxsync * Process the flags and timeout.
3bad884471a4755d52abffc98cc326f153750ca1vboxsync uTimeout = uTimeout < UINT64_MAX / UINT32_C(1000000) * UINT32_C(1000000)
3bad884471a4755d52abffc98cc326f153750ca1vboxsync if ( (fFlags & (RTSEMWAIT_FLAGS_NANOSECS | RTSEMWAIT_FLAGS_ABSOLUTE))
3bad884471a4755d52abffc98cc326f153750ca1vboxsync || pWait->cNsRelTimeout < UINT32_C(1000000000) / 100 /*Hz*/ * 4)
3bad884471a4755d52abffc98cc326f153750ca1vboxsync uint64_t cTicks = drv_usectohz((clock_t)(uTimeout / 1000));
3bad884471a4755d52abffc98cc326f153750ca1vboxsync pWait->fInterruptible = !!(fFlags & RTSEMWAIT_FLAGS_INTERRUPTIBLE);
3bad884471a4755d52abffc98cc326f153750ca1vboxsync * Cyclic timeout callback that sets the timeout indicator and wakes up the
3bad884471a4755d52abffc98cc326f153750ca1vboxsync * waiting thread.
3bad884471a4755d52abffc98cc326f153750ca1vboxsync * @param pvUser The wait structure.
3bad884471a4755d52abffc98cc326f153750ca1vboxsyncstatic void rtR0SemSolWaitHighResTimeout(void *pvUser)
3bad884471a4755d52abffc98cc326f153750ca1vboxsync /* Note: Trying to take the cpu_lock here doesn't work. */
3bad884471a4755d52abffc98cc326f153750ca1vboxsync * Do the actual wait.
3bad884471a4755d52abffc98cc326f153750ca1vboxsync * @param pWait The wait structure.
3bad884471a4755d52abffc98cc326f153750ca1vboxsync * @param pCnd The condition variable to wait on.
3bad884471a4755d52abffc98cc326f153750ca1vboxsync * @param pMtx The mutex related to the condition variable.
3bad884471a4755d52abffc98cc326f153750ca1vboxsync * The caller has entered this.
3bad884471a4755d52abffc98cc326f153750ca1vboxsyncDECLINLINE(void) rtR0SemSolWaitDoIt(PRTR0SEMSOLWAIT pWait, kcondvar_t *pCnd, kmutex_t *pMtx)
3bad884471a4755d52abffc98cc326f153750ca1vboxsync * No timeout - easy.
3bad884471a4755d52abffc98cc326f153750ca1vboxsync/** @todo Use the new cv_*hires* stuff here when available. */
3bad884471a4755d52abffc98cc326f153750ca1vboxsync * High resolution timeout - arm a one-shot cyclic for waking up
3bad884471a4755d52abffc98cc326f153750ca1vboxsync * the thread at the desired time.
3bad884471a4755d52abffc98cc326f153750ca1vboxsync Cyh.cyh_level = CY_LOW_LEVEL; /// @todo try CY_LOCK_LEVEL and CY_HIGH_LEVEL?
3bad884471a4755d52abffc98cc326f153750ca1vboxsync * Normal timeout.
3bad884471a4755d52abffc98cc326f153750ca1vboxsync rc = cv_timedwait_sig(pCnd, pMtx, pWait->u.lTimeout);
3bad884471a4755d52abffc98cc326f153750ca1vboxsync /* Above zero means normal wake-up. */
3bad884471a4755d52abffc98cc326f153750ca1vboxsync /* Timeout is signalled by -1. */
3bad884471a4755d52abffc98cc326f153750ca1vboxsync /* Interruption is signalled by 0. */
3bad884471a4755d52abffc98cc326f153750ca1vboxsync * Checks if a solaris wait was interrupted.
3bad884471a4755d52abffc98cc326f153750ca1vboxsync * @returns true / false
3bad884471a4755d52abffc98cc326f153750ca1vboxsync * @param pWait The wait structure.
3bad884471a4755d52abffc98cc326f153750ca1vboxsync * @remarks This shall be called before the first rtR0SemSolWaitDoIt().
3bad884471a4755d52abffc98cc326f153750ca1vboxsyncDECLINLINE(bool) rtR0SemSolWaitWasInterrupted(PRTR0SEMSOLWAIT pWait)
3bad884471a4755d52abffc98cc326f153750ca1vboxsync * Checks if a solaris wait has timed out.
3bad884471a4755d52abffc98cc326f153750ca1vboxsync * @returns true / false
3bad884471a4755d52abffc98cc326f153750ca1vboxsync * @param pWait The wait structure.
3bad884471a4755d52abffc98cc326f153750ca1vboxsyncDECLINLINE(bool) rtR0SemSolWaitHasTimedOut(PRTR0SEMSOLWAIT pWait)
3bad884471a4755d52abffc98cc326f153750ca1vboxsync * Deletes a solaris wait.
3bad884471a4755d52abffc98cc326f153750ca1vboxsync * @param pWait The wait structure.
3bad884471a4755d52abffc98cc326f153750ca1vboxsyncDECLINLINE(void) rtR0SemSolWaitDelete(PRTR0SEMSOLWAIT pWait)
3bad884471a4755d52abffc98cc326f153750ca1vboxsync * Enters the mutex, unpinning the underlying current thread if contended and
3bad884471a4755d52abffc98cc326f153750ca1vboxsync * we're on an interrupt thread.
3bad884471a4755d52abffc98cc326f153750ca1vboxsync * The unpinning is done to prevent a deadlock, see s this could lead to a
3bad884471a4755d52abffc98cc326f153750ca1vboxsync * deadlock (see #4259 for the full explanation)
3bad884471a4755d52abffc98cc326f153750ca1vboxsync * @param pMtx The mutex to enter.
3bad884471a4755d52abffc98cc326f153750ca1vboxsyncDECLINLINE(void) rtR0SemSolWaitEnterMutexWithUnpinningHack(kmutex_t *pMtx)
3bad884471a4755d52abffc98cc326f153750ca1vboxsync * Note! This assumes nobody is using the RTThreadPreemptDisable in an
3bad884471a4755d52abffc98cc326f153750ca1vboxsync * interrupt context and expects it to work right. The swtch will
3bad884471a4755d52abffc98cc326f153750ca1vboxsync * result in a voluntary preemption. To fix this, we would have to
3bad884471a4755d52abffc98cc326f153750ca1vboxsync * do our own counting in RTThreadPreemptDisable/Restore like we do
3bad884471a4755d52abffc98cc326f153750ca1vboxsync * on systems which doesn't do preemption (OS/2, linux, ...) and
3bad884471a4755d52abffc98cc326f153750ca1vboxsync * check whether preemption was disabled via RTThreadPreemptDisable
3bad884471a4755d52abffc98cc326f153750ca1vboxsync * or not and only call swtch if RTThreadPreemptDisable wasn't called.