semmutex-linux.cpp revision c68a3984216eaa85ae7144b3b0d9b168276dbcf3
449854c2a07b50ea64d9d6a8b03d18d4afeeee43Ken Stubbings/* $Id$ */
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster/** @file
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster * IPRT - Mutex Semaphore, Linux (2.6.x+).
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster */
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster/*
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster * Copyright (C) 2006-2007 Sun Microsystems, Inc.
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster *
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster * This file is part of VirtualBox Open Source Edition (OSE), as
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster * available from http://www.virtualbox.org. This file is free software;
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster * you can redistribute it and/or modify it under the terms of the GNU
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster * General Public License (GPL) as published by the Free Software
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster * Foundation, in version 2 as it comes in the "COPYING" file of the
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster *
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster * The contents of this file may alternatively be used under the terms
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster * of the Common Development and Distribution License Version 1.0
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster * VirtualBox OSE distribution, in which case the provisions of the
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster * CDDL are applicable instead of those of the GPL.
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster *
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster * You may elect to license modified versions of this file under the
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster * terms and conditions of either the GPL or the CDDL or both.
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster *
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
ccf9d4a5c6453fa9f8b839baeee25147865fbb7dJames Phillpotts * Clara, CA 95054 USA or visit http://www.sun.com if you need
7865e731ddb5646082d96b96b1a11d82e9db794fKohei Tamura * additional information or have any questions.
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster */
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster/*******************************************************************************
ccf9d4a5c6453fa9f8b839baeee25147865fbb7dJames Phillpotts* Header Files *
ccf9d4a5c6453fa9f8b839baeee25147865fbb7dJames Phillpotts*******************************************************************************/
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster#include <iprt/semaphore.h>
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster#include "internal/iprt.h"
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster#include <iprt/alloc.h>
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster#include <iprt/asm.h>
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster#include <iprt/assert.h>
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster#include <iprt/err.h>
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster#include <iprt/lockvalidator.h>
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster#include <iprt/thread.h>
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster#include <iprt/time.h>
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster#include "internal/magics.h"
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster#include "internal/strict.h"
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster#include <errno.h>
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster#include <limits.h>
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster#include <pthread.h>
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster#include <unistd.h>
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster#include <sys/time.h>
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster#include <sys/syscall.h>
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster#if 0 /* With 2.6.17 futex.h has become C++ unfriendly. */
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster# include <linux/futex.h>
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster#else
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster# define FUTEX_WAIT 0
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster# define FUTEX_WAKE 1
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster#endif
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster/*******************************************************************************
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster* Structures and Typedefs *
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster*******************************************************************************/
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster/**
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster * Linux internal representation of a Mutex semaphore.
449854c2a07b50ea64d9d6a8b03d18d4afeeee43Ken Stubbings */
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Fosterstruct RTSEMMUTEXINTERNAL
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster{
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster /** The futex state variable.
449854c2a07b50ea64d9d6a8b03d18d4afeeee43Ken Stubbings * 0 means unlocked.
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster * 1 means locked, no waiters.
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster * 2 means locked, one or more waiters.
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster */
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster int32_t volatile iState;
449854c2a07b50ea64d9d6a8b03d18d4afeeee43Ken Stubbings /** Nesting count. */
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster uint32_t volatile cNesting;
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster /** The owner of the mutex. */
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster pthread_t volatile Owner;
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster /** Magic value (RTSEMMUTEX_MAGIC). */
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster uint32_t volatile u32Magic;
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster#ifdef RTSEMMUTEX_STRICT
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster /** Lock validator record associated with this mutex. */
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster RTLOCKVALIDATORREC ValidatorRec;
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster#endif
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster};
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster/* Undefine debug mappings. */
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster#undef RTSemMutexRequest
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster#undef RTSemMutexRequestNoResume
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster/**
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster * Wrapper for the futex syscall.
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster */
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Fosterstatic long sys_futex(int32_t volatile *uaddr, int op, int val, struct timespec *utime, int32_t *uaddr2, int val3)
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster{
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster errno = 0;
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster long rc = syscall(__NR_futex, uaddr, op, val, utime, uaddr2, val3);
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster if (rc < 0)
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster {
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster Assert(rc == -1);
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster rc = -errno;
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster }
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster return rc;
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster}
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan FosterRTDECL(int) RTSemMutexCreate(PRTSEMMUTEX pMutexSem)
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster{
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster /*
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster * Allocate semaphore handle.
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster */
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster struct RTSEMMUTEXINTERNAL *pThis = (struct RTSEMMUTEXINTERNAL *)RTMemAlloc(sizeof(struct RTSEMMUTEXINTERNAL));
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster if (pThis)
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster {
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster pThis->u32Magic = RTSEMMUTEX_MAGIC;
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster pThis->iState = 0;
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster pThis->Owner = (pthread_t)~0;
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster pThis->cNesting = 0;
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster#ifdef RTSEMMUTEX_STRICT
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster RTLockValidatorInit(&pThis->ValidatorRec, NIL_RTLOCKVALIDATORCLASS, RTLOCKVALIDATOR_SUB_CLASS_NONE, NULL, pThis);
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster#endif
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster *pMutexSem = pThis;
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster return VINF_SUCCESS;
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster }
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster return VERR_NO_MEMORY;
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster}
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan FosterRTDECL(int) RTSemMutexDestroy(RTSEMMUTEX MutexSem)
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster{
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster /*
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster * Validate input.
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster */
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster if (MutexSem == NIL_RTSEMMUTEX)
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster return VINF_SUCCESS;
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster struct RTSEMMUTEXINTERNAL *pThis = MutexSem;
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster AssertMsgReturn(pThis->u32Magic == RTSEMMUTEX_MAGIC,
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster ("MutexSem=%p u32Magic=%#x\n", pThis, pThis->u32Magic),
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster VERR_INVALID_HANDLE);
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster /*
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster * Invalidate the semaphore and wake up anyone waiting on it.
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster */
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster ASMAtomicWriteU32(&pThis->u32Magic, RTSEMMUTEX_MAGIC_DEAD);
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster if (ASMAtomicXchgS32(&pThis->iState, 0) > 0)
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster {
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster sys_futex(&pThis->iState, FUTEX_WAKE, INT_MAX, NULL, NULL, 0);
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster usleep(1000);
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster }
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster pThis->Owner = (pthread_t)~0;
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster pThis->cNesting = 0;
ccf9d4a5c6453fa9f8b839baeee25147865fbb7dJames Phillpotts#ifdef RTSEMMUTEX_STRICT
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster RTLockValidatorDelete(&pThis->ValidatorRec);
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster#endif
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster /*
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster * Free the semaphore memory and be gone.
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster */
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster RTMemFree(pThis);
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster return VINF_SUCCESS;
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster}
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan FosterDECL_FORCE_INLINE(int) rtSemMutexRequest(RTSEMMUTEX MutexSem, unsigned cMillies, bool fAutoResume, RTSEMMUTEX_STRICT_POS_DECL)
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster{
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster /*
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster * Validate input.
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster */
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster struct RTSEMMUTEXINTERNAL *pThis = MutexSem;
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster AssertReturn(pThis->u32Magic == RTSEMMUTEX_MAGIC, VERR_INVALID_HANDLE);
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster#ifdef RTSEMMUTEX_STRICT
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster RTTHREAD hThreadSelf = RTThreadSelfAutoAdopt();
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster RTLockValidatorCheckOrder(&pThis->ValidatorRec, hThreadSelf, RTSEMMUTEX_STRICT_POS_ARGS);
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster#endif
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster /*
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster * Check if nested request.
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster */
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster pthread_t Self = pthread_self();
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster if ( pThis->Owner == Self
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster && pThis->cNesting > 0)
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster {
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster ASMAtomicIncU32(&pThis->cNesting);
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster return VINF_SUCCESS;
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster }
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster#ifndef RTSEMMUTEX_STRICT
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster RTTHREAD hThreadSelf = RTThreadSelf();
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster#endif
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster /*
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster * Convert timeout value.
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster */
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster struct timespec ts;
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster struct timespec *pTimeout = NULL;
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster uint64_t u64End = 0; /* shut up gcc */
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster if (cMillies != RT_INDEFINITE_WAIT)
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster {
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster ts.tv_sec = cMillies / 1000;
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster ts.tv_nsec = (cMillies % 1000) * 1000000;
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster u64End = RTTimeSystemNanoTS() + cMillies * 1000000;
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster pTimeout = &ts;
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster }
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster /*
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster * Lock the mutex.
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster * Optimize for the uncontended case (makes 1-2 ns difference).
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster */
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster if (RT_UNLIKELY(!ASMAtomicCmpXchgS32(&pThis->iState, 1, 0)))
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster {
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster for (;;)
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster {
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster int32_t iOld = ASMAtomicXchgS32(&pThis->iState, 2);
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster /*
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster * Was the lock released in the meantime? This is unlikely (but possible)
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster */
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster if (RT_UNLIKELY(iOld == 0))
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster break;
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster /*
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster * Go to sleep.
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster */
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster if (pTimeout && ( pTimeout->tv_sec || pTimeout->tv_nsec ))
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster RTSEMMUTEX_STRICT_BLOCK(hThreadSelf, &pThis->ValidatorRec);
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster long rc = sys_futex(&pThis->iState, FUTEX_WAIT, 2, pTimeout, NULL, 0);
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster RTSEMMUTEX_STRICT_UNBLOCK(hThreadSelf);
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster if (RT_UNLIKELY(pThis->u32Magic != RTSEMMUTEX_MAGIC))
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster return VERR_SEM_DESTROYED;
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster /*
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster * Act on the wakup code.
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster */
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster if (rc == -ETIMEDOUT)
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster {
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster Assert(pTimeout);
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster return VERR_TIMEOUT;
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster }
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster if (rc == 0)
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster /* we'll leave the loop now unless another thread is faster */;
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster else if (rc == -EWOULDBLOCK)
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster /* retry with new value. */;
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster else if (rc == -EINTR)
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster {
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster if (!fAutoResume)
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster return VERR_INTERRUPTED;
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster }
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster else
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster {
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster /* this shouldn't happen! */
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster AssertMsgFailed(("rc=%ld errno=%d\n", rc, errno));
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster return RTErrConvertFromErrno(rc);
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster }
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster /* adjust the relative timeout */
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster if (pTimeout)
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster {
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster int64_t i64Diff = u64End - RTTimeSystemNanoTS();
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster if (i64Diff < 1000)
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster {
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster rc = VERR_TIMEOUT;
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster break;
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster }
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster ts.tv_sec = i64Diff / 1000000000;
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster ts.tv_nsec = i64Diff % 1000000000;
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster }
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster }
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster /*
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster * When leaving this loop, iState is set to 2. This means that we gained the
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster * lock and there are _possibly_ some waiters. We don't know exactly as another
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster * thread might entered this loop at nearly the same time. Therefore we will
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster * call futex_wakeup once too often (if _no_ other thread entered this loop).
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster * The key problem is the simple futex_wait test for x != y (iState != 2) in
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster * our case).
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster */
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster }
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster /*
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster * Set the owner and nesting.
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster */
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster pThis->Owner = Self;
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster ASMAtomicWriteU32(&pThis->cNesting, 1);
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster#ifdef RTSEMMUTEX_STRICT
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster RTThreadWriteLockInc(RTLockValidatorSetOwner(&pThis->ValidatorRec, hThreadSelf, RTSEMMUTEX_STRICT_POS_ARGS));
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster#endif
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster return VINF_SUCCESS;
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster}
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan FosterRTDECL(int) RTSemMutexRequest(RTSEMMUTEX MutexSem, unsigned cMillies)
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster{
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster#ifndef RTSEMMUTEX_STRICT
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster int rc = rtSemMutexRequest(MutexSem, cMillies, true, RTSEMMUTEX_STRICT_POS_ARGS);
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster Assert(rc != VERR_INTERRUPTED);
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster return rc;
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster#else
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster return RTSemMutexRequestDebug(MutexSem, cMillies, (uintptr_t)ASMReturnAddress(), RT_SRC_POS);
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster#endif
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster}
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan FosterRTDECL(int) RTSemMutexRequestDebug(RTSEMMUTEX MutexSem, unsigned cMillies, RTHCUINTPTR uId, RT_SRC_POS_DECL)
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster{
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster#ifdef RTSEMMUTEX_STRICT
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster int rc = rtSemMutexRequest(MutexSem, cMillies, true, RTSEMMUTEX_STRICT_POS_ARGS);
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster Assert(rc != VERR_INTERRUPTED);
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster return rc;
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster#else
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster return RTSemMutexRequest(MutexSem, cMillies);
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster#endif
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster}
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan FosterRTDECL(int) RTSemMutexRequestNoResume(RTSEMMUTEX MutexSem, unsigned cMillies)
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster{
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster#ifndef RTSEMMUTEX_STRICT
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster return rtSemMutexRequest(MutexSem, cMillies, false, RTSEMMUTEX_STRICT_POS_ARGS);
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster#else
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster return RTSemMutexRequestNoResumeDebug(MutexSem, cMillies, (uintptr_t)ASMReturnAddress(), RT_SRC_POS);
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster#endif
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster}
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan FosterRTDECL(int) RTSemMutexRequestNoResumeDebug(RTSEMMUTEX MutexSem, unsigned cMillies, RTHCUINTPTR uId, RT_SRC_POS_DECL)
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster{
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster#ifdef RTSEMMUTEX_STRICT
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster return rtSemMutexRequest(MutexSem, cMillies, false, RTSEMMUTEX_STRICT_POS_ARGS);
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster#else
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster return RTSemMutexRequest(MutexSem, cMillies);
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster#endif
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster}
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan FosterRTDECL(int) RTSemMutexRelease(RTSEMMUTEX MutexSem)
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster{
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster /*
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster * Validate input.
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster */
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster struct RTSEMMUTEXINTERNAL *pThis = MutexSem;
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster AssertReturn(pThis->u32Magic == RTSEMMUTEX_MAGIC, VERR_INVALID_HANDLE);
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster /*
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster * Check if nested.
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster */
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster pthread_t Self = pthread_self();
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster if (RT_UNLIKELY( pThis->Owner != Self
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster || pThis->cNesting == 0))
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster {
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster AssertMsgFailed(("Not owner of mutex %p!! Self=%08x Owner=%08x cNesting=%d\n",
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster pThis, Self, pThis->Owner, pThis->cNesting));
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster return VERR_NOT_OWNER;
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster }
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster /*
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster * If nested we'll just pop a nesting.
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster */
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster if (pThis->cNesting > 1)
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster {
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster ASMAtomicDecU32(&pThis->cNesting);
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster return VINF_SUCCESS;
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster }
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster /*
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster * Clear the state. (cNesting == 1)
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster */
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster#ifdef RTSEMMUTEX_STRICT
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster RTThreadWriteLockDec(RTLockValidatorUnsetOwner(&pThis->ValidatorRec));
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster#endif
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster pThis->Owner = (pthread_t)~0;
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster ASMAtomicWriteU32(&pThis->cNesting, 0);
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster /*
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster * Release the mutex.
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster */
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster int32_t iNew = ASMAtomicDecS32(&pThis->iState);
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster if (RT_UNLIKELY(iNew != 0))
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster {
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster /* somebody is waiting, try wake up one of them. */
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster ASMAtomicXchgS32(&pThis->iState, 0);
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster (void)sys_futex(&pThis->iState, FUTEX_WAKE, 1, NULL, NULL, 0);
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster }
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster return VINF_SUCCESS;
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster}
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster
a688bcbb4bcff5398fdd29b86f83450257dc0df4Allan Foster